第7講 ポインタ
第3話 謎の解明
コード再掲
#include<stdio.h>
void f(); //関数f()のプロトタイプ宣言
int main() {
f(); //関数f()に仕事を命じている
return(0);
}
void f() {
int *b; //ポインタbの宣言
*b = 1; //箱*bに1を入れる
printf("*b =%d\n", *b); //箱*bの中身を表示
printf("b=%d\n", b); //箱*bの住所を表示
}
ところが、Ctrl+F5で実行してみると、
とエラーしてしまいます。
エディタがコードの問題なしのお済み付けを与えても、
実行するとエラーしてしまうことはよくあります。
今回もその例となります。
何が問題でしょうか。
エラー原因を探るために、
前回のコードを
#include<stdio.h>
void f(); //関数f()のプロトタイプ宣言
int main() {
f(); //関数f()に仕事を命じている
return(0);
}
void f() {
int a, *b; //変数aとポインタbの宣言
a = 1; //箱aに1を入れる
b = &a; //住所を収納する箱bに箱aの住所を代入
printf("b =%d\n", b); //住所を収納する箱の中身を表示
printf("b + 1 =%d\n", b + 1); //住所を収納する箱の中身を表示
}
と書き換えてみましょう。
実行画面は、
の不思議な結果になりました。
b + 1とbに1加えただけですから、
b + 1=1756713
であるはずなのに、
b + 1=1756716
となっています。
実は、記憶装置の一定容量のメモリを割り振るといいましたが、
変数の方によって割り振る容量は変わってきます。
int型の場合4バイトが割り振られます。
long long型なら8バイトです。
double型も同じ8バイトです。
(int型の箱aに割り振られたメモリは、
1756713から1756716です。
b = 1756712
だから、1756712から1756715のはずだとお思いになりますよね。
実はメモリの割り振りが1756713から1756716のとき、
メモリアドレス(メモリ番地)は1756712とするのがC言語の文法なのです。
割り振られたメモリの1つ前の番地をメモリのアドレスとするという定義になっているのです。)
int型は4バイトですので、
b + 1は4増加の1756716としてくれるようにC言語は出来ているのです。
ですから、もし8バイトであれば、
b + 1は8増加にしてくれるのです。
これはC言語のサービスなのです。
さて、
エラーの解消は
#include<stdio.h>
#include<stdlib.h> //malloc()が使えるようにインクルード
void f(); //関数f()のプロトタイプ宣言
int main() {
f(); //関数f()に仕事を命じている
return(0);
}
void f() {
int *b = (int *)malloc(sizeof(int)); //ポインタbの宣言と初期化
*b = 1; //箱*bに1を入れる
printf("*b =%d\n", *b); //箱*bの中身を表示
printf("b =%d\n", b); //箱*bの住所bを表示
}
でできます。
(int *)malloc(sizeof(int)); の部分はメモリサイズの定義と確保です。
sizeof(int)はintのサイズという意味で、4バイトです。
これによって、*bに4バイト分のメモリが確保されます。
void f() {
int a,*b; //変数aとポインタbの宣言
a = 1; //箱aに1を入れる
b = &a; //住所を収納する箱bに箱aの住所を代入
printf("a =%d\n", a); //箱aの中身を表示
printf("&a=%d\n", &a); //箱aの住所を表示
printf("b =%d\n",b); //住所を収納する箱の中身を表示
printf("*b =%d\n",*b); //住所を収納する箱の中身を表示
}
において=(int *)malloc(sizeof(int)); が必要でなかったのは、
b = &a; //住所を収納する箱bに箱aの住所を代入
という初期化(最初の代入)を通して、
*bのメモリサイズが4バイトであることがわかったからです。
というのはaのサイズが4バイトであったからです。
でもこちらが例外でポインタを定義するときには、
int *b=(int *)malloc(sizeof(int)); //ポインタbの宣言と初期化
のように確保すべきメモリサイズをコンピュータに教えるのが正道です。
確保したメモリサイズが4バイトであるために、
#include<stdio.h>
#include<stdlib.h> //malloc()が使えるようにインクルード
void f(); //関数f()のプロトタイプ宣言
int main() {
f(); //関数f()に仕事を命じている
return(0);
}
void f() {
int *b = (int *)malloc(sizeof(int)); //ポインタbの宣言と初期化
*b = 1; //箱*bに1を入れる
printf("*b =%d\n", *b); //箱*bの中身を表示
printf("b =%d\n", b); //箱*bの住所bを表示
printf("b+1=%d\n", b+1); //箱*bの次の住所b+1表示
}
とすると、
となります。確保すべき容量が4バイトであることがわかったからです。
さて、皆さんコードを
#include<stdio.h>
#include<stdlib.h> //malloc()が使えるようにインクルード
void f(); //関数f()のプロトタイプ宣言
void g(); //関数g()のプロトタイプ宣言
int main() {
f(); //関数f()に仕事を命じている
g(); //関数g()に仕事を命じている
return(0);
}
void f() {
int a[10],i; //配列と制御変数の定義
for (i = 0; i < 10; i++)a[i]=i+1; //データ作成
for (i = 0; i < 10; i++)printf("%d ", a[i]); //データ表示
printf("\n"); //改行
}
void g() {
int *a=(int *)malloc(sizeof(int)*10), i; //配列と制御変数の定義
for (i = 0; i < 10; i++)a[i] = i + 1; //データ作成
for (i = 0; i < 10; i++)printf("%d ", a[i]); //データ表示
printf("\n"); //改行
}
と変更して実行するとどうなると思いますか。