プログラミング演習 II
2003
年10
月29
日(第2,3
回)木村巌
今日やること
配列の復習
ポインタの復習
多倍長整数の配列での実現 足し算と繰り上がり
malloc()
とfree()
配列
それぞれの型
T
について、T
型の配列が存在 する(void
型、「…を返す関数」型を除く)
:
T var[16];
のように宣言する.
T
は、整数、浮動小数点 数、文字、などが主な例.例:
int ary[16];
int
型の配列.ary[0]
からary[15]
までの16
個配列の正体
T
型の値を、指定された個数だけ保持 できるメモリの先頭のアドレス(T
型 のポインタ).例:
int ary[16];
sizeof (ary); /* == sizeof (int) * 16 == 64byt
e */
配列は 0 から始まる
配列は、
0
から始まる添え字を持つint ary[16]
なら、ary[0]
からary[15]
ま で.ary[16]
を読み書きしても(読み書きできてしまう!)、結果は予測できな い!!
配列の要素はすべて同じ型
int ary[16];
と宣言すると、
ary[0]
からary[15]
はす べてint
型.配列の初期化
int ary[3] = {1, 2, 3};
int ary[] = {1, 2, 3};
どちらも同じ意味.
後者のほうが間違いがない(コンパイ ラが要素の数を数えてくれる).
レポート課題1(フィボナッ チ数)
フィボナッチ数
f(n)
は、次の漸化式で 定義される:f(0) = 1, f(1) = 1,
f(n) = f(n-1) + f(n-2), n >= 2.
f(n)
を求めるプログラムをCで書け.各 項はlong
で表すこと何項目まで正しく求められるか?
多倍長整数の配列での実現
暫定的に、以下のようにする:
配列の長さを固定:
DIM
とする 基数を固定:BASE
とするlong
の配列、次元はDIM
とりあえず非負整数のみ添え字の小さい方が小さい方の桁
多倍長整数の配列での実現
(2)
つまり、
#define BASE 10
#define DIM 3
long a[DIM] = {1, 0, 0}; /* DIM = 3 */
なら、
a = 1 + 0*10
1+ 0 * 10
2 =1.
DIM
桁のBASE
進表記繰り上がり
a = a_0 + a_1*10^1 + a_2 * 10^2, b = b_0 + b_1*10^1 + b_2 * 10^2,
のとき、
c=a+b
をどのように計算するか考える
各
c_i=a_i+b_i
をi
桁目にするのではな いBASE
より大きくなったときに、次の 桁へ繰り上げるプログラム例
( mpinteger-wo-malloc.c )
以上のようなアイディアで、フィボナ ッチ数の計算を行うプログラムを作る
.
ポインタ型
C
の型の一つ任意の型
T
に対して、「T
のポインタ 型」が定義できる従って、「 T のポインタのポインタ」型 等々も定義できる
例:
integer
型のポインタ型変数a……int
*a
例:
char
型のポインタ型変数s…char *s
ポインタって何 ?
型
T
のポインタ型の値は、型T
のモノ(
object
)のアドレス(メモリ上の場所)
型
T
のポインタ型の変数は、型T
のモ ノのアドレスを保持するのに必要なだ けのメモリを占めるポインタの作り方
型
T
のモノから、それを指すポインタ値を つくるには、アドレス演算子&
を使う例:
int a = 1; int *aptr; aptr = &a;
型
T
のポインタ値から、それが指している 型T
のモノを見るには、間接演算子*
を使 う例:
int *bptr; int b;
ポインタって何?(続)
int a = 1; /*
int が保存できるメモリを確保し、 1 を 保存*/
int *aptr = &a; /*
そのメモリの番地*/
1
aptr
ポインタに対して出来ること
T *p; /* p
がT
型のポインタ*/
ポインタの間接参照(そのポインタが 指すモノを取り出す):
*T /* T
型のモ ノ*/
ポインタの算術:
T ary[8]; T *p = &ary [0];
ならば、
p + i
とary[i]
とは同じメなぜポインタがいるのか ?
一つの理由は、
C
言語での関数引数が、値渡しだから 例
int a = 1; f(a);
とすると、
f()
に渡されるのは、a
の値 のコピー.変数a
そのものが渡されるの ではないプログラム例:
swap.c
を参照ポインタと配列との関係(テキ スト10章)
式の中に現れる配列は、「
T
の配列」から「
T
へのポインタ」に変換される(ary_ptr.c
参 照)
このときのポインタは、配列の
0
番目の成分 を指すポインタint a[8], *aptr; aptr = a;
と、
int a[8], *aptr; aptr = &a[0];
とはまったく同じ
メモリの確保:静的な確保
これまでは、プログラムの字面に、メ モリの確保が指示されていた:
たとえば、
long a[10];
は、sizeof(long) *
10 byte
のメモリを確保し、その先頭アドレスを
a
という名前で識別するプログラムの実行が始まる前、コンパ イル時にすべてのメモリが確保されて
メモリの動的確保: malloc()
プログラムの実行が始まってから、指 定された大きさのメモリを確保するラ イブラリ関数:
void *malloc(size_t).
malloc (16);
で16byte
のメモリを確保し、その先頭アドレスを返す
.
返されるアドレスは、
void
型のポインタVoid
型のポインタは、任意の型に変換可 能な「総称型」(generic type
)型の明示的変換(キャスト)
C
の型システムでは、一定の規則の下 で、型の変換が行える.当然行えるべき変換…
int
からlong, flo at
からdouble, int
からfloat, long
からd ouble
など:int a; long aa; aa = (long) a;
逆もある.(精度の切り捨て)
総称型: void *
malloc()
で確保したメモリは、何に使われるか限定できない
何にでも使える型:
void *
実際には、
void *
をほかの型に変換(キャスト)して使う 例
void *tmp; tmp = malloc (16);
malloc() の使い方
場合によっては、メモリの確保に失敗する
.
その場合、返値が
NULL
.void *tmp;
long *a;
tmp = malloc (sizeof (long) * 4);
if (tmp == NULL) /* エラー処理 */
else a = (long *)tmp;
変数のエクステント
変数の有効期間
関数内で宣言された変数は、その関数 内に制御がある間のみ有効だった(プ ログラミング演習Iの
6/15
の回の資料 参照)関数内で確保したメモリは、明示的に 解放されるまで有効.
malloc() を使った多倍長計算
プログラム例参照.
レポート課題 2
BASE100, DIM 3
の場合、1. a = 23 + 34*100 + 45*100^2, b = 11 + 22*10 0 + 33*100^2
について、a+b
を手で計算せ よ.2. a = 23 + 34*100 + 45*100^2, b = 88 + 77*10
0 + 44*100^2
について、a+b
を手で計算せ よ.レポート課題 3
プログラム例
mpinteger.c
で、BASE
を100とし、mpinteger-wo-malloc.c
のように、引数として何番目のフィボ ナッチ数まで計算するかを指定できる ように改造したものを作成せよ.レポート課題提出要領
2003
年11
月4
日(火)一杯に、木村 までメールで送ること.アドレスはiwao@sci.toyama-u.ac.jp
添付ファイルではなく、できるだけメ ール本文にレポート本文を記載してく ださい.
参考にした文献や友人のレポートは、
その旨明記すること.