12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと

Slides:



Advertisements
Similar presentations
オブジェクト指向言語・ オブジェクト指向言語演習 中間試験回答例. Jan. 12, 2005 情報処理技術基礎演習 II 2 オブジェクト指向言語 中間試験解説 1  (1) 円柱の体積(円柱の体積 = 底面の円の面積 x 高さ) を求めるプログラムを作成しなさい。ただし、出力結果は、入 力した底面の円の半径.
Advertisements

復習 配列変数の要素 5は配列の要素数 これらの変数をそれぞれ配列の要素と呼ぶ この数字を配列の添え字,またはインデックスと呼ぶ
復習 配列変数の要素 5は配列の要素数 これらの変数をそれぞれ配列の要素と呼ぶ この数字を配列の添え字,またはインデックスと呼ぶ
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
データ構造とアルゴリズム 第10回 mallocとfree
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
基礎プログラミングおよび演習 第9回
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
第8回 プログラミングⅡ 第8回
理由:文字数より要素数の多い配列を用いた時に,文字列の最後を示すため
理由:文字数より要素数の多い配列を用いた時に,文字列の最後を示すため
構造体.
アルゴリズムとデータ構造 補足資料6-3 「サンプルプログラムcat3.c」
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
精密工学科プログラミング基礎 第9回資料 (12/11 実施)
ファイル操作と文字列の利用.
10: ファイル入出力 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング論 関数ポインタ と 応用(qsort)
ちょっとした練習問題① 配列iroを['R', 'W', 'R', 'R', 'W' , 'W' , 'W']を宣言して、「W」のときの配列の番号をprintfで表示するようなプログラムを記述しなさい。
プログラミング2 関数
プログラミング論 ファイル入出力
プログラミング応用 printfと変数.
プログラミング論 II 2008年10月30日 文字列
プログラミング 4 記憶の割り付け.
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
第10章 これはかなり大変な事項!! ~ポインタ~
04: 式・条件分岐 (if) C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
第13章 文字の取り扱い方 13.1 文字と文字型変数 13.2 文字列 13.3 文字型配列への文字列の代入
第13章 文字の取り扱い方 13.1 文字と文字型関数 13.2 文字列 13.3 文字型配列への文字列の代入
第7回 プログラミングⅡ 第7回
地域情報学 C言語プログラミング 第5回 ポインタ、関数、ファイル入出力 2017年11月17日
プログラミング論 ファイル入出力
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
09: ポインタ・文字列 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング基礎B 文字列の扱い.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
精密工学科プログラミング基礎Ⅱ 第4回資料 今回の授業で習得してほしいこと: 文字列の扱い ファイル入出力の方法 コマンドライン引数の使い方
情報処理Ⅱ 第2回:2003年10月14日(火).
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
プログラミング言語論 第六回 理工学部 情報システム工学科 新田直也.
プログラミング基礎a 第6回 C言語によるプログラミング入門 配列と文字列(その2)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
11: 動的メモリ確保 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング 3 2 次元配列.
文字列へのポインタの配列 static char *lines[MAXLINES]; lines[0] NULL
第13章 文字の取り扱い方 13.1 文字と文字型変数 13.2 文字列 13.3 文字型配列への文字列の代入
09: ポインタ・文字列 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと
11: 動的メモリ確保 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと
ネットワーク・プログラミング Cプログラミングの基礎.
第5回 プログラミングⅡ 第5回
情報処理Ⅱ 2006年11月24日(金).
情報処理Ⅱ 第7回 2004年11月16日(火).
11: 動的メモリ確保 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング 4 文字列.
11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
2005年度 データ構造とアルゴリズム 第2回 「C言語の復習:配列」
情報処理Ⅱ 2005年11月25日(金).
プログラミング演習II 2004年11月 16日(第5回) 理学部数学科・木村巌.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング入門2 第5回 配列 変数宣言、初期化について
情報処理Ⅱ 小テスト 2005年2月1日(火).
第1章 文字の表示と計算 printfと演算子をやります 第1章 文字の表示と計算.
第1章 文字の表示と計算 printfと演算子をやります.
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
Presentation transcript:

12: コマンドライン引数 C プログラミング入門 基幹7 (水5) Linux にログインし、以下の講義ページを開いておく こと http://www-it.sci.waseda.ac.jp/teachers/w 483692/CPR1/ 2017-07-05

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

