270 likes | 425 Views
構造体. 構造体とは. 複数のデータを一つのまとまりとして定義したもの 例えば、 個人データを整理することを考えてみましょう。 項目として、 名前 メールアドレス 内線番号 の3つを1人分のデータとして一まとまりとすることにしましょう。 名前は、 文字列 メールアドレスも 文字列 内線番号は、 4桁の整数 . Itoh Yukihiro itoh@cs.inf.shizuoka.ac.jp 1474 Sato Fumiaki sato@cs.inf.shizuoka.ac.jp 1453. これらの各々を 「一つの」データとみる。 つまり、
E N D
構造体とは • 複数のデータを一つのまとまりとして定義したもの例えば、 • 個人データを整理することを考えてみましょう。項目として、名前 メールアドレス 内線番号の3つを1人分のデータとして一まとまりとすることにしましょう。 名前は、 文字列 メールアドレスも 文字列 内線番号は、 4桁の整数
Itoh Yukihiro itoh@cs.inf.shizuoka.ac.jp 1474 Sato Fumiaki sato@cs.inf.shizuoka.ac.jp 1453 これらの各々を 「一つの」データとみる。 つまり、 グリーンのカード1枚が 一つのデータとみる。
新しい「型」を定義する 新しい「型」の定義 • 一つのデータが複数のデータのまとまり 個々のデータの型も文字列と文字列と様々 • そんなデータは、既存の型では入りきらない
新しい「型」の定義の方法 新しく定義する「型」の名前 構造体タグ名 struct parsonal_data { char name[20]; char address[50]; int num; }; ひとまとまりのデータを構成する 個々の要素データの名前と型 メンバー struct タグ名 { メンバ1 [型 変数(配列)名] メンバ2 [型 変数(配列)名] ・ ・ }; 一般的には
これと同様に 新しい「型」のデータの宣言 • ここまでは、あくまでも「型」の定義 • int型、floatg型、char型などと共に、parsonal_data型が使えるようになっただけ • 実際に整数型の変数を使うためには、 変数宣言が必要 • parsonal_data型の「構造体」を宣言する
構造体の宣言 struct parsonal_data itoh; “itoh”という名前の構造体が用意される。 これは、 nameという文字列 addressという文字列 numという整数 がひとまとまりになったもの。
構造体の型定義と宣言を同時にする struct parsonal_data { char name[20]; char address[50]; int num; } itoh, nakatani;
構造体の型定義と宣言を同時にし、更に初期値を設定する構造体の型定義と宣言を同時にし、更に初期値を設定する struct parsonal_data { char name[20]; char address[50]; int num; } itoh={ “YUKIHIRO ITOH”, “itoh@cs.inf.shizuoka.ac.jp”, 1474 };
構造体への値の代入・参照 struct parsonal_data itoh, nakatani; strcpy(itoh.name, “YUKIHIRO ITOH”); strcpy(itoh.address, “itoh@cs.inf.shizuoka.ac.jp”); itoh.num=1474; call=itoh.num; initial=itoh.name[0];
構造体をそっくりそのまま代入 struct parsonal_data itoh, clone; strcpy(itoh.name, “YUKIHIRO ITOH”); strcpy(itoh.address, “itoh@cs.inf.shizuoka.ac.jp”); itoh.num=1474; clone = itoh;
構造体の配列 struct parsonal_data progsatff[4]; さっきの itoh みたいな構造体が4つ並んだ配列 仮に、progstaff[0]に 伊東のデータが入っていたとすると、 prog_staff[0].name “YUKIHIRO ITOH” prog_staff[0].address[0] “i”
構造体のメンバにポインタもかける R I I T Y U K O I H ・・・ char add_list[100][50]; struct parsonal_data { char name[20]; char *add_ptr; int num; } itoh={ “YUKIHIRO ITOH”, add_list[0], 1474 ポインタ add_ptr 1474 num add_list add_list[0]
コマンド行の引数 #include <stdio.h> int main(int argc, char *argv[]) { int i; printf("argc = %d\n\n", argc); printf("その内容は:\n"); for (i = 0; i < argc; i++) { printf(" argv[%d] : %s\n", i, argv[i]); } return 0; }
main(argc, *argv[]) • コマンド行入力を受け付ける場合のメイン関数の定義の書式 • argcargument count の意味 • argv argument value の意味
argc • コマンド行を空白で区切ったとき、 いくつの文字列から構成されるかを表す整数値が入る。
argv[ ] • 空白で区切られた文字列が、順にargv[0], argv[1], ・・・ に入る。
argv[0] argv[1] argv[2] argv[3] 4 従って、 $ ./args foo bar baz とすると #include <stdio.h> int main(int argc, char *argv[]) { int i; printf("argc = %d\n\n", argc); printf("その内容は:\n"); for (i = 0; i < argc; i++) { printf(" argv[%d] : %s\n", i, argv[i]); } return 0; }
実行結果は、 $ ./args foo bar baz argc = 4 その内容は: argv[0] : ./args argv[1] : foo argv[2] : bar argv[3] : baz
ファイルの入出力 • ファイルを開く (fopen) • ファイルを読む (fscanf) • ファイルに書く (fprintf) • ファイルを閉じる (fclose) いずれの操作もファイルポインタ(ファイル変数)という特殊なポインタを通じて行う
ファイルポインタの用意 FILE *ファイル変数; 例えば、 FILE *fp1
"w" ファイルのオープン fopen("ファイル名""モード") fopenはオープンされたファイルを指すポインタを返す。 エラーの場合にはNULLを返す。 そのポインタをファイルポインタに格納しておく。 fp1 = fopen("foo.txt", "r" ); if (fp1 == NULL) { printf("Cannot open file '%s'.\n", "foo.txt"); exit(1); } 読み込み(read)モード "r" 書き込み(write)モード "w"
ファイルの読み込み fgets fgets(文字列, 文字列サイズ, ファイルポインタ) 例えば、 #define BUFLEN 1024 char buf[BUFLEN]; fgets(buf, BUFLEN, fp1); stdinとは? ようやく正体をあらわしたな!!
ファイルの読み込み fscanf fscanf(ファイルポインタ, 書式, パラメータ) sscanfとほとんど同じ 違いは、 sscanf 文字列を対象とする fscanf ファイルを対象とする
ファイルへの書き込み fprintf(fp1, "%d", a);
ファイルのクローズ fclose int f; f = fclose(fp1); if (f != 0) { printf("Cannot close file '%s'.\n", "foo.txt"); exit(1); }
ファイルの最後 EOF(End of File) 1度オープンしたファイルからデータを複数回読み出すと、2回目に読んだ場所は、1回目に読み終わった次の場所から順次読み出します。 ファイル 最初に読んだところ 2回目に読んだところ 3回目に読んだところ ファイルの最後まで読み終わって、終端まで来たときに、 1文字ずつ読み出す関数は文字の代わりに EOF という コードを返します(教科書p.215のプログラム例)。 (int getchar(void), int fgetc(FILE *fp) など) 文字列を読み出す関数は、NULLを返します。 (char *fgets など)