第6回目 簡単な構造体(5/15)
今日のキーワード
- malloc したメモリは、free するまで自由に使える
- 新しい変数タイプを作る
■ malloc で確保した領域について
- malloc を実行すると、引数で指定するバイト数だけ、メモリを確保する。その領域は、自由に読み書きできる。
- malloc を実行するプログラム上の場所は、main 関数内であっても、サブルーチン内であっても構わない。サブルーチン内で実行し、サブルーチンから呼出し元に return で戻ったときでも、確保したメモリ領域は、自由に読み書きできる。ローカル変数と異なる点である。
- free(ポインタ引数) というステートメント(プログラムのコマンド)がある。これを実行すると、そのポインタ引数で指し示された領域は、解放され、読み書きできなくなる。
- プログラムが終了すると、malloc で確保していたメモリは、free を実行しなくても、解放される。
■ 2次元ベクトルの構造体を作る
□ 宣言、代入、参照の例
/* list0601.c */
typedef struct{
double x;
double y;
} vector;
main()
{
vector a,b;
printf(”1つ目のベクトルを入力してください: ”);
scanf(”%lf %lf”, &(a.x), &(a.y));
printf(”2つ目のベクトルを入力してください: ”);
scanf(”%lf %lf”, &(b.x), &(b.y));
printf(”ベクトルを表示します。\n”);
printf(” a=( %2.2lf, %2.2lf )\n”, a.x, a.y );
printf(” b=( %2.2lf, %2.2lf )\n”, b.x, b.y );
}
□ 関数の引数(方法1)
メイン関数で vec_print を呼ぶと、引数 a がコピーされ、v に代入される。
- 関数内で、v の値を変えても、a には影響しない。
- 構造体の大きさが大きい場合、コピーにコストがかかる。
vec_print(vector v)
{
printf(”( %2.2lf, %2.2lf )”, v.x, v.y);
}
- - -
main()
{
- - -
printf(” a=”); vec_print(a);
printf(” b=”); vec_print(b);
}
□ 関数の引数(方法2)
メイン関数で vec_print を呼ぶと、引数 a のアドレス値がコピーされ、v に代入される。
- 関数内で、v の値を変えると(v->x = 0など)、a に影響する。
- 構造体の大きさが大きくても、アドレス値のみのコピーであるため、構造体サイズに依存しない。
vec_print(vector *v)
{
printf(”( %2.2lf, %2.2lf )”, v−>x, v−>y);
}
- - -
main()
{
- - -
printf(” a=”); vec_print(&a);
printf(” b=”); vec_print(&b);
}
■ 演習1 ⇒ prac0601.c
- 2つのベクトルの内積値を返す関数 dotproduct を作成せよ。
- 2つのベクトルの和を求める関数 vec_add を作成せよ。ただし、vec_add は 2 通りの作り方があり、1つは、3引数をとり、第1、第2引数の和を第3引数の変数に代入する方法である。もう1つは、2引数と1つの返り値をとるもので、2引数の和を、malloc により vector タイプで確保したメモリに代入し、そのアドレスを返す方法である。前者の方法で実現せよ。
- 2つのベクトルの差を求める関数 vec_sub を作成せよ。3引数をとること。
■ malloc を使う方法
vector タイプでメモリを確保するには、以下のようにする。ポインタ変数 c を使って、vectorのメンバ変数にアクセスするには、矢印「->」を使う。
vector *c;
c = (vector *)malloc(sizeof(vector))
c->x = 1.0;
c->y = 2.0;
■ 演習2 ⇒ prac0602.c
- malloc を使ってベクトルの和、差を返すように、prac0601.c を改造せよ。
□ malloc を使う時の注意点
- malloc での確保は、必ずしも成功するわけではない。返り値が NULL である場合は、確保に失敗している。その場合は、プログラムをエラー終了させる。
vector *v;
v = (void *)malloc(sizeof(vector))
if( v == NULL ){
fprintf(stderr,"エラー\n");
exit(-1);
}
- malloc で確保した領域は、不要になると解放すること。したがって、次のプログラムは、マズイ。
vector a,b;
vec_print( vec_add( a, b ) );
正しくは、たとえば、以下のようにする。
vector a,b, *c;
c = vec_add(a,b);
vec_print(c);
free(c);
◇ 演習2で、上記の処理をしていない場合は追加せよ。⇒ prac0603.c
■ 宿題
以下の2つのプログラムを作成せよ。
プログラム、手書きによるコメント、そして、実行結果を提出せよ。
- まず、分数を表す構造体 frac を作成せよ。frac を構成する変数は、分母と分子であり、それぞれ、int den; と int num; とする。 分数同士の四則演算を行う関数、add, sub, mult, div を、3引数の関数として、malloc を使わずに作成せよ。ただし、約分はしなくてよい。⇒ prac0604.c
- 角度を扱う構造体 angle を定義せよ。angle は角度をラジアンとするか度とするかを表す変数 unit、および、角度の値を表す変数 val、を持つ。角度の単位を変更する関数 angle_chunit、角度の足し算をする関数 angle_add、を作成せよ。ここで、angle_chunit は2引数の関数であり、第1引数に angle 型の変数を、第2引数に変更先の角度単位を指定し、第1引数の変数値を変更する。なお、角度単位の表現方法は自由とする。angle_add は2引数の関数であり、計算結果は、malloc によりメモリを確保したところに代入する。また、足される角度と足す角度の単位が異なる場合には、足される側の単位に揃えて計算するものとする。 ⇒ prac0605.c
(c) Masato TOKUHISA, 2003, May. 10