200 likes | 292 Views
情報基礎演習 B 後半第5回. 担当 岩村 TA 谷本君. 前回の復習1. 構造体 新しい変数の型を定義する メンバの参照 ドットを用いる. 変数名 . メンバ. 前回の復習2. ファイルポインタの宣言 FILE *fp; ファイルのオープン fp=fopen(“ ファイル名” , “ モード” ); モード r: 読み込み(ファイルがなければエラー) w: 書き込み(既にファイルがあれば破棄して上書き) a: 追加(ファイルがあれば。なければwと同じ) ファイルのクローズ fclose(fp);. 先週の課題.
E N D
情報基礎演習B後半第5回 担当 岩村 TA 谷本君
前回の復習1 • 構造体 • 新しい変数の型を定義する • メンバの参照 • ドットを用いる 変数名.メンバ
前回の復習2 • ファイルポインタの宣言 FILE *fp; • ファイルのオープン fp=fopen(“ファイル名”, “モード”); • モード • r: 読み込み(ファイルがなければエラー) • w: 書き込み(既にファイルがあれば破棄して上書き) • a: 追加(ファイルがあれば。なければwと同じ) • ファイルのクローズ fclose(fp);
先週の課題 • 任意の人数の名前、身長、体重をファイルから読み込み、BMIを計算して出力するプログラムを作成しなさい • 名前、身長、体重、BMIを扱う構造体を使う • データファイルは用意してあるものを使う • データファイルの構造 人数、(1人目の)名前、身長、体重、 (2人目の)名前、身長、体重… • ただし身長の単位はcm、体重はkg
後半の予定 • 関数 • ポインタ(前半) • ポインタ(後半) & メモリの動的確保 • 構造体 & ファイルの入出力 • プリプロセッサ & 復習+α (おまけ)文字列処理 & コマンドライン引数の処理
プリプロセッサ • コンパイル前にプログラムを書き換える処理 • 例) • #include <stdio.h> • #define N 50
ファイルの挿入(#include) • 関数は使う前に定義が必要 #include<stdio.h> int main(void){ printf(“hello!!\n"); return(0); } 修正後のプログラム /* stdio.h */ printfの定義… fprintfの定義… scanfの定義… fscanfの定義… /* stdio.h */ printfの定義… fprintfの定義… scanfの定義… fscanfの定義… int main(void){ printf(“hello!!\n"); return(0); } コンパイル前に プログラムを修正
マクロ定義 (#define) • 文字列の置き換え • #define N 50 • マクロの定義 • #define wa(a,b) a+b 副作用があるので注意が必要
文字列の置き換え • コンパイル前に文字列を置き換える • 書式 #define 置き換える文字列 置き換えられる文字列 • 例 • #define N 50 • #define FILENAME “data.txt” • 効能 • 後で数値やファイル名などを変えたいとき、一括して変えられる
マクロの定義 • コンパイル前に文字列を置き換えて、関数のような処理を行う • 例) #define wa(a,b) a+b printf("wa(x,y) = %f\n",wa(x,y)); 文字列の置き換えによって wa(x,y)x+y を実現
マクロの定義と関数の違い • 関数との違い • 変数の型がない • 単にソースコードを変更しただけなので • 余計な処理時間がかからない • 普通関数を呼び出すと多少時間がかかる • マクロは単にソースコードを変更しただけ • 注意しないと意図した動作をしない場合がある(副作用)
マクロの定義の副作用 • プログラム #define kake(a,b) a*b printf("wa(x,y) = %f\n",kake(x,y+10)); • マクロの展開 kake(x,y+10)x*y+10 ≠x*(y+10) 括弧がない!
これまでの復習+α • ポインタについて • アドレスを扱う変数 • 関数の呼び出し方法の違い • 値を渡す • アドレスを渡す(配列を渡す) • 配列の先頭のアドレスを関数に渡せば、配列を関数に渡したことになる
ポインタ • アドレスを扱う変数 • 具体的には、変数が格納されているメモリの先頭番地を記憶する
動的な配列の確保(malloc) • ポインタを用意すれば、mallocが配列を確保してくれる • 関数の先頭でなくてもよい • 配列の大きさはプログラムの実行後に決定可能 • 一方、配列だと… • 関数の先頭でないと宣言できない • 配列の大きさはコンパイル時に決定(定数のみ) • 配列でよくある間違い int n; int a[n]; nは変数! これはmallocでしか実現できない
動的でない配列(int a[3]) a自体がポインタみたいなもの
関数への値の渡し方 関数wa main関数 a,bの値をx,yにコピー int wa(int x, int y) { int z; z=x+y; return z; } … sum=wa(a,b); … zの値をsumにコピー 関数wa(参照渡しversion) main関数 void wa(int *z, int x, int y) { *z=x+y; } … wa(&sum, a,b); … sumの中身を変更 sumのアドレスをzにコピー
配列を関数へ渡す方法 mallocで配列を確保した場合 int wa_all(int n, int *a) { int i, t=0; for (i=0; i<n; i++) { t += a[i]; } return(t); } int *a, n=5, total; a = (int *)malloc(sizeof(int)*n); … total = wa_all(n, a); … free(a); int a[5]で配列を確保した場合 int wa_all(int n, int a[]) { int i, t=0; for (i=0; i<n; i++) { t += a[i]; } return(t); } int a[5], n=5, total; … total = wa_all(n, a); …