C言語のポインタ(やJS等の値型と参照型の違い)はエクセルで説明すると簡単に分かる説
初めに
C言語のポインタはよくギターのFコードのように初心者の挫折ポイントとして語られることがあります。でもこれは説明の仕方に問題があるのではと思っています。
よくある説明にアドレスは家の住所でポインタは住所の番地です!ってのがありますがこれが分かりにくいと思います。あと最近は変数はラベルです!という説明が増えてるらしいけどそれも分かりにくいと思います。なのでこの記事ではエクセルで説明すると簡単に分かる説を提唱したいと思います。
C言語だけじゃなくC#やJavascriptなどの値型と参照型の違いも同じようにエクセルで説明すると分かりやすいと思います。
プログラミング初心者の方や初心者に教える機会のある方はぜひ見て頂ければと思います。
YouTubeにこの記事と同じ解説動画出しました。(ちょっと内容違うけど)
文章より動画が良い人はこちらをどうぞ
YouTube動画
ポインタ解説
さっそく解説していきます。
エクセルを使ったことがある人は分かると思いますが、エクセルではセルに直接値を入れることもあればセルの値を参照することもあります。
例えばセルB2に12という値を入れます。
そして次にセルC2に=B2と入れます。この=B2はセルB2を参照するという意味ですね。
ポインタもこれとほぼ同じです。
セルの位置を表すB2やC2をアドレス、セルの値を変数の値とみることが出来ます。
以下はポインタ変数C2を宣言して変数B2のアドレスを入れ、C2の参照先の値を表示するプログラムです。
int B2 = 12;
int *C2 = &B2;
printf("%d", *C2); // 12
どうでしょう?先ほどのエクセルの内容と見比べるとやってることは同じなのが分かると思います。
ではエクセルのセルB2の値を30に変えてみます。するとB2を参照しているC2の表示も変わりました。
同じことをC言語でやってみます。
int B2 = 12;
int *C2 = &B2;
printf("%d", *C2); // 12
B2 = 30;
printf("%d", *C2); // 30
ポインタは参照してるだけなので参照先の値が変わると*C2の値も変わるのが分かります。
配列のポインタ
次に配列のポインタを説明します。
エクセルのセル一つを変数一つとして考えると以下のようなセルB2からD2を要素数3の配列と考えることが出来ます。
この配列の宣言をC言語で以下のように書けます
int x[3] = {10, 21, 32};
printf("%d %d, %d", x[0], x[1], x[2]); // 10, 21, 32
配列の先頭アドレスを取得するときの書き方は以下の二種類あり、どちらの書き方でもOKです。
int x[3] = {10, 21, 32};
int* p1 = x;
int* p2 = &x[0];
これをエクセルで表すと以下のようになります。配列の先頭要素を指してるのでセルB4の値は=B2となっていますね。
そして変数p1のアドレスを一つずらすと配列の次の要素を指すことが出来ます。
int x[3] = {10, 21, 32};
int* p1 = x;
p1++;
printf("%d", *p1); // 21
なので以下のようなループ処理で配列の全要素を走査できます。
int x[3] = {10, 21, 32};
int* p1 = x;
for(int i = 0; i < 3; i++) {
printf("%d ", *p1);
p1++;
}
10 21 32
おまけ(const変数なのに書き換えれる!?)
おまけでたまにネタになるJavascriptとかでconst変数なのに値書き換えれる!!について説明します。(C言語は無理です)
C言語だと以下のようなコードはエラーが起きます
const int x[2] = {1, 2};
x[0] = 99; // エラー: const変数の値を変更しようとしている
でもJavascriptで以下のようなコードを書くとxはconst変数なのに配列の要素書き換えれてしまいます。(オブジェクトの中身も同じように書き換えれる)
const x = [1, 2, 3];
x[1] = 99;
console.log(x); // [1, 99, 3]
const x = {a:1, b:2};
x.a = 99;
console.log(x); // { a: 99, b: 2 }
ちなみに値型のconst変数は書き換えようとすると普通にエラーが起きます
const x = 1;
x = 99; // エラー
console.log(x);
なぜ書き換えれるかはこれもエクセルで考えると分かりやすいです。
変数x(セルB4)には配列の先頭アドレス(B2)が入っています。
constは変数xにだけ効きます。なのでx[1](セルC2)にはconstはついてないことになり書き換え可能となります。
なので変数xに別の配列を入れようとするとこれはエラーになります。
const x = [1, 2, 3];
x[1] = 99;
x = [3, 4, 5]; // エラー
console.log(x);
ちなみにChatGPTに聞くと以下のように回答してくれました。端的に説明されてて分かりやすいと思います。
JavaScriptとC言語では const キーワードの意味が異なります。
JavaScriptでは const は変数の再代入を禁止しますが、
オブジェクトや配列の内容(プロパティや要素)の変更は許可されています。
つまり、const で宣言された配列に新しい要素を代入することは可能です。
一方で、C言語では const は変数の内容が変更不可であることを意味します。
const で宣言された配列の要素は、変更することができません。
いかがだったでしょうか
C言語のポインタは難しいと言われがちですけど要は参照してるだけなので一回理解すれば大したことないと思います。
Discussion