ポインタと配列 ポインタと配列 配列を関数に渡す 法 課題 : 配列によるスタックの実現
ポインタと配列 (1/2) a が配列であるとき, 変数の場合と同様に, &a[0] [] の値は配列要素 a[0] のアドレス. C 言語では, 配列は主記憶上の連続領域に割り当てられるようになっていて, 配列名 a はその配列に割り当てられた領域の先頭番地となる. したがって,&a[0] と a は同じ値. 右図では共に 1200. また,TYPE 型 (int や float など ) へのポインタに 3 を足すと,TYPE 型に必要なバイト数 3 を足したことになり, &a[3] と a+3 の値は共に a[3] のアドレス. したがって, a[3] への参照は,*(a+3) でも行える. 注意 : 配列名 ( 上記では a) に値を代 することはできない. 1200 120 1 int a[10] 1 a[0] 1204 1236 1240 a[1] a[9] 1
ポインタと配列 (2/2) 前ページで述べたことから, たとえば, 要素数 10 の int 型の配列 a に記憶されている値を順に表示する次の文 for(i=0 ; i<10 ; i++) printf( %d n, a[i]); は以下のように書くこともできる. p=a ; for(i=0 ; i<10 ; i++) { printf( %d n, *p) ; p++ ; printf( %d n,*(p+i)) でも OK 配列 ( の先頭番地 ) を引数とする関数では, 上記のような配列要素の参照法を使うことがある. 2
配列を関数に渡すには (1/2) #include <stdio.h> int SumArray(int *, int); int main() { int a[5] ; a[0]=12; a[1]=8; a[2]=21; a[3]=59; a[4]=1; printf( %d n,sumarray(a,5)); 配列 a の先頭アドレスと 要素数を SumArray に渡す int SumArray(int *d, int n) { int i, sum=0; d に格納されているアドレ for(i=0 ; i<n ; i++) { スから,4バイトごとに sum = sum + *d ; int 型の値を n 個取り出 d++; し, 合計する ( 合計は sum に記憶 ) return(sum); この例では, 渡された配列の要素の値を変更 してはいないが, 勿論, 変更することも可能 3
配列を関数に渡すには (2/2) 先の例の関数 SumArray は int SumArray(int d[], int n) { int i, sum=0; for(i=0 ; i<n ; i++) { sum = sum + d[i] ; return(sum); としてもよい ( 仮引数には, 配列名と型だけで要素数が示されていないことに注意 ). この場合, プロトタイプ宣言 ( 予告編 ) は次のようになる. int SumArray(int[], int); 2 次元配列,3 次元配列などの多次元の配列を関数に渡す場合には配列を関数, 主記憶上の連続領域に要素がどの順番で並んでいるかに注意しなければならない. 詳しくは参考テキストを参照. 4
演習 (1/2) 1. 次のプログラムを書いて実行し, 表示される値の意味を考えよう. #include <stdio.h> int main() { int a[5], *p, i ; for(i=0 ; i<5 ; i++) a[i]=i*10; p=a; for(i=0 ; i<5 ; i++){ printf( p=%p(%u) p=%p(%u),*p=%d,a[%d]=%d n a[%d]=%d n,p,p,*p,i,a[i]); p p++ ; 5
演習 (2/2) 2. 関数 DspArray(int *array, int n) は, 第一引数 (array) としてint 型の配列の先頭番地を, 第二引数 (n) として整数を受け取り,array に渡された番地から連続 n 個の int 型の値を表示する関数である. この関数を定義し,main 関数では以下のように, 整数を10 個入力し, それを大きさ 10 の int 型の配列 a に記憶し,DspArray を利用して,a[0]~a[9] の値を表示する. プログラムを完成せよ. また, main 関数の赤の部分を DspArray(&a[2],3) とどうなるか確かめよ. #include <stdio.h> void DspArray(int *, int); int main(){ int i, a[10]; for(i=0 ; i<10 ; i++) { printf( a[%d]=,i); scanf( %d,&a[i]); DspArray(a,10); /* DspArray の定義 */ 6
課題 11(1/4) スタックとは, 値を記憶する ( 積む,PUSH する ) ことと, 最後に記憶した値を取り出す (POP する ) ことができるデータ構造 ( 記憶装置 ) である. 70 24 24 33 24 24 初期状態 データ 24 を PUSH データ 70 を PUSH POP して,70 を取り出す データ 33 を PUSH 要素数 N の int 型の配列 stk を用いて整数を記憶するスタックを実現しよう. 現在のスタックのトップの配列要素の番号を示す変数を top とすると, 上記の状態はそれぞれ, 以下のように表せる. top = N top = N-1 top = N-2 top = N-1 top = N-2 stk[n-1]=24 stk[n-2]=70 stk[n-1]=24 stk[n-2]=33 stk[n-1]=24 stk[n-1]=24 7
課題 課題 11(2/4) 後述するような仕様の関数 push, pop を利用し,main 関数では, 次のようなスタック操作命令 i5 5 を PUSH o POP を読み込んで ( 終了は C-d とキー入力することで表す ), PUSH のときで, 正常に PUSH できた場合には, スタックの全体表示 POP のときで, 正常に POP できた場合には,POP された値とスタック全体の表示 をする. このようなプログラムの一部 ( 主に main 関数の部分 ) を次ページに示す. プログラムを完成し, これにより, スタックへの操作が正しく行われていることを確認せよ. 8
課題 11(3/4) #include<stdio.h> int push(int, int*, int*), pop(int*, int*, int*); void dsp_ stack(int, int*); #define N 5 int main() char 型は1 文字を扱うデータ型である. { この宣言により,char 型の変数 cmd を int data, stk[n], top=n; 宣言している. char cmd; cmd に1 文字読み込む while(scanf("%c",&cmd)!=eof){ ( ){ if(cmd=='i') { 読み込んだ文字が i かどうかの比較 scanf("%d",&data); このように文字は で囲む. if(push(data,&top,stk)==1) dsp_stack(top, stack(top stk); else if(cmd=='o'){ 読み込んだ文字が o かどうかの比較 if(pop(&data,&top,stk)==1){ p p printf( poped data=%d n",data); dsp_stack(top, stk); /* 以下, 関数 push, pop, dsp_stack の定義 */ 9
課題 11(4/4) int push(int data, int *sp, int *STK) : スタックへの PUSH STK にはスタックを表現している配列の先頭番地が渡され,sp には変数 top のアドレスが渡される. この状態のスタックに data を PUSH する関数. ただし,PUSH できる (sp が指す内容 > 0) 場合は, 実際に PUSH し, 返り値として 1 を返して終了.PUSH できない場合は, 返り値として 0 を返して終了.PUSH できた場合は,sp に渡されるアドレスの中身 ( つまり, 変数 top の値 ) は1 小さくなることに注意. int pop(int *datap, int *sp, int *STK) : スタックから POP STK にはスタックを表現している配列の先頭番地が渡され,sp には変数 top のアドレスが渡される. この状態のスタックから値を POP し, datap で示されるアドレスに格納する関数. ただし,POP できる (sp が指す内容 <N) 場合は, 実際に POP し, 返り値として 1 を返して終了. POP できない場合は, 返り値として 0 を返して終了.POPできた場合は,spに渡されるアドレスの中身( つまり, 変数 top の値 ) は 1 大きくなることに注意. void dsp_stack(int top, int *a) : a[top]~a[n-1] の値を表示実行例 :dsp_stack(3,stk) stack(3 stk) (N=5 と仮定 ) 3: 10 4: 21 10