メモリとポインタ
プログラムの前提 コンピュータは、0と1で計算をし、 0と1でデータを保存している。 メモリを学ぶのに必要な知識である。
メモリを学ぶ前に 2進数について学ぶ 箱が一つあり、箱の中には0か1が入る。 箱一つで数をいくつ表現できるか 解 0、1
メモリを学ぶ前に では、箱2つでは、数をいくつ表現できる か 解 00 ( 0 ) 01 ( 1 ) 10 ( 2 ) 11 ( 3 ) つまり箱一つで4つの数を表現できる。 ()内は10進数
メモリの考え方 イメージとして メモリは箱が並んだ長い一列のロッカーの 構造 箱1つを1ビットとして考えられる。 (0か1だから) 0 or 1 ・・・・・・
1ビットと1バイト 1 ビット・・・0 or 1・・・2の1乗 1バイト・・・8ビット・・・2の8乗 つまり、箱が8個集まったものを 1バイトとしている。
int 型での宣言とは int 型は4バイト使う つまり32ビット使っている 計32個 上の箱を使って数を表現している 例えば int a = 450; と宣言すれば、 メモリ上では ( )
ポインタへの導入 メモリは1バイトごとに番号がついている この番号のことをアドレスと呼ぶ。 0001番 0002番 0003番0004番
アドレスの確認 プログラムは下の通り 番号を調べるには %p を使う。 #include int main(void) { int i; printf(“%p\n”,&i); return 0; } 結果は16進数で表示される
複数のアドレスを調べると #include int main(void) { int i1,i2,i3; printf("i1(%p)\n",&i1); printf("i2(%p)\n",&i2); printf("i3(%p)\n",&i3); return 0; } 結果は各自で 結果は一桁目が4つず つ ずれているはず これは変数の宣言に int 型 ( 4バイト)を 用いたから
配列とアドレス #include int main(void) { int array[10]; printf("array(%p)\n",array); printf("array[0](%p)\n",&array[0]); printf("array[1](%p)\n",&array[1]); printf("array[2](%p)\n",&array[2]); return 0; } array(0012FF5C) array[0](0012FF5C) array[1](0012FF60) array[2](0012FF64) 配列を使う場合 array に & を使う 必要がない
ポインタ ポインタとは ポインタ型、ポインタ値、ポインタ変数の 総称 するアドレスを扱うもの
ポインタ型について 特徴 int 型や double 型といった型と合体すること で ポインタ型は扱える。 (例) int *a; ポインタ型はアドレスを記憶する変数の型
ポインタ値とポインタ変数 ポインタ型とは 変数のアドレス値 ポインタ変数 ポインタ型で宣言された実際の変数 この変数には、その元となった型の変数の アドレスを自由に代入できる
ポインタ変数の宣言とアドレス代 入 int main(void){ int *p; //int 型のポインタ型の宣言 int i; p = &i; // アドレスの代入 return 0; }
ポインタ変数のモードの話 通常変数モード int 型と同じように値を扱える (例) *p = 10; ポインタ型変数モード アドレスを扱う (例) p = &i; //i のアドレスを p に格納する
ポインタ変数のモードの話 #include int main(void){ int *p,i; p = &i;//p はアドレスを格納する *p = 10; //*p は値を格納する printf(“*p=%d\n”,*p); printf(“i = %d\n”,i); return 0; }
ポインタ変数のモードの話 #include int main(void){ int *p,i; p = &i; *p = 10; printf(“*p=%d\n”,*p); printf(“i = %d\n”,i); return 0; } *p は、通常変数モード に切り替わった変数p 結果 *p=10; i = 10;
今日の演習 今回はサイト:演習問題一覧をお借りしま す。 t/c_sub/index_en.html
メモリとポインタ( 2 回目)
復習問題 a = 10 を表示せよ。(ただし a = 10; としない) int main(void){ int a; int *p; // ここにかく // ここにかく (最高 2 行だと思われる) printf(“a = %d\n”,a); return 0; }
ポインタ型の引数 自作関数の引数にポインタ型を使用する 今までは int value(int a){ 処理 ; }
ポインタ型の引数 #include void func(int *pvalue); int main(void) { int value = 10; printf("&value = %p\n",&value); func(&value); printf("value = %d\n",value); return 0; } void func(int *pvalue) { printf("pvalue = %p\n",pvalue); *pvalue = 100; return; }
自作関数を実行する前 アドレス 0018FF5C 値 10 変数名 value
自作関数を実行した後 アドレス 0018FF5C 値 100 変数名 value 関数で行われていること 1.自作関数に value のアドレスを渡す 2.アドレスの値に 100 を代入する
ポインタと配列の話 自作関数の引数に配列を用いる #include int getaverage(int data[10]); int main(void) { int average,array[10] = {15,78,98,15,98,85,17,35,42,15}; average = getaverage(array); printf(“%d\n”,average); return 0; } int getaverage(int data[10]) { int i,average = 0; for (i = 0;i < 10;i++) { average += data[i]; } return average / 10; } // 結果 49
関数に配列を用いても問題ないようにみえ る しかし、配列の要素数が変わると問題が発 生する。
要素数が 5 の場合 #include int getaverage(int data[10]); int main(void) { int average,array[5] = {15,98,98,17,42}; average = getaverage(array); printf(“%d\n”,average); return 0; } int getaverage(int data[10]) { int i,average = 0; for (i = 0;i < 10;i++) { average += data[i]; } return average / 10; } // 結果 おかしいことに
配列の引数は配列の要素数は無視されている。実際、 int getaverage(int data[]); としても問題ない。 実は配列を関数渡すというのは アドレスを関数に渡しているのと同じである int getaverage(int data[10]); int getaverage(int *data); // アドレスの先頭番地を渡 す 上の二つは同じように扱える。
問. おかしい点を探せ #include int getaverage(int *data); int main(void) { int average,array[10] = {15,78,98,15,98,85,17,35,42,15}; average = getaverage(array); printf("%d\n",average); return 0; } int getaverage(int *data) { int i,average = 0; for (i = 0;i < 10;i++) { average += data[i]; return average / 10; }
[] は配列の要素を選択するという意味もある が data[i] は data というアドレスと i を足している という意味でもある。
参考文献 苦しんで覚える C 言語 アカバス