今回の内容 コマンドライン引数の取り扱い シェルから引数 (オプション) を受け取る 技術的には二重ポインタ (double pointer) である ポインタへのポインタ 秋期の「Cプログラミング」で使うが、この講義ではあまり踏み込まない 文字列から数値への変換 コマンドライン引数は単なる文字列なので、数値として扱うには変換が必要

ポインタと文字列と配列の復習

アドレス値のことをポインタとも呼ぶことがある 復習:アドレスとポインタ メモリ上の位置を表す値 型を持つ 変数 a のアドレスは &a ポインタ変数に格納できる アドレス値のことをポインタとも呼ぶことがある int a { int a = 100; int *p = &a; printf("%d", *p); 100 int *p 矢印が指す位置のアドレスを持っている

デリファレンス演算子 * で、アドレスが指す位置の内容を読み書きできる 添え字演算子 [] で、ポインタの指す位置をずらして読み書きできる 復習:アドレス演算と読み書き デリファレンス演算子 * で、アドレスが指す位置の内容を読み書きできる 添え字演算子 [] で、ポインタの指す位置をずらして読み書きできる ポインタ p にはアドレスが入っている ポインタ p に対して p+1 は型の大きさ1つ分だけ動かしたアドレス ポインタ p に対して *(p+n) と p[n] は同じ p[0] == *(p+0) == *p == -23 -23 85 p[1] == *(p+1) == 85 p 矢印が指す位置のアドレスを持っている メモリ上のデータをどんな値とみなすかは、ポインタの型で決まる

配列変数名は、式中で配列の先頭へのポインタとなる 配列変数を a とすると a そのものがアドレス 復習:配列とポインタ 配列変数名は、式中で配列の先頭へのポインタとなる 配列変数を a とすると a そのものがアドレス &a[0] (0 番要素のアドレス) と同じ &a と書いてもよい それぞれ型が異なる場合があるが詳細は省略する。ポインタに関する専門書を参照 int a[4] 365 a[0] == *a == p[0] == *p == 365 p p = &a という代入をした場合

文字列=「メモリ上の文字 (char 型の値) が並んでいる領域」の先頭へのポインタ なぜ char 型なのかは歴史的な事情による 復習:文字列(ポインタ) 文字列=「メモリ上の文字 (char 型の値) が並んでいる領域」の先頭へのポインタ なぜ char 型なのかは歴史的な事情による 日本語を含む場合でも、基本的には char でよい 文字列リテラルを書くと、その文字列がシステム領域に用意され、その先頭ポインタを表す 文字列の終端は null 文字 ('\0') である なので、 null-terminated string と呼ばれる ほかに、 ASCIIZ とか C string とも呼ばれる { const char *s = "Hello world!\n"; s 'H' 'e' 'l' 'd' '!' '\n' '\0' ローカル変数 文字列データはシステム領域にある

配列を文字列リテラルで初期化すると、その文字数 + 1 の大きさの配列が生成される 復習:文字列(配列) 配列を文字列リテラルで初期化すると、その文字数 + 1 の大きさの配列が生成される 末尾に null 文字 ('\0') が自動的に付加される { char s[] = "Hello world!\n"; char s[] 'H' 'e' 'l' 'd' '!' '\n' '\0' ローカル変数

コマンドライン引数処理

ホワイトスペースで分割される (トークン化) コマンドは受け取った引数を処理する コマンドライン引数 シェルでコマンド名の後ろに書く文字列 ホワイトスペースで分割される (トークン化) コマンドは受け取った引数を処理する tokenize [user@host]$ gcc src.c -o src -Wall -Wextra この場合、 5 個の引数を gcc というプログラムに渡している [user@host]$ ./src hello world C 言語で書いた自作のプログラムに引数を渡した場合、どのように処理すればいいのか?

main 関数として以下のプロトタイプを使う int main(int argc, char** argv); コマンドライン引数の受け取り方 main 関数として以下のプロトタイプを使う int main(int argc, char** argv); cf. 今までのは int main(void); 引数名は何でもよいが慣用的に argc, argv または ac, av が使われる それぞれ、 argument count と argument vector (引数の列) という意味 第2引数の書き方として、 char **argv char *argv[] のどちらでも、文法上は同じである。後者の書き方をする人もいるので覚えておく

argv の内容 文字列へのポインタの配列 最後に null ポインタで終わる ./prog hello world 100 と実行した場合 char **argv argv[4] == NULL main 関数の自動変数の領域 システムのメモリ領域 argv[0][0] argv[0] '.' '/' 'p' 'g' 'r' 'o' '\0' argv[1] 'h' 'e' 'l' '\0' 'o' たとえば argv[1] が "hello" という文字列だと思えばよい 'w' 'o' 'r' '\0' 'l' 'd' '1' '0' '\0'

null ポインタの入っている要素の番号を表す n 個の引数を指定すると argc == n+1 ./prog hello world 100 と実行した場合 この例の場合 argc == 4 つまり、指定した引数の個数 + 1 char **argv argv[argc] == NULL main 関数の自動変数の領域 システムのメモリ領域 argv[0][0] argv[0] '.' '/' 'p' 'g' 'r' 'o' '\0' argv[1] 'h' 'e' 'l' '\0' 'o' 'w' 'o' 'r' '\0' 'l' 'd' '1' '0' '\0'

例題:引数をすべて表示する argv[i] を i = 1, ..., argc-1 まで表示 プログラム名が arg の場合 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 なので表示できない

例題:引数をすべて表示する (別の書き方) argv はポインタ変数であり、直接移動させることもできる プログラム名が arg の場合 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 が表す文字列が変わっていく NULL が現れるまで動かすので、 argc は必要ない 初期化条件は空 ポインタを動かすだけでは何番目かがわからない。必要なら変数を用意してカウントする

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

コマンドライン引数の注意 引数はあくまでも文字列である たとえば、 100 と書いても、 "100" という文字列でしかない 数値として扱うには標準ライブラリ関数で変換する (次のスライドで説明) 引数が空文字列になる場合もある たとえば、 ./prog "" abc と書いて実行すると、 argv[1] は空文字列、 argv[2] は "abc" 引数はシステム領域に作られるので、 (const はついていないが) 書き換えてはいけない

文字列から数値へ変換する

"100" という3文字 (+終端null) の文字列を int 型の 100 に変換したい そうしないと、ループとか計算で使えない 文字列→数値の変換 "100" という3文字 (+終端null) の文字列を int 型の 100 に変換したい そうしないと、ループとか計算で使えない 代表的な2つの方法を紹介 sscanf ato*, strto* 一族 // 例えば、 argv[1] == "3" だとして、 int i; int n = argv[1]; // 当然できない for(i = 0; i < n; ++i) { ...

sscanf() は、文字列を解析して変数に値を書きこむ プログラム名が arg の場合 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) 整数として変換する 整数として変換できない文字列だった場合は何もしない 整数として変換できるところまで使われる 変換対象の文字列

sscanf() は、文字列を解析して変数に値を書きこむ プログラム名が arg の場合 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) double として変換する 小数の値として解釈されている l (エル) は不要

文字列を数値に変換する関数として<stdlib.h> に以下の 2 種類がある 文字列を数値に変換する (2) 変換関数 文字列を数値に変換する関数として<stdlib.h> に以下の 2 種類がある atox() は簡単に使えるが、変換に失敗したかどうかを判断できない float ではない 関数名 変換する型 備考 atoi int 範囲外の値だった場合の戻り値は未定義。 変換に失敗した場合は 0 を返す。 (関数名は ASCII to x という意味 ASCII は文字コードのこと) atol long int atof double strtol 変換に変換に失敗した場合は 0 を返す。 失敗した位置をポインタとして得られる。 strtol, strtoul は基数 (何進法表記か) を指定する。 (関数名は string to x という意味) strtoul unsigned long int strtod

文字列を数値に変換する (2) 変換関数 なるべく右の strtox() を使うべき { // 整数に変換する例 { 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) { ... 10進数を指定 p は変換に失敗した最初の位置である。 もし、文字列の先頭と同じなら、1文字も解釈できなかったことになる 変換の失敗位置が必要なければ、 NULL を渡してもよい #include <stdlib.h> int atoi(const char *str); long strtol(const char *str, char **str_end, int base ); atoi, strtol のプロトタイプ