ID非公開
ID非公開さん
2021/2/26 19:57
11回答
C言語なんかでよく「ポインタがわからない」といわれます。これって、どの辺がわからないのでしょうか。
C言語なんかでよく「ポインタがわからない」といわれます。これって、どの辺がわからないのでしょうか。 私は特に難しく感じないのですが、人に教える際に、わからない人はいったいどの辺がわからないのかという類型をいろいろ知っておけば、わかりやすく教えられそうだと考えました。 なので、今現在本当に混乱している人というよりも、最初はよくわからなかったけど、何らかのブレイクスルーによって今ではすっかり分かるようになって、以前の自分を振り返って分析できている人の回答が助かります。
多くの方にご協力いただきありがとうございます。 ここまで挙げられたものをまとめてみると、概ね次の3点になるかと思います。 (1) ソースコード上の「*」の意味は、実は文脈に応じて複数の異なる意味になるのに、単一の意味によって解釈しようとして混乱する。 (2) 変数の値が、整数値のアドレスで指定されるメモリ上に、型に応じたバイト数で記憶されるという、アーキテクチャについての知識がない。 (3) 変数とは異なる、ポインタならではの使い道を知らない。 私は8ビットパソコンの時代に触り始めたので、特に(2)は思いもよりませんでした。ちょっと驚いたので、知っている学校で初年度の「プログラミング入門」に使われているC言語の教科書を見てみたら、なんと、確かにほとんど触れられていませんでした。ポインタのインクリメントの項で申し訳程度に脚注で「char は1バイト、int は4バイト、double は8バイト」と書いてあるだけでした。そもそも2進数や2の補数表現などについても言及無し。これならわかるわけないですね。 引き続き回答をお待ちしています。
ベストアンサー
趣味でc言語使っているものです。 コードべた張りになってしまいますが、c言語を勉強したてだった私がポインタで悩んだのは次のコードがなぜうまく実行できないかです。 これの理解に時間がかかりました。 #include <stdio.h> #define ROW 2 //行列の行数 #define COL 3 //行列の列数 /* 行列の内容を出力する関数 */ void print_matrix(int **mat){ for(int i = 0; i < ROW; i++){ for(int j = 0; j < COL; j++){ printf("%d\t",mat[i][j]); } printf("\n"); } } int main(void){ int mat[ROW][COL] = {{1,2,3},{4,5,6}}; print_matrix(mat); return 0; } /* 望んでいる実行結果: 1 2 3 4 5 6 */ 当時の私は1次元の配列を関数に渡すのは造作もないが、2次元以上になるとなぜか表記方法が煩雑になる。くらいにしか思ってませんでした。 仮に1次元配列ならば、 void print_array(int arr[]); でも void print_array(int *arr); でもいいのに、2次元配列を渡すとなると void print_matrix(int **mat); これではうまく実行できない。なぜか? という感じです。 (※print_arrayはintの1次元配列の要素を出力する関数とし、いずれの関数も動的でない配列を渡して呼び出すものとします。) ポインタが難しいのはその仕様が独特且つ初心者には複雑に感じるからだと思います。 糖衣構文によってポインタと配列はとても親和性があるように見えますが、それゆえ初めて学ぶときに多くの誤解を招きがちです。 また、宣言したポインタは何の型を指すポインタなのかを厳密に理解できないうちは扱うのは難しいです。 int *p[3]; //pをintへのポインタの配列(要素数:3)として宣言する。 int (*p)[3]; //pをintの配列(要素数:3)へのポインタとして宣言する。 int **p; //pをintへのポインタへのポインタとして宣言する。 以上の違いを丁寧に説明してくれている本やサイトはあまりない気がします。 さらにconstがからんでくるとどういう意味/動作になるかとか、malloc/freeの使い方、関数ポインタとは... というすぐに理解できないかもしれない仕様があります。 分かる人には一瞬なんでしょうが。 他の方が仰るようなメモリ空間や番地の概念もそうなのですが、基礎となる仕様が複雑だから初心者が躓くのではないかと考えます。
3人がナイス!しています
ID非公開
ID非公開さん
質問者
2021/2/28 19:06
> void print_matrix(int **mat); > これではうまく実行できない。なぜか? という感じです。 この期待を持ってしまうのが、私にはちょっとわかりませんでした。 int型の二次元配列は、特に細工をしなければ、すべてのint型データが一続きに並んだだけのものであって、「行ごとのint配列の先頭ポインタ」の配列になっているのではない、と考えるのが自然かと思いました。そうすると、二次元配列のポインタといえども、それをダブルポインタで表せるだろうという期待は出てこない気がします。うーん。どうでしょうか?
質問者からのお礼コメント
多くの人の事例を募った質問なので、回答をいただいたすべての方を「ベストアンサー」としたいところですが、システム上一つに絞れということなので、ご自身の入門時の事例を具体的に書いてくれた点からこの方をベストアンサーとさせていただきます。ここに回答いただいた皆さんにも入門者に教えるときなどに参考にしていただけるような、知恵を集める知恵袋にふさわしい質問と回答になったかと思います。ありがとうございました。
お礼日時:3/8 17:31