メモリとポインタ プログラムの前提 コンピュータは、0と1で計算をし、 0と1でデータを保存している。 メモリを学ぶのに必要な知識である。 メモリを学ぶ前に 2進数について学ぶ 箱が一つあり、箱の中には0か1が入る。 箱一つで数をいくつ表現できるか 解 0、1 メモリを学ぶ前に では、箱2つでは、数をいくつ表現できるか 解 00(0) 01(1) 10(2) 11(3) つまり箱一つで4つの数を表現できる。 ()内は10進数 メモリの考え方 イメージとして メモリは箱が並んだ長い一列のロッカーの構造 0 0 0 or or or 1 1 1 ・・・ 箱1つを1ビットとして考えられる。 (0か1だから) 1ビットと1バイト 1ビット・・・0or1・・・2の1乗 1バイト・・・8ビット・・・2の8乗 つまり、箱が8個集まったものを 1バイトとしている。 int型での宣言とは int型は4バイト使う つまり32ビット使っている 計32個 上の箱を使って数を表現している 例えば int a = 450;と宣言すれば、 メモリ上では (00000000000000000000000111000010) ポインタへの導入 メモリは1バイトごとに番号がついている 0001番 0002番 0003番 0004番 この番号のことをアドレスと呼ぶ。 アドレスの確認 プログラムは下の通り 番号を調べるには%pを使う。 #include <stdio.h> int main(void) { int i; printf(“%p\n”,&i); return 0; } 結果は16進数で表示される 複数のアドレスを調べると #include <stdio.h> 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 <stdio.h> 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<stdio.h> 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<stdio.h> 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; 今日の演習 今回はサイト:演習問題一覧をお借りします。 http://www9.plala.or.jp/sgwrt/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 <stdio.h> 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 <stdio.h> 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 <stdio.h> 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 <stdio.h> 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言語 http://9cguide.appspot.com/15-07.html アカバス http://akabas.net/lib/CExercise.aspx?id=8
© Copyright 2024 ExpyDoc