数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
今日の内容: #define typedef struct ファイルの読み書き 課題:行列を表す構造体とファイル読み書き
#define 定数(数値,文字列)に名前をつける #define ARRAY_LENGTH 100 int a[ARRAY_LENGTH]; for (i=0; i<ARRAY_LENGTH; i++) a[i] = 0; プログラム中に直接数値を書くと,値を変更し忘れたりするので, 極力名前を定義してそれを使う
typedef 通常の変数の型に違う名前をつけられる typedef int data_t; data_t x, y, z; ポインタの型なども定義できる typedef char *string_t; string_t name; // 文字列へのポインタ
struct (構造体)1 複数の変数をまとめたもの struct person { char *name; // 名前の文字列 int age; // 年齢 }; struct person P1; P1.name = “Kunihiko Sadakane”; P1.age = 10;
struct (構造体)2 typedef で構造体に名前をつけると便利 typedef struct { char *name; // 名前の文字列 int age; // 年齢 } person; person P1; P1.name = “Kunihiko Sadakane”; P1.age = 10;
struct (構造体)3 実行結果 age(P1) = 10 age(P2) = 11 構造体は関数の引数や返り値にできる person inc_age(person P) { person Q; Q = P; Q.age++; return Q; } int main() person P1, P2; P1.name = "Kunihiko Sadakane"; P1.age = 10; P2 = inc_age(P1); printf("age(P1) = %d\n", P1.age); printf("age(P2) = %d\n", P2.age); 構造体は関数の引数や返り値にできる 構造体変数間の代入もできる 実行結果 age(P1) = 10 age(P2) = 11
struct (構造体)4 実行結果 age(P1) = 11 age(P2) = 10 構造体のポインタを使うほうが一般的 int main() { person *P1, *P2; P1 = malloc(sizeof(person)); P1->name = "Kunihiko Sadakane"; P1->age = 10; P2 = malloc(sizeof(person)); *P2 = *P1; // 中身のコピー inc_age(P1); printf("age(P1) = %d\n", P1->age); printf("age(P2) = %d\n", P2->age); } #include <stdio.h> #include <stdlib.h> typedef struct { char *name; int age; } person; void inc_age(person *P) { P->age++; } 実行結果 age(P1) = 11 age(P2) = 10
struct (構造体)5 実行結果 age(P1) = 11 age(P2) = 11 注意:ポインタの代入では中身はコピーされない さらに注意:中身をコピーした場合でも,構造体の要素 name は ポインタなので,元の文字列を変更するとそれを参照している全ての変数 が変わる int main() { person *P1, *P2; P1 = malloc(sizeof(person)); P1->name = "Kunihiko Sadakane"; P1->age = 10; P2 = P1; // ポインタの代入 inc_age(P1); printf("age(P1) = %d\n", P1->age); printf("age(P2) = %d\n", P2->age); } #include <stdio.h> #include <stdlib.h> typedef struct { char *name; int age; } person; void inc_age(person *P) { P->age++; } 実行結果 age(P1) = 11 age(P2) = 11
行列を構造体で表す typedef struct { int n, m; // 行数,列数 double **A; // (行を表す配列)の配列へのポインタ } matrix; matrix *malloc_matrix(int n, int m) { matrix *a; int i; a = malloc(sizeof(*a)); a->n = n; a->m = m; a->A = malloc(n * sizeof(double *)); for (i=0; i<n; i++) { a->A[i] = malloc(m * sizeof(double *)); } return a; main() { matrix *a; a = malloc_matrix(10, 10); }
ファイル操作の手続き: ファイル操作 ファイルからのデータ読み込み ファイルへのデータ書き出し 基本的な手順 読みこむ/書き出すファイルを開く (fopen) 読み込み/書き出しの操作 (fscanf/fprintf) ファイルを閉じる (fclose)
ファイルを開く/閉じる: fopen/fclose fopen(ファイル名, モード) モード:r(読み込み), w(書き込み), a(追記) FILE *fp; // ファイルポインタの宣言 fp = fopen(“input.txt”, “r”) ; // 読み込みモードでinput.txtを開く fclose(fp); // 閉じる 各種ファイル処理
ファイルへの書き込み、読み込み: ファイルポインタ以外はprintf/scanfと同様 書き出し:fprintf(ファイルポインタ, …) fprintf(fp, “%d \n”, i) 読み込み:fscanf(ファイルポインタ, …) 整数は %d, 実数は %lf int x; double y; fscanf(fp, “%d %lf”, &x, &y); ファイルの最後に到達した場合 EOF を返す if ( fscanf(。。。) == EOF ){….}
コマンドライン引数の利用 ./a.out input.txt 10 0.1 と引数をつけて実行したとき argc = 4; argv[0] = “./a.out”; プログラム名 argv[1] = “input.txt”; argv[2] = “10”; argv[3] = “0.1”; int main(int argc, char *argv[]) { FILE *f; int n; double x; if (argc < 4) exit(1); // 引数が足りない f = fopen(argv[1], “r”); n = atoi(argv[2]); // 文字列を整数に x = atof(argv[3]); // 文字列を実数に }
課題 n 行 m 列の行列をファイルから読み込み,新たに確保した行列に代入 matrix *input_matrix(char *filename); 行列を入力と同じ形式でファイルに出力 void output_matrix(char *filename, matrix *a); 2つの行列 A, B の積を計算し,新たに確保した行列 C に代入 matrix *product(matrix *A, matrix *B); 行列のサイズが合わないときは C は確保せずに NULL を返す 行列のメモリを開放する void free_matrix(matrix *A);
行列のファイル形式 2 3 1.0 2.0 3.0 4.0 5.0 6.0 行数 列数 1行目 2行目
課題の提出: 本日(4/21)の18時までに提出 提出ファイルをメールに添付し以下に送付 宛先:miprogramming2014+3@gmail.com