プログラミング論 II 2009年10月15日 ポインタ http://www.ns.kogakuin.ac.jp/~ct13140/Prog.2009/ 1 見つかった誤り if( x = 3 ){ ... } "x=3"は比較ではなく、代入. x += 2 は、"xが2増える"が, x =+ 2 は、"x に +2 を代入"となる. つまり "x = +2"となってしまう D-2 見つかった誤り x = x+1; はOK. x+1 = x; はNG. 代入は 右の値を左に入れる. x = 3 はOKだが, 3 = x はNG. D-3 見つかった誤り • #define MAX 100 は,MAXを100に置き換えてからコンパイルする – MAXという変数があるわけではない! #define MAX 100 i=MAX; #define MAX 100 MAX=30; MAXという変数が あるわけではない これを i=100; コンパイル これを 100=30; コンパイル???? D-4 概要 • ポインタ – 難易度が高いが,極めて重要 – & と * の2種類しかない. • ちなみに… –前期最重要事項 : 関数 –後期最重要事項 : pointer D-5 5 ポインタ • なにかを「指す」ものがポインタである. • C言語ではアドレスを理解すれば良い. • 一般に理解が難しいとされる D-6 メモリとアドレス • 計算機はメモリにデータを保存している. – 通常1バイト(8bit)単位で管理される. – 1バイトの記憶領域が大量にある. • 各バイトには,固有の通し番号(住所,アドレス) がついている. それぞれのメモリに 1バイトのデータを 記憶できる. 各1バイトに固有の 住所がついている. 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 7 100 56 23 53 1バイトの記憶領域が10個ある例. 45 95 2 0 65 D-7 変数の記憶領域 • 変数を作ると,当然メモリ上にそのための記憶領 域が自動的に確保される. char abc; /* char型変数を1個用意 */ 変数abcの内容は, 4番地に記録する ことに決めたとする. (計算機が自動で行う) abc 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 7 100 56 23 53 45 95 2 0 65 D-8 変数の記憶領域 • 変数を作ると,当然メモリ上にそのための記憶領 域が自動的に確保される. char abc; /* char型変数を1個用意 */ char *p; &abc は,「変数abcは メモリの何番地か」を返す. abc = 7; pには「4番地」が入る. p = &abc; 7では無いことに注意! abc 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 7 100 56 23 7 45 95 2 0 65 D-9 &演算子 • &演算子はアドレスを調べる演算子. • 変数に&を付けると,そのアドレスが得られる. void main(){ char abc; char *p; p = &abc; printf("abcのアドレスは%pです.\n", p); } 実行結果 abcのアドレスは0013FF7Cです. D-10 &演算子 void main(){ char abc, def; char *p; p = &abc; printf("abcのアドレスは%pです.\n", p); p = &def; printf("defのアドレスは%pです.\n", p); } 実行結果 abcのアドレスは0013FF7Cです. defのアドレスは0013FF78です. D-11 &演算子 void main(){ char abc, def, ghi; printf("アドレスは%p %p %pです.\n", &abc, &def, &ghi); } 実行結果 アドレスは0013FF7C 0013FF78 0013FF74です. D-12 &演算子 void main(){ char abc[5]; printf("アドレスは%p %p\n%p %p %pです.\n", &(abc[0]), &(abc[1]), &(abc[2]), &(abc[3]), &(abc[4])); } 実行結果 アドレスは0013FF78 0013FF79 0013FF7A 0013FF7B 0013FF7Cです. D-13 &演算子 void main(){ int abc[5]; printf("アドレスは%p %p\n%p %p %pです.\n", &(abc[0]), &(abc[1]), &(abc[2]), &(abc[3]), &(abc[4])); } int型は4バイト 実行結果 アドレスは0013FF6C 0013FF70 0013FF74 0013FF78 0013FF7Cです. D-14 ポインタ変数 • アドレスを格納する変数 – 整数を格納できる変数があるように, アドレスを格納する変数がある. char ch; /* char型を格納する */ char *p; /* char型変数のアドレスを格納 */ p = &ch; /* ch は"4番地"なので,pには"4番地"が入る ch 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 7 100 56 23 7 45 95 2 0 65 D-15 アドレス型変数(ポインタ変数) • アドレスを格納する変数 – 整数を格納できる変数があるように, アドレスを格納する変数がある. char ch; /* char型を格納する */ char *p; /* char型変数のアドレスを格納 */ p = &ch; printf("アドレスは%pです\n", p); ポインタ(アドレス型)をprintfで表示するには, %p を使う. D-16 *演算子 • アドレスの間接参照演算子. • アドレスの中身にアクセスする. 変数a,b,pを宣言した. char a, b; char *p; それぞれ,メモリの 6番地,5番地,4番地が 割与えられたとする. 注意:実際はアドレスは1バ イトではない. p b a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 D-17 *演算子 • アドレスの間接参照演算子. • アドレスの中身にアクセスする. char a, b; char *p; 変数aに53を代入. a = 53; つまり,メモリの6番地に 53を格納. p b a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 53 D-18 *演算子 • アドレスの間接参照演算子. • アドレスの中身にアクセスする. char a, b; char *p; &aで変数aのアドレスを得る. 変数aは6番地なので, a = 53; pには6番地が代入される. p = &a; 注意:実際は「番地」という 単位はつかない. p b a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 6 番地 53 D-19 *演算子 • アドレスの間接参照演算子. アドレス(ポインタ)に • アドレスの中身にアクセスする. * を付けると, そのアドレスの中身を char a, b; char *p; 意味する. a = 53; pは「6番地」. p = &a; *pは「6番地の中身」 すなわち53 b = *p; p b a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 6 53 番地 53 D-20 *演算子 char a; char *p; aが5番地に, pが4番地に 割り当てられたとする. p a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 D-21 *演算子 char a; char *p; p = &a; p &a で, aのアドレスを獲得. &a は"5番地"である. pに"5番地"が 格納される. (メモリの4番地に "5番地"が格納される) a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 D-22 *演算子 char a; char *p; p = &a; a = 8; p aに8を代入. aは5番地なので, メモリの5番地に 8が格納される. a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-23 *演算子 char a; char *p; p = &a; a = 8; printf("%d", *p); pは5番地. *pは「5番地の中身」. 5番地には, "8"が格納されているので, 8が表示される. 実行結果 8 実質,a と *p は同一. p a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-24 *演算子 char a; char *p; aが5番地に, pが4番地に 割り当てられたとする. p a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 D-25 *演算子 char a; char *p; p = &a; p &a で, aのアドレスを獲得. &a は"5番地"である. pに"5番地"が 格納される. (メモリの4番地に "5番地"が格納される) a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 D-26 *演算子 char a; char *p; p = &a; *p = 8; pは5番地. *pは「5番地の中身. 「5番地の中身」を "8"にする. 結果,aが"8"になる. p a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-27 *演算子 aを表示する. 当然,"8"が 表示される. char a; char *p; p = &a; *p = 8; printf("%d", a); 実質,「aへの代入」と 「*pへの代入」は 同一である. 実行結果 8 p a aへの値の代入は 行っていないが, aの値が変わる. 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-28 *演算子 char a; char *p; p = &a; a = 7; p aに"7"を代入. すなわち, メモリの5番地に "7"を格納. a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 7 D-29 *演算子 char a; char *p; p = &a; a = 7; *p = 8; p pは「5番地」 *p=8 は, 「メモリ5番地を8にする」 aの値が変わってしまった. a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-30 *演算子 char a; char *p; p = &a; a = 7; *p = 8; printf("%d", a); aの値を表示する. 当然,"8"が表示される. 実行結果 8 p a 0番地 1番地 2番地 3番地 4番地 5番地 6番地 7番地 8番地 9番地 5 番地 8 D-31 アドレス型変数(ポインタ変数) • アドレスを格納する変数 – 整数を格納できる変数があるように, アドレスを格納する変数がある. char int char int ch; i; *p0; *p1; /* /* /* /* 整数や文字コードの入れ物 */ 整数の入れ物 */ char型変数のアドレスの入れ物 */ int型変数のアドレスの入れ物 */ D-32 アドレス型変数(ポインタ変数) char a; /* a は char型 */ char *b; /* b は アドレス型 */ char c, *d, e, *f; /* cは char型,d はアドレス型, eは char型,f はアドレス型 */ char *g, h; /* g はアドレス型, hはchar型 */ 不慣れなうちは,この様な記述は避けるのが無難? D-33 配列とアドレス(ポインタ) • 配列の場合,アドレスは連続している. – char ch[10]が100番地~109番地に割り振られ た例. ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 D-34 配列とアドレス(ポインタ) void main(){ char abc[5]; printf("アドレスは%p %p\n%p %p %pです.\n", &(abc[0]), &(abc[1]), &(abc[2]), &(abc[3]), &(abc[4])); } 実行結果 アドレスは0013FF78 0013FF79 0013FF7A 0013FF7B 0013FF7Cです. D-35 配列とアドレス(ポインタ) void main(){ int abc[5]; printf("アドレスは%p %p\n%p %p %pです.\n", &(abc[0]), &(abc[1]), &(abc[2]), &(abc[3]), &(abc[4])); } 実行結果 アドレスは0013FF6C 0013FF70 0013FF74 0013FF78 0013FF7Cです. D-36 配列とアドレス(ポインタ) • 配列の場合,アドレスは連続している. – int &( &( &( i[3]が100番地~111番地に割り振られた例 i[0] ) は,100番地 (この例では) int型は i[1] ) は,104番地 4バイトである. i[2] ) は,108番地 i[0] 100 番地 101 番地 102 番地 i[1] 103 番地 104 番地 105 番地 106 番地 i[2] 107 番地 108 番地 109 番地 110 番地 111 番地 D-37 配列とアドレス(ポインタ) char ch[12]; char *p; p = &(ch[0]); printf("%p\n", p); p = ch; printf("%p\n", p); 実行結果 0013FF74 0013FF74 添え字を付けずに ([0]などを付けずに) 配列名だけを書くと, 配列の先頭のアドレス を意味する. この場合,ch と &(ch[0]) は同義. D-38 ポインタ演算 char ch[10]; char *p; p = ch; printf("%p\n", p); p++; printf("%p\n", p); 実行結果 0013FF74 0013FF75 D-39 配列とアドレス(ポインタ) char ch[10]; char *p; p = ch; pには, ch[10]の先頭アドレスである 100番地が代入される. ch[10]が100番地~109番地に割り当てられたとする. ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 D-40 配列とアドレス(ポインタ) char ch[10]; char *p; p = ch; pが100番地なので, 「100番地の内容」を *p = 1; "1"にする. つまり,ch[0]が "1"になる. ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 1 D-41 配列とアドレス(ポインタ) char ch[10]; char *p; p = ch; pの値は「100番地」だった. *p = 1; pが1増えて, 「101番地」になる. p++; ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 1 D-42 配列とアドレス(ポインタ) char ch[10]; char *p; p = ch; pの値は「101番地」. 101番地の中身が *p = 1; "2"になる. すなわちch[1]が p++; "2"になる. *p = 2; ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 1 2 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 D-43 配列とアドレス(ポインタ) char ch[10]; char *p; p = ch; pはch[0]を指している. *p = 1; p++; pはch[1]を指している. *p = 2; ch[0] ch[1] ch[2] ch[3] ch[4] ch[5] ch[6] ch[7] ch[8] ch[9] 100 番地 101 番地 1 2 102 番地 103 番地 104 番地 105 番地 106 番地 107 番地 108 番地 109 番地 D-44 ポインタ演算 int i[10]; int *p; p = i; printf("%p\n", p); p++; printf("%p\n", p); i[0] 84 番地 85 番地 86 番地 実行結果 0013FF74 0013FF78 差が4 i[1] 87 番地 88 番地 89 番地 90 番地 i[2] 91 番地 92 番地 93 番地 94 番地 95 番地 D-45 ポインタ演算 • int型変数のアドレスに1足すと, 4バイト分増加して,次のintのアドレスになる. – 減算も同様. • char型変数のアドレスを1足すと, 1バイト分増加して,次のcharのアドレスになる. – ただし, int型が4バイトとは限らない. 処理系による.ほとんどの例で4バイト. char型は必ず1バイト. D-46 ポインタ演算 p++を行うと, char *p; の場合,アドレスが1番地進む. int *p; の場合,アドレスが4番地進む. double *p の場合,アドレスが8番地進む. (ただし,int型が4バイト,double型が8バイトの 場合) D-47 ポインタ演算 • 以下の様な操作が可能. – アドレスに整数を加算/減算して,次の/前のアドレス に格納されているデータにアクセス. – アドレス同士の引き算をし,何個離れているか調べる • 以下の様な操作は行えない. – アドレスに乗算/除算を行う. – アドレス同士の加算. D-48 ポインタ演算 (OK) char *p, *q; int i; の場合, p++; p--; p=q+2; p=q-2; OK. OK. OK. OK. pのアドレスが1番地増える. pのアドレスが1番地減る. pはqの2番地後. pはqの2番地前. i=p-q; OK. iにはpとqの差が代入される. D-49 ポインタ演算 (NG) char *p, *q, *r; の場合, p=q+r; p=q*2; p=q/2; p=q+1.2; NG.アドレス同士の加算はNG. NG.アドレスに乗算と除算はNG. NG.アドレスに乗算と除算はNG. NG.加算減算は整数のみ. D-50 *演算子 と [] int *p, x[10]; p = x; のとき p と &(x[0]) と x は同義. p+1 と &(x[1]) と x+1 は同義. p+2 と &(x[2]) と x+2 は同義. D-51 *演算子 と [] int *p, x[10]; p = x; のとき *p と x[0] と *x は同義. *(p+1) と x[1] と *(x+1) は同義. *(p+2) と x[2] と *(x+2) は同義. D-52 注意 int *p, x[10]; p = x; のとき p++; x++; ←これはOK. ←これはNG. x という変数があるわけではない. x は &(x[0]) という定数. よって,読めるが書けない. D-53 関数の仮引数と実引数(値渡し) void func(int a){ a = 7; } x void main(){ int x = 3; func(x); printf("%d\n", x); } 100 番地 3 D-54 関数の仮引数と実引数(値渡し) void func(int a){ a = 7; } x void main(){ int x = 3; func(x); printf("%d\n", x); } 100 番地 3 D-55 関数の仮引数と実引数(値渡し) void func(int a){ a = 7; } void main(){ int x = 3; func(x); printf("%d\n", x); } x a 100 番地 104 番地 3 3 別のメモリに割り当てられた 別の変数 D-56 関数の仮引数と実引数(値渡し) void func(int a){ a = 7; } void main(){ int x = 3; func(x); printf("%d\n", x); } x a 100 番地 104 番地 3 7 別のメモリに割り当てられた 別の変数 D-57 関数の仮引数と実引数(値渡し) void func(int a){ a = 7; } x void main(){ int x = 3; func(x); printf("%d\n", x); } 実行結果 3 100 番地 3 D-58 関数の仮引数と実引数(値渡し) void func(int x){ x = 7; } void main(){ int x = 3; func(x); printf("%d\n", x); } 実行結果 3 この2個を 同じ名前にしても 結果は変わらない. x x 100 番地 104 番地 3 3 別のメモリに割り当てられた 別の変数 D-59 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } x px 100 番地 104 番地 3 D-60 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } x px 100 番地 104 番地 3 100 番地 D-61 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } x px 100 番地 104 番地 3 100 番地 D-62 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } x px p 100 番地 104 番地 108 番地 3 100 100 番地 番地 D-63 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } x px p 100 番地 104 番地 108 番地 7 100 100 番地 番地 D-64 関数の仮引数と実引数(参照渡し) void func(int *p){ *p = 7; } void main(){ int x = 3; int *px; px = &x; func(px); printf("%d\n", x); } 実行結果 7 x px 100 番地 104 番地 7 100 番地 D-65 void main(){ 練習0 int i, *j, k; i = 3; j = &i; k = i; *j = 4; k = 5; printf("i=%d\n", i); } D-66 void main(){ 練習1 int i[2], *j; i[0]=3; i[1]=7; j=i; j++; printf("%d\n", *j); } D-67 void main(){ 練習2 int i[2], *j; i[0]=3; i[1]=7; j=i; (*j)++; printf("%d\n", *j); } D-68 やってはいけないこと void main(){ int i=0, j[2]; j[0] = 7; j[1] = 8; /* OK! */ j[2] = 9; /* NG! */ printf("%d\n", i); } 実行結果 9 j[0] 84 番地 85 番地 86 番地 7 j[1] 87 番地 88 番地 89 番地 90 番地 8 i 91 番地 92 番地 93 番地 94 番地 95 番地 9 D-69 やってはいけないこと void main(){ int i[2], *p; p = i; /* OK. pはi[0]のアドレス */ *p = 7; /* OK. i[0] が 7 になる */ p++; /* OK. pはi[1]のアドレス */ *p = 8; /* OK. i[1] が 8 になる */ p++; /* NG.pはi[2]のアドレス? */ *p = 9; /* NG! i[2]相当の場所に 書き込みをしてしまう! */ } D-70 ポインタへのポインタ int i, *p, **pp; iは int(整数)を入れる箱. pは 「intの箱のアドレス」を入れる箱. ppは「『アドレスを入れる箱』のアドレス」を入れる箱. i 84 番地 85 番地 p 86 番地 87 番地 88 番地 89 番地 pp 90 番地 91 番地 92 番地 93 番地 94 番地 95 番地 D-71 ポインタへのポインタ int i, *p, **pp; i = 3; i 84 番地 85 番地 p 86 番地 87 番地 88 番地 89 番地 pp 90 番地 91 番地 92 番地 93 番地 94 番地 95 番地 3 D-72 ポインタへのポインタ int i, *p, **pp; i = 3; p = &i; i 84 番地 85 番地 p 86 番地 3 87 番地 88 番地 89 番地 pp 90 番地 91 番地 92 番地 93 番地 94 番地 95 番地 84番地 D-73 ポインタへのポインタ int i, *p, **pp; i = 3; p = &i; pp = &p; i 84 番地 85 番地 p 86 番地 3 87 番地 88 番地 89 番地 pp 90 番地 84番地 91 番地 92 番地 93 番地 94 番地 95 番地 88番地 D-74 ポインタへのポインタ int i, *p, **pp; i = 3; p = &i; pp = &p; printf("%d\n", **pp); i 84 番地 85 番地 p 86 番地 3 実行結果 3 87 番地 88 番地 89 番地 pp 90 番地 84番地 91 番地 92 番地 93 番地 94 番地 95 番地 88番地 D-75 ポインタへのポインタ int i, *p, **pp; i = 3; p = &i; pp = &p; printf("%d\n", **pp); i 84 番地 85 番地 *(*pp) は *(84番地) なので, 「84番地の中身」となり "3"を意味する. p 86 番地 3 *pは「88番地の中身」 なので, 「84番地」を意味する. 87 番地 88 番地 89 番地 pp 90 番地 84番地 91 番地 92 番地 93 番地 94 番地 95 番地 88番地 D-76 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; *pc = n*n*n; squareが100番地, } cubeが104番地で void main(){ あったとする. int square, cube; sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } D-77 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; *pc = n*n*n; 引数を 3,100番地,104番地 } として,関数にジャンプ. void main(){ int square, cube; sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } squareが100番地,cubeが104番地であったとする. D-78 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; nが3, *pc = n*n*n; psが100番地, pcが104番地として } 関数sq_cuを開始. void main(){ int square, cube; sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } squareが100番地,cubeが104番地であったとする. D-79 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; psは"100番地". 「100番地の中身を *pc = n*n*n; 3*3にする」 } という処理. これにより void main(){ squareの値が int square, cube; 変わる. sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } squareが100番地,cubeが104番地であったとする. D-80 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; pqは"104番地". 「104番地の中身を *pc = n*n*n; 3*3*3にする」 } という処理. これにより void main(){ cubeの値が int square, cube; 変わる. sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } squareが100番地,cubeが104番地であったとする. D-81 応用例:値を2個返す関数 C言語では,戻り値は1個しか用意できない. void sq_cu(int n, int *ps, int *pc){ *ps = n*n; 実行結果 *pc = n*n*n; 9 27 } void main(){ int square, cube; sq_cu(3, &square, &cube); printf("%d %d\n", square, cube); } squareが100番地,cubeが104番地であったとする. D-82 多次元配列の配置 • int a[3][2]は, 「長さ2の配列」が3本であって, 「長さ3の配列」が2本ではない? int a[3][2]は以下の順で割り当てられる. a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1] D-83 復習 i void main(){ int i=10, j=11; 104番地 int *p; の中身 p=&j; printf("*p=%d\n",*p); *p=7; printf("i=%d j=%d",i,j); } 104番地 の中身 j p 100 104 108 番地 番地 番地 10 11 10 11 10 11 104 10 11 104 10 7 104 10 7 104 *p=11 実行結果 i=10 j=7 D-84 練習 3 void main(){ int x=10, y=11, z=12; int *p; printf("x=%d y=%d z=%d\n",x,y,z); p=&x; *p=5; printf("x=%d y=%d z=%d\n",x,y,z); p=&y; *p=6; printf("x=%d y=%d z=%d\n",x,y,z); p=&z; *p=7; printf("x=%d y=%d z=%d\n",x,y,z); } 何と表示される? D-85 解答 3 x=10 y=11 z=12 x=5 y=11 z=12 x=5 y=6 z=12 x=5 y=6 z=7 D-86 練習 4 void main(){ 何と表示される? int x[3]; int *p; x[0]=10; x[1]=20; x[2]=30; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); p=x; /* p=&(x[0]) の意味 */ *p=7; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); p++; *p=6; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); p++; *p=5; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); } D-87 解答 4 x[0]=10 x[1]=20 x[2]=30 x[0]=7 x[1]=20 x[2]=30 x[0]=7 x[1]=6 x[2]=30 x[0]=7 x[1]=6 x[2]=5 D-88 練習 5 void main(){ 何と表示される? int x[3]; int *p; x[0]=10; x[1]=20; x[2]=30; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); p=x; /* p=&(x[0]) の意味 */ *p=7; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); (*p)++; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); *p=6; printf("x[0]=%d x[1]=%d x[2]=%d\n",x[0],x[1],x[2]); } D-89 解答 5 x[0]=10 x[1]=20 x[2]=30 x[0]=7 x[1]=20 x[2]=30 x[0]=8 x[1]=20 x[2]=30 x[0]=6 x[1]=20 x[2]=30 D-90
© Copyright 2025 ExpyDoc