メモリとポインタ プログラムの前提 コンピュータは、0と1で計算をし、 0と1

メモリとポインタ
プログラムの前提
コンピュータは、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