C ポインタ (宣言と単項演算子) を初心者に説明するにはどうすればよいでしょうか? 質問する

C ポインタ (宣言と単項演算子) を初心者に説明するにはどうすればよいでしょうか? 質問する

最近、C プログラミングの初心者にポインターを説明する機会があり、次のような難しさに遭遇しました。ポインターの使い方をすでに知っている場合は、まったく問題には思えないかもしれませんが、次の例を冷静に考えてみてください。

int foo = 1;
int *bar = &foo;
printf("%p\n", (void *)&foo);
printf("%i\n", *bar);

まったくの初心者にとって、この出力は驚くべきものかもしれません。2 行目で *bar を &foo として宣言したばかりですが、4 行目で *bar は実際には &foo ではなく foo であることがわかります。

混乱の原因は、* 記号の曖昧さにあると言えるでしょう。2 行目では、* 記号はポインターを宣言するために使用されています。4 行目では、* 記号はポインターが指す値を取得する単項演算子として使用されています。これらは 2 つの異なるものですよね?

しかし、この「説明」は初心者にはまったく役に立ちません。微妙な矛盾を指摘することで新しい概念を紹介しているだけです。これは正しい教え方とは言えません。

それで、カーニハンとリッチーはそれをどう説明したのでしょうか?

単項演算子 * は間接演算子または逆参照演算子です。ポインターに適用すると、ポインターが指すオブジェクトにアクセスします。[…]

ポインタ ip の宣言はint *ipニーモニックとして意図されており、式が*ipint であることを示します。変数の宣言の構文は、変数が出現する可能性のある式の構文を模倣する。

int *ip*ipは、「が を返す」と読むべきでしょうかint? しかし、なぜ宣言後の割り当てはそのパターンに従わないのでしょうか? 初心者が変数を初期化したい場合はどうなりますか? int *ip = 1(読み方:*ipが を返しint、 はintです1) は期待どおりに動作しません。概念モデルが首尾一貫していないようです。何か見落としているのでしょうか?


編集:それは試みた答えをここにまとめます

ベストアンサー1

速記の理由:

int *bar = &foo;

あなたの例で混乱を招く可能性があるのは、これを次のものと同等であると誤解しやすいことです:

int *bar;
*bar = &foo;    // error: use of uninitialized pointer bar!

それが実は手段:

int *bar;
bar = &foo;

変数の宣言と割り当てを分離して次のように記述すると、混乱が生じる可能性はなくなり、K&R の引用で説明されている使用 ↔ 宣言の並列処理は完璧に機能します。

  • 最初の行は、であるbarような変数 を宣言します。*barint

  • 2 行目は、 のアドレスfooを に割り当てbar*bar( ) を( int) のエイリアスにします。fooint

C ポインタ構文を初心者に紹介する場合、最初はポインタ宣言と代入を分離するこのスタイルに固執し、C でのポインタ使用の基本概念が十分に理解された後にのみ、結合された省略構文を(混乱を招く可能性があるという適切な警告を付けて)紹介すると役立つ場合があります。

おすすめ記事