授業内容

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