12: コマンドライン引数 - waseda university変換に変換に失敗した場合は0...

19
12: コマンドライン引数 Linux にログインし、以下の講義ページ を開いておくこと http://www-it.sci.waseda.ac.jp/ teachers/w483692/CPR1/ 2015-06-29 C プログラミング入門 総機1 (1) 1

Upload: others

Post on 12-Aug-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

12: コマンドライン引数

Linux にログインし、以下の講義ページを開いておくこと http://www-it.sci.waseda.ac.jp/teachers/w483692/CPR1/

2015-06-29

C プログラミング入門 総機1 (月1)

1

Page 2: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

内容 説明 呼び出し元の変数を書き換える 第 9 回 文字列を渡す・配列を渡す 第 10 回 ファイルポインタ 第 10 回 複数の値を返す 第 11 回 大きな領域を確保する 第 11 回

2015-06-29 C プログラミング入門 総機1 (月1) 2

まとめ:ポインタを使った処理

Page 3: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

コマンドライン引数の取り扱い シェルから引数 (オプション) を受け取る 技術的には二重ポインタ (double pointer) である

• ポインタへのポインタ • 秋期の「Cプログラミング」で使うが、この講義ではあまり踏み込まない

文字列から数値への変換 コマンドライン引数は単なる文字列なので、数値として扱うには変換が必要

2015-06-29 C プログラミング入門 総機1 (月1) 3

今回の内容

Page 4: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

メモリ上の位置を表す値 型を持つ 変数 a のアドレスは &a ポインタ変数に格納できる アドレス値のことをポインタとも呼ぶことがある

2015-06-29 C プログラミング入門 総機1 (月1) 4

復習:アドレスとポインタ

int *p

100

int a

矢印が指す位置のアドレスを持っている

{ int a = 100; int *p = &a; printf("%d", *p);

Page 5: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

デリファレンス演算子 * で、アドレスが指す位置の内容を読み書きできる 添え字演算子 [] で、ポインタの指す位置をずらして読み書きできる ポインタ p に対して *(p+n) と p[n] は同じ

2015-06-29 C プログラミング入門 総機1 (月1) 5

復習:アドレス演算と読み書き

p

-23 85

メモリ上のデータをどんな値とみなすかは、ポインタの型で決まる

p[0] == *p == 23

p[1] == *(p+1) == 85

矢印が指す位置のアドレスを持っている

Page 6: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

配列変数名は、式中で配列の先頭へのポインタとなる 配列変数を a とすると a そのものがアドレス &a[0] (0 番要素のアドレス) と同じ &a と書いてもよい

2015-06-29 C プログラミング入門 総機1 (月1) 6

復習:配列とポインタ

p

365 a[0] == *a == p[0] == *p == 365

int a[4]

それぞれ型が異なる場合があるが詳細は省略する。ポインタに関する専門書を参照

p = &a という代入をした場合

Page 7: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

文字列は、メモリ上の文字 (char 型の値) が並んでいる領域の先頭へのポインタである なぜ char 型なのかは歴史的な事情による 日本語を含む場合でも、基本的には char でよい 文字列リテラルを書くと、その文字列がシステム領域に用意され、その先頭ポインタを表す

文字列の終端は null 文字 ('¥0') である 配列を文字列リテラルで初期化すると、自動的に付加される

2015-06-29 C プログラミング入門 総機1 (月1) 7

復習:文字列

Page 8: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

シェルでコマンド名の後ろに書く文字列 ホワイトスペースで分割される (トークン化) コマンドは受け取った引数を処理する

2015-06-29 C プログラミング入門 総機1 (月1) 8

コマンドライン引数

[user@host]$ gcc src.c -o src -Wall -Wextra

[user@host]$ ./src hello world

この場合、 5 個の引数を gcc というプログラムに渡している

C 言語で書いたプログラムに引数を渡した場合、どのように処理すればいいのか?

Page 9: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

main 関数として以下のプロトタイプを使う int main(int argc, char** argv); cf. 今までのは int main(void); 引数名は何でもよいが慣用的に argc, argv または ac, av が使われる それぞれ、 argument count と argument

vector (引数の列) という意味

2015-06-29 C プログラミング入門 総機1 (月1) 9

コマンドライン引数の受け取り方

第2引数の書き方として、 • char **av • char *av[] のどちらでも、文法上は同じである。後者の書き方をする人もいるので覚えておく

Page 10: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

システムのメモリ領域

文字列へのポインタの配列 最後に null ポインタで終わる

2015-06-29 C プログラミング入門 総機1 (月1) 10

argv の内容

./prog hello world 100 と実行した場合

'h' 'e' 'l' '¥0' 'l' 'o'

'w' 'o' 'r' '¥0' 'l' 'd'

'1' '0' '0' '¥0'

'.' '/' 'p' 'g' 'r' 'o' '¥0' argv[0]

char **argv main 関数の自動変数の領域

argv[0][0]

規格では、 argv[0] に実行したコマンドが必ず入るとは定められていないが、多くの処理系でこうなる

たとえば argv[1] が "hello" という文字列だと思えばよい

argv[1]

argv[4] == NULL

Page 11: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

システムのメモリ領域

null ポインタの入っている要素の番号を表す n 個の引数を指定すると argc == n+1

2015-06-29 C プログラミング入門 総機1 (月1) 11

argc の意味

./prog hello world 100 と実行した場合

'h' 'e' 'l' '¥0' 'l' 'o'

'w' 'o' 'r' '¥0' 'l' 'd'

'1' '0' '0' '¥0'

'.' '/' 'p' 'g' 'r' 'o' '¥0' argv[0]

char **argv main 関数の自動変数の領域

argv[0][0]

この例の場合 argc == 4 つまり、指定した引数の個数 + 1

argv[1]

argv[argc] == NULL

Page 12: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

argv[i] を i = 1, ..., argc-1 まで表示

2015-06-29 C プログラミング入門 総機1 (月1) 12

例題:引数をすべて表示する

int main(int argc, char **argv) { int i; printf("%d arguments:¥n", argc-1); for(i = 0; i < argc; ++i) { printf("[%d] == ¥"%s¥"¥n", i, argv[i]); } return 0; }

[user@host]$ ./arg hello 123 2 arguments [0] == "./arg" [1] == "hello" [2] == "123"

argc までループさせない なぜなら、 argv[argc] == NULL なので表示できない

プログラム名が arg の場合

Page 13: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

argv はポインタ変数であり、直接移動させることもできる

2015-06-29 C プログラミング入門 総機1 (月1) 13

例題:引数をすべて表示する (別の書き方)

int main(int argc, char **argv) { printf("%d arguments:¥n", argc-1); for( ; *argv != NULL; ++argv) { printf("¥"%s¥"¥n", *argv); } return 0; }

[user@host]$ ./arg hello 123 2 arguments "./arg" "hello" "123"

*argv は argv[0] と同じであり、 argv 自体を動かしていくと、 *argv が表す文字列が変わっていく

プログラム名が arg の場合

NULL が現れるまで動かすので、 argc は必要ない 初期化条件は空 ポインタを動かすだけでは何番目かがわからな

い。必要なら変数を用意してカウントする

Page 14: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

とりあえず、 argv[i] が、 i 番目の引数、と考えるだけで OK ただし、 i は 1 からカウント 最低限 p. 12 のプログラムが使えればよい

2015-06-29 C プログラミング入門 総機1 (月1) 14

難しいと思う人は…

Page 15: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

引数はあくまでも文字列である たとえば、 100 と書いても、 "100" という文字列でしかない 数値として扱うには標準ライブラリ関数で変換する (次のスライドで説明)

引数が空文字列になる場合もある たとえば、 ./prog "" abc と書いて実行すると、 argv[1] は空文字列、 argv[2] は "abc"

引数はシステム領域に作られるので、 (const はついていないが) 書き換えてはいけない

2015-06-29 C プログラミング入門 総機1 (月1) 15

コマンドライン引数の注意

Page 16: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

sscanf() は、文字列を解析して変数に値を書きこむ

2015-06-29 C プログラミング入門 総機1 (月1) 16

文字列を数値に変換する (1) sscanf

int main(int argc, char **argv) { int i; printf("%d arguments:¥n", argc-1); for(i = 1; i < argc; ++i) { int v = -1; sscanf(argv[i], "%d", &v); printf("[%d] == ¥"%s¥" (%d)¥n", i, argv[i], v); } return 0; }

[user@host]$ ./arg hello 123 abc 3.14 4 arguments [1] == "hello" (-1) [2] == "123" (123) [3] == "abc" (-1) [4] == "3.14" (3)

プログラム名が arg の場合

整数として変換できない文字列だった場合は何もしない

整数として変換する

整数として変換できるところまで使われる 変換対象の文字列

Page 17: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

sscanf() は、文字列を解析して変数に値を書きこむ

2015-06-29 C プログラミング入門 総機1 (月1) 17

文字列を数値に変換する (1) sscanf

int main(int argc, char **argv) { int i; printf("%d arguments:¥n", argc-1); for(i = 1; i < argc; ++i) { double v = -1; sscanf(argv[i], "%lf", &v); printf("[%d] == ¥"%s¥" (%f)¥n", i, argv[i], v); } return 0; }

[user@host]$ ./arg hello 123 abc 3.14 4 arguments [1] == "hello" (-1.000000) [2] == "123" (123.000000) [3] == "abc" (-1.000000) [4] == "3.14" (3.140000)

プログラム名が arg の場合

double として変換する

小数の値として解釈されている l (エル) は不要

Page 18: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

文字列を数値に変換する関数として<stdlib.h> に以下の 2 種類がある atox() は簡単に使えるが、変換に失敗したかどうかを判断できない

2015-06-29 C プログラミング入門 総機1 (月1) 18

文字列を数値に変換する (2) 変換関数

関数名 変換する型 備考 atoi int 範囲外の値だった場合の戻り値は未定義。

変換に失敗した場合は 0 を返す。 (関数名は ASCII to x という意味 ASCII は文字コードのこと)

atol long int

atof double

strtol long int 変換に変換に失敗した場合は 0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数 (何進法表記か) を指定する。 (関数名は string to x という意味)

strtoul unsigned long int

strtod double

float ではない

Page 19: 12: コマンドライン引数 - Waseda University変換に変換に失敗した場合は0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数

なるべく右の strtox() を使うべき

2015-06-29 C プログラミング入門 総機1 (月1) 19

文字列を数値に変換する (2) 変換関数

{ int x; char *s = "2014.2"; x = atoi(s); printf("¥"%s¥" == %d¥n", s, x);

{ int x; char *s = "2014.2"; char *p; x = strtol(s, &p, 10); printf("¥"%s¥" == %d", s, x); // 変換が完全に失敗した場合 if(str == p) { ...

変換の失敗位置が必要なければ、 NULL を渡してもよい

p は変換に失敗した最初の位置である もし、文字列の先頭と同じなら、1文字も解釈できなかったことになる

10進数を指定

#include <stdlib.h> int atoi(const char *str); long strtol(const char *str, char **str_end, int base );

atoi, strtol のプロトタイプ