質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

31回答

13121閲覧

C言語のポインタが難解とされる理由

yohhoy

総合スコア6191

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

5グッド

15クリップ

投稿2015/04/25 05:59

プログラミングC言語の学習者にとって、**ポインタ(pointer)**の理解は大きなハードルと言われています。
例えば「C言語 ポインタ」だけを専門に扱う入門書籍は、これまでにも大量に刊行されています。

C言語における「ポインタの難しさ」はどこから来ると思われますか?
(具象的な疑問解決ではなく、ご意見募集というニュアンスです。対象はC言語に限定します。)

以下は私の考える理由候補です:

  • ポインタ関連の文法の分かりにくさ(特に変数宣言)
  • ヌルポインタ(NULL)の意味
  • 動的メモリ管理(malloc/free)の難しさ
  • 配列とポインタの関係性
  • 関数ポインタ
drumath2237, kamitani, aaaaaaaa👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2019/08/17 11:57

投稿からかなりの時間が経過しています。 ベストアンサーなり自己解決として、質問をクローズしましょうd^^
guest

回答31

0

最も基本的なことですが
・ポインタとメモリアドレスの関係が高級言語(?)だけを扱っていると理解しにくい。
・・・アセンブラから入ると処理(関数)もデータも同じメモリに格納されているのだから当然アドレスが存在する・・・というのが判るのですが・・・
#学校でアセンブラ教えないのかなぁ

投稿2015/04/25 06:13

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TaroToyotomi

2015/06/03 22:31

皆さんの意見を見てみると、アドレスという概念を習得するのが理解への早道のようですね。 コンピュータは、プログラムやデータをどこかのアドレスに格納することで初めて扱うことが出来るようになって、変数宣言とはずばりアドレスを割り当てる操作に他ならないです。 ポインタ変数の宣言も同様にアドレスを入れるための変数を宣言しているということが理解できれば難しくはないのですけどね。
KenTerada

2015/06/26 12:12

僕も,計算機の挙動がわかっていれば,残るポインタの難しさは記述方法だけだと思います. C言語はより計算機の挙動に近いレベルで記述するので,学習にはぴったりだと思います. どこかで,コンパイルしたバイナリデータを見るツールを使って,プログラムがどのように動作しているのかを学べば良いと思います. 最近の高級言語は計算機の挙動を意識しないでもコーディングできるように作られているので,プログラムは書けるけど計算機がどう動いているのかはわからない,って人が多いんじゃないでしょうか.
cateye

2015/07/14 10:30

NOP10回が1ミリだから、100回廻せば10ミリウエイト入れられるとか・・・ 今時のCPUじゃキャシュのおかげで意味がありませんが、そんな事やるとすっごく怒られます^^; ・・・AVR大好きd^^
Tosshi

2019/06/04 00:23

他の言語を学んだことのある人からしたら、概念的に理解できないことが多いと思います。 自分は大学の講義でC言語から、プログラミング学習を始めた者です。ポインタから授業について行けなくなった、挫折した人、嫌いになった人が圧倒的に多いです。 ポインタまでの学習内容は、なんとなく出来てしまう事が多い様ですが、アドレスといわれてもピンとこない人が多いみたい。 今まで感覚的に出来ていたのに、しっかりと理解出来てないと動かなくなるため挫折する人、難しいと思う人が多いと思います。
guest

0

個人的な考えですが、利便性と利用目的がわからないのではないでしょうか。初心者がプログラムをする際にあまり関数やクラスを使用しないために、どのような場合に使いどういった利便性があるという認識がないため理解できず、さらにそこにハードウェア的なメモリの番地が〜といった話が入ることで、必要ないもの+知らない言葉で理解するのを放棄していると思います。

投稿2015/04/28 07:55

Neight

総合スコア127

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AmaiSaeta

2015/04/28 14:01

「利便性と利用目的がわからない」というこの意見に賛成です。 各種アルゴリズムやデータ構造の実現にポインタは必要不可欠ですが、それらについて知らないとポインタは何に使えるか理解するのが難しい。 この、「Aの為にはBが必要」「Bの為にはAが必要」という「堂々巡り」の関係が、理解の妨げとなってしまうのでしょう。
guest

0

ここまでの回答と重複する点も多いかと思いますが、
ご質問(の題)の要因を箇条書きで整理してみます。

・C言語が比較的シンプルでプログラミング初学者向きだから、
難しいと発言する人の数自体が多い(だから需要が多く書籍も多い)。

・ポインタ自体より、ポインタを使ったメモリ管理全体や
アルゴリズムが難しいのだが、ポインタが難しさの象徴になっている。

・機械は難しい。機械語は難しい。機械語ほどではないけどアセンブラも難しい。
そしてCは、中水準言語とか高級アセンブラと称されるように機械寄りの言語で、
機械(のメモリ)と接する部分のポインタが、ほかの高級言語であまり出てこないから。

・ポインタが難しいというより、ポインタ関連、メモリ関連のバグの原因特定が難しい。
Cの開発環境のレガシーさもあって、ポインタが難しいというよりデバッグが苦しい。

・既知の学習モデルでないから。変数は数学の変数の応用だから、すんなり理解できる。
四則演算や論理演算もつまづかない。それらがやさしいというより、数学で習うから。
しかしポインタは学校で習わず、Cではじめて習うから、つまずきやすい。

・イメージしにくいから。IF文やFor文などのフローチャート的な制御構造は、
一般的な作業の手順と同じだから、すんなりイメージできる。
ポインタも番地のたとえはともかく、ポインタのポインタとか、
関数ポインタとか、発展的なものはすんなりイメージできない。

このように複合的な要因があると思います。

投稿2015/07/16 20:43

LLman

総合スコア5592

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

広く言えば、多分、単純にアドレス指し示し先という解釈以上に、凝った処理の事例が多いからでは。
※ことの本質レベルが分かってないと、その処理系が読み取れない。ポインタのポインタとか、関数へのポインタとか…

狭く言えば、教科書レベル(狭義の変数レベル)でポインタを見ていると、右辺値、左辺値も一緒くたに扱うので、右辺値、左辺値を意識しないことから発生するのではと思います。

投稿2015/04/25 11:12

S.Toyoda

総合スコア116

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/04/27 03:27

左/右辺値とポインタの関連に飛躍があるようで分からなかったのですが、&演算子オペランドの話でしょうか?
S.Toyoda

2015/04/27 06:14

厳密にいえば、C言語においては、左辺値はアドレスに紐付けられたオブジェクト(といういい方も微妙ですが)、すなわちいわゆる変数か純粋なポインタ(デリファレンスされた参照)となります。ところが、右辺値はまぁ、それこそおおよそどのようなものも取り扱えるます。そこで、本来左辺値にあわせて、右辺値を構成すべきところを、右辺値にあわせて左辺値を構成しているような例が多いです。なぜ変数を利用するのか、なぜポインタを利用するのかが、右辺値に重きを置かれているってことですね。 もっと端的な使い方でいえば、 char array[512]; char array2[512]; strcpy(array2, array); と char array[512]; char *ptr; ptr = &(array[0]); を「同じこと」と説明しているものも少なくありません。 これ、明らかにおかしいでしょ? strcopyなんで、厳密に右辺値、左辺値の話題じゃないですが、代入を参照先の置き換えとしている例は、結構あります…
yohhoy

2015/04/27 13:54

(コメント頂いておいて何ですが、前半部分で仰りたい趣旨が分かりませんでした。) 後半の配列/ポインタの混同理解は確かによく見かけますね。
guest

0

  • 計算機の仕組みを理解しないまま入門するケースがある

ノイマン型の基本的な仕組みをほとんど理解していないプログラマーがいきなりポインターをやるのは無謀かも知れません。
私も計算機科学を体系的に学んだわけではないのですが、機械語を少しやっていたおかげで理解不能のレベルではありませんでしたね。

  • 文法が直感的でない

未だに慣れません。
メインがC言語ではないので、久しぶりにやってみるとたまに混乱します。

  • ポインターの応用、データ構造の実装

ポインターを何のために使うのかという点で、データ構造について学んでいない人はここでつまずく気がします。
ポインター自体とは別の話だとは思いますが、ポインターの難解さと一緒くたにされることも多いのではないでしょうか。

投稿2015/04/26 07:33

argius

総合スコア9394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/04/27 03:49

ノイマン型コンピューターであることとポインタの理解には、さほど関連性を見いだせないのですがどういうニュアンスでしょうか? 3点目のデータ構造+アルゴリズムとの結びつきは、たしかに影響がつよそうです。
argius

2015/04/27 04:31

ノイマン型のところは、何て書くか悩んだところです。 現在の一般的なコンピューターのCPUがどのようにプログラムを実行していくかが分からないと、ポインターのイメージが抽象的すぎて掴めない、というケースが経験上多かった気がします。 ...ということを書きたかったのですが、上手くまとめられませんでした。
pi-chan

2015/10/23 12:53

表現が最適かどうかは別として、命令やデータの「メモリ上での位置」(=つまりポインタ)を意識する必要のあるのはノイマン型(=プログラム内蔵型)の最も顕著な特徴なので、適切な回答だと思います。例えばニューラルネットワーク型のコンピュータにはポインタおよび変数という概念自体がありません。
argius

2015/10/23 13:07

pi-chanさん コメントありがとうございます。 回答当時の私がそこまで考えて書いたのかは多分に怪しいところですが、然程におかしなことは言ってなかったんですね。
guest

0

私はポインタの理解で苦労した記憶がほとんどありません。これは「初心者のころによいお手本に出会えたから」というのが、最大の理由だと思います。
新人教育でC言語を初めて勉強した時当然ポインタも出てきましたが、解っていたつもりになっていただけでした。業務で先輩方のプログラムを読んで初めて、「どういう時にどのように使えばよいか」が解るようになりました。(感謝感謝です)
その後の業務を通じて他の人が書いたプログラムを読む機会も多くありましたが、ポインタの乱用・誤用も多々あります。初心者のころにこういうプログラムに出会ってしまっていたら、私も「ポインタは解らない」という一人になっていたかもしれません。

(ポインタに限った事ではありませんが)「プログラミングの勉強」=「覚えること」だと思っている人もいますね。
if やループ程度ならパターンを覚えるだけでも対応できるのかもしれませんが、ポインタの扱いは「覚えきれない」ものでしょう。

・ポインタ関連の文法の分かりにくさ(特に変数宣言)
確かにそうです。しばらくC言語から遠ざかっていて戻ってきた時、一番忘れていたのはポインタ周りの記述方法でした。

投稿2015/06/26 08:46

mie

総合スコア229

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

私の場合は『コンパイル時になされる』と、『実行時に計算される』の区別を認識できていなかった事も理解が妨げられる理由でした。
(これが理解できるまでsizeof()と各種の型のポインタに+1した時の値の実験を繰り返した)。

投稿2015/04/27 15:18

kppn

総合スコア44

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/04/29 02:26

ポインタの加減算はたしかに理解の落とし穴ですね。「sizeof()と各種の型のポインタに+1した時の値の実験」は、私自身もやったことを思い出しました(笑)
guest

0

1.「ポインタが分からない」と言う人のレベルが様々だから
「動的メモリ管理(malloc/free)の難しさ」については、「効率的な」と言う枕詞を入れるだけで永遠の課題とも言えるものになってしまいます。そんなものに効率的な解があるなら、メモリリークやバッファオーバフローは起きません。

2.周りが難しい難しいと言いすぎるから
人間の心理として、難しいと言ってる連中が多い物をムリに理解しようと言う気にはなれないのかもしれません。ポインタの機能自体は理解出来ている人は多いはずです。ですが、1の理由により「その程度で理解したつもりになるな」と言う連中が少なからず出て来るので、まじめな人ほど、自分はまだ「ポインタが分かってない」と思うわけです。

3.アルゴリズム(およびデータ構造)が理解出来ていないことを「ポインタが分からない」と言っている。
ポインタを利用するアルゴリズム(およびデータ構造)は極めて多い(そして扱うことができるレベルも高くなる)わけですが、それを理解出来ていないのを「ポインタが分からない」と言っているわけです。「C言語 ポインタ」だけを専門に扱う入門書籍と呼ばれるものは、殆どこれらの解説に終始しています。本当に「C言語 ポインタ」だけを解説した専門書は見たことがありません。

投稿2015/05/30 17:32

編集2015/05/30 17:44
niconico

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/06/06 16:54

「2. 周りが難しい難しいと言いすぎるから」はあまり考えたことのない観点だったので興味深いです。たしかに、そういう負の心理バイアスはありそうな気もします。 「その程度で理解したつもりになるな」とかは、[奥が深い症候群](http://0xcc.net/misc/bad-knowhow.html)と自尊感情がダメな方向に組み合わさった結果かもしれません。
guest

0

変数の値が扱っているデータそのものではない、とか。
データそのものの参照のしかたに癖がある(ヌル文字とかメモリサイズを意識しないとメモリリークしたり)、とか。
確保しているメモリサイズをプロパティ的な所に持っていないので、確保したメモリサイズを意識しないといけない点もあります。

実データを処理するだけでも処理手順などを考えなければいけないのに、実データにアクセスするだけのために考えることがいくつもあるのって結構面倒くさいです。

とは言いつつ、メモリ管理をイメージできると色々な考え方ができて他の言語にも応用できるので苦労しますが勉強する価値はあると思います。

投稿2015/04/25 06:56

HachiyaKouya

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/04/27 13:59

「変数の値が扱っているデータそのものではない」=ポインタ変数の中身は"普通の意味での数値"ではない というのは、入門書でよくある変数="数値を入れる箱"と捉えるモデルでは理解しずらいかもしれませんね。
HachiyaKouya

2015/04/27 15:30

普通の変数に関しては「変数="数値を入れる箱"」で問題ないと思います。 ポインタ変数は「数値を入れる箱がどこにあるかを示す数値を入れる箱」などと言う表現になるので、そのモデルでは理解しづらいですね。 ただの箱一つをイメージすればよかったものが、ポインタが出てきた途端に幾つもある箱とその置き場所を管理する住所録とか集合住宅的なものを意識しないといけなくなるので同じ物で例えようとするとイメージしづらいかもしれないな、と思います。
guest

0

この問題の根本的な原因は、説明に携わる立場の人間
(教育者、出版関係者、書籍執筆者、中堅以上の技術者)
の多くが、一つの勘違いをしていることに起因していると思います。

つまり、


低レベル(ハードウェアに近い)な話は人間には難しく、
高レベル(高次概念に抽象化された)な話は人間に分かりやすい、
わかりやすく説明するためには、低レベルの話を避けて高レベルの概念で説明しなければならない


という誤解です。

アドレスとメモリ空間で説明すれば簡単に済む説明を
「そういうハードウェアに近い説明をするのは、説明者として芸が無いという事になり沽券にかかわる」
とでも思っているかのように無理やりアドレスとメモリ空間を使わずに説明しようとしているから、
わけがわからなくなるのです。
C言語の登場当初は、アセンブラの熟練者から「Cは難しい」という話を聞くことがありました。
「コンピュータの初心者にも分かり易い説明」を目指した結果、
コンピュータの熟練者で概念の本質が理解できている人間にさえ意味が通じなくなった説明で、
初心者が本当の理解を得られるわけがないのです。

同様の理由で本来以上に難しいとされてしまっている事柄には、

  • オブジェクト指向
  • JavaやPerlにおける参照

などがあると思います。

投稿2016/02/20 16:29

kozuchi

総合スコア1193

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2016/05/09 02:23

「アドレスとメモリ空間で説明すれば簡単に済む説明」、 「無理やりアドレスとメモリ空間を使わずに説明しようとしているから、 わけがわからなくなる」に共感します。
yumetodo

2016/08/06 15:45

まあC言語の規格書にはメモリーとはどこにも書いてない(はず)なのも一因でしょうね・・・。説明にはそれ持ち出すほうが絶対ラクなんですが
guest

0

こんにちは。
今更で申し訳ないのですが、興味深いテーマなので、意見を述べさせて下さい。

私自身はアセンブラから入ったので苦労は無かったのですが、娘が今、学校で苦労してます。
新しいことを教える際には、既に理解していることと照らしあわせて説明すると説明しやすいです。
そこで、娘にポインタの概念を教える際に、現実世界に照らしあわせてみようと思ったのですが、それができないのです。

C言語のポインタを無理やり現実世界に対応させようとすると、例えば「あのりんご」になると思います。
「りんご」が型で、「ある1つのりんご」が変数ですね。そして、「あのりんご」と指し示すことがポインタに当たると思います。

C言語のポインタは遠隔操作の達人で、ポインタが指す変数を自由に操作できます。中身を取出したり、インクリメントしたりなど。
しかし、「あのりんご」のままでは遠隔操作できないです。「あのりんご」を食べたいならそこまで行くか、「あのりんご」を手元に持ってくる必要があります。
つまり、現実の世界では変数(りんご)を直接操作することしかできず、ポインタで指し示した変数を操作することってできないです。

メモリやアドレスの概念が難しいことが最大の原因と思いますが、アナロジーを使えないことも理解しづらい原因の1つと考えてます。

【閑話休題】
ところで、高級言語だとポインタの概念を理解する必要が無いとよく聞きますが、これは誤りと思います。
JavaやC#はポインタの概念を排除し、「参照」と呼んでますが、実装はポインタです。
代入文でオブジェクトをコピーしたつもりが、実はポインタがコピーされているだけなので、実体は1つのままです。ある変数を修正したら、いつの間にか他の変数まで変わるってことが普通におきます。
以前C#でハマりました。分かっていてもデバッグは超たいへんです。全てのクラス・オブジェクトが参照なので、他と共有されている可能性があるのです。

ですので、JavaやC#でさえも、ポインタの概念を理解しないままだと、この落とし穴にハマったら最後、なかなか抜け出せないと思います。

投稿2015/10/23 04:37

編集2015/10/23 04:43
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/10/26 04:57

「アナロジーを使えない」というのは興味深い見方だと思いました。 ポインタの説明では、「変数は値を入れる箱だ/箱には番地が付いてる/ポインタ変数には番地を入れるのだ」という表現を良く見かけますが、ここでは何かに"例え"ているのではなく、ポインタという機能(の一部)を言い換えただけですね。ポインタ自体があまりにプリミティブな概念のため、より分かりやすいモノへの言い換え(≒アナロジー)が難しいということかもしれません。 ちなみに、個人的には後半のご意見にも賛同します。(参照渡しvs.値渡しの議論で良く紛糾するのであまり近づきたくない話題ですが:P)
Chironian

2015/10/26 09:13

>参照渡しvs.値渡しの議論で良く紛糾するのであまり近づきたくない話題ですが:P なるほど、意外なところに議論の種があるのですね。 ムーブも考慮して常に効率が最大になる方式を考えると嵌りそうですね。
guest

0

高級言語っぽく見えても、根本的にはアセンブラで書くことと変わらない考え方が必要なことが原因のように思います…

他のモダンな言語は、概ねそれぞれに意識しているプログラミング・パラダイムがありますよね。
プログラミング・パラダイムを意識するということは、なにかしら作りたい処理があって、それを表記し易くする為に言語側の機能にいろいろ手が尽くされています。
でもC言語は元々OSを効率良くメンテナンスする為に開発されたプロツールで、初心者は想定していないような作りです。また、アセンブラのコードを生成する為のツールですし、ほとんど最低限の機能しか与えられていません。(最悪アセンブラで書き足せばいい、って話もあります。)

ツールとして考えると、ひどくローレベルのものがむき出しで、下手に弄ればなにが起こるかわからない。「触るな危険」て札をぶら下げているようなものではないかと。(ライブラリの呼び出しでも一歩間違うと、初心者にはなんで止まったか分からない状態にハマります。)
学校の先生あたりからすると、アセンブラとセットで覚えて欲しい言語かもしれませんが、これをろくにプログラミングをしたことのない人がいきなり覚えろと言われたらやっぱり難行だろうなぁ、と思ってしまいます。

自分は、BASIC, アセンブラ, Cの順に覚えたので、特にポインタが理解不能ではありませんでしたが、ポインタを利用した様々な実装にはやっぱり閉口しました。
実装方法を見ただけだと実現される機能がほぼイメージできないものも結構あります。そういったものは、提供される機能の概念と実現するアプローチに対して(場合によっては記述様式に対しても)深い理解が不可欠になってきます。(最近の言語ってそういうことをスマートに解決していて、わりとイメージできるところに上手に落とし込んでいますが。)

ポインタ自体は、抽象的に捉えメモリなどを指し示すだけのもの…とシンプルに考えられれば、特に悩む問題ではないわけですけども。
C言語の自由度の高さ。縛りのなさ。記述様式の難解さ。というのは、初心者にとって言語に実現できる範囲を全くイメージできなくさせる原因になっていて、(どこまで分かれば分かったことになるのか…というジレンマも含めて)そういう事柄がネックになっているのではないかと。

というわけで…
最初に書いたことが原因かなぁ、と考えます。

その、イメージできなくさせる原因が具体的になにか、って聞いてるんだ。
…というツッコミもあるかと思いますが「数学が難しくて理解できない。」と思う人が何故いるのか、という問いと似たようなもので、どちらもある程度物事を抽象化して、順序よく組み立てるスキルの問題。ということかと思います。(アセンブラライクな処理の組み立てと考えると、実現度合いがローレベルすぎるのもかえって厄介ではないかと思います。)

投稿2015/07/18 16:10

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ポインタが難解だ、と言われるのは、ポインタ操作を重視する教育上の問題が大きいと思います。

yohhoyさん含め他の何人かの人が言うように、ポインタの加減算がわかりづらいです。
しかも実質上業務では必要ない。にも拘わらず、そこを気軽に教えることがおかしな気がします。
アドレスに対する演算と、それ以外を上手く区別できる人とできない人で、ポインタの難度が大きく変わっています。

「ポインタの値(アドレス)を変更してみる」ところを早い時期から学習に組み込むケースをよく見ます。
どんなにそれでコードがシンプルになろうが、(ポインタに格納された)アドレスの値を直接変更するを教えることは最初は避けるべきだと思います。そもそもプログラムを作る上でそれらの知識は必要無いはずです。

多くの場合、プログラマーはあるアドレスに対する書き込み/読み取り操作をしたいだけです。
yohhoyさんが上げた難解な理由にあたりそうなものも、ポインタとの関係はアドレスの取得・保存に限るものが殆どです。
ポインタを通じて変数や配列の値を書き換えることにだけ注力すれば、ポインタの問題はずっとシンプルになります。

Cでは配列で学ぶ(sizeof等を除く)殆どの操作がポインタに適用でき、またポインタの操作もその多くが配列に適用できますね。
この理由も、アドレスに対する書き込み/読み込みを軸に考えればシンプルに説明できます。

変数はメモリ上に確保されます。その確保された位置をアドレスと言いますよね。だから変数のアドレスは後から変更できません。配列も変数ですからそれは同じです。配列が普通の変数と違うのは、変数はアンパサンド(&)をつけることでアドレスを取得するのに対し、配列は名前を指定することで先頭要素のアドレスを取得することができることです。
これが、ポインタがアドレスを取得する時と同じ記述になるので人によっては混乱します。

lang

1int a[10]; 2int b*; 3b = a; // 簡単に代入できる 4//a++; // しかしこれはエラーになる、なぜか 5b++;

このことは、「取得したアドレスに対する操作なので同じことができる」と簡潔に説明できます。
ポインタのみインクリメントできる理由は、ポインタはアドレスを新たに書き込むことが可能だからと説明できます。

・変数/配列 アドレスについて読み取りのみ可能=アドレスは変更不可能
・ポインタ アドレスについて書き込み・読み取り双方が可能

ポインタの加減算と配列の添え字は方言みたいなものです。
そのため、私はポインタでも配列で使う添え字の方を重用した方が良いと思っています。
アドレスの開始位置の変化しない、配列の記法の方がずっと理解しやすいからです。

投稿2015/06/03 12:36

編集2015/06/03 12:48
haru666

総合スコア1593

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自分が始めてC言語を学んだときを思い返すと、ポインタ=アドレスという概念自体はすんなり受け入れられたような気がします。
しかし、構造体などと組み合わせたときにデータ構造同士の参照が複雑になってくると理解が及ばなくなった記憶がありますね。(例:木構造、キュー、リンクリスト等)

投稿2015/04/26 05:44

TaroToyotomi

総合スコア1430

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2015/04/26 06:19

たしかに双方向リンクなんかだと、途中への挿入や削除があると・・・・・××? ・・・・ってなりましたね
yohhoy

2015/04/27 13:52

たしかにポインタの解説とデータ構造の説明がセットになっていることは多いですね。実体験に基づく意見は参考になります。
guest

0

いきなり「メモリアドレス」というハードに寄った都合の話が出てくるからじゃないですかね

投稿2015/04/25 06:12

ozwk

総合スコア13551

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

考えることが多い

ポインタはどこを参照するか(ポインタ型変数の値そのもの)と参照先(間接参照演算子*で得られるもの)の2つが変更可能なので、cv-qualifierもその双方に対して修飾ができたりで、そこら辺が理解を妨げる要因かなと思います。それだけ思考が増えるので。C++の参照は参照先しか変更できず、どこを参照するかは変更できないので思考が節約できるかもしれません。

配列とポインタの兼ね合い

やむを得なかったとはいえ、配列が3つの例外を除きポインタに読み替えられるのはいろいろと理解を妨げているかな、と思います。コンテナとイテレーターと参照が合体しているようなもんですからね、後発言語的に考えれば。

ひどいのが、入門本における配列の説明ですね。「配列とポインタは密接な関係にある」と書くお馬鹿がいたり(全くの別物)、添字演算子[]も配列の機能とか大嘘書いている馬鹿がいたり(それはポインタ演算のsyntax sugerだ)。
初心者にとっては出会う本を間違えると一生ポインタが理解できません。Yahoo!知恵袋で回答者をしているのですが、ここが理解できない質問者がものすごく多い。(そもそも独習Cの説明が腐っている、苦しんで覚えるCはましな説明だけど)

セキュリティ

あとはポインタはなんでも出来てしまうので、少しでも設計や実装を誤るだけでバッファーオーバーランからくるメモリー破壊を起こしてしまいます。C標準関数もそのへんうまく扱えないというか、それどころかgetsみたいにどうやっても安全に使えない関数があったりしますし。(C11で_s付き関数が追加されてましになった)

文法の汚さ

c

1int* p1, p2;//p2はint型

あとコレや、HogeAnimalLoverさん指摘の

c

1int* p; 2int *p;//同じ

や関数ポインタ

c

1typedef int (*func_t)(int, double, const char*, size_t);//型名はfunc_t

に代表されるように文法が絶望的に汚い。

C99のrestrict、C11で配列の最低要素数を関数の引数に指定できるようになったことで少しずつマシになってきてはいますが、残念ながら、C99はともかく、C11に対応した入門書はないに等しい現状があり・・・

教育の問題

授業で教える側の人間の知識がヘタするとC言語標準化以前でストップしていたりするのが「ポインタ分かんない」の間接的な要因かなと。未だにbcc32 5.5.1使っている連中はいい加減滅びてください。

投稿2016/08/06 15:40

編集2016/08/06 15:49
yumetodo

総合スコア5852

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2016/08/08 06:42

概ね同意です。(専門化された教育機関でない場合は)授業としてC言語を教えること自体に無理があるような気はしますね… 1つ合意できないのは、C99のrestrictは改善ではなく、むしろC言語(コンパイラ)におけるポインタ関連の最適化処理(エイリアス解析)の技術的限界の露呈と、それをプログラマの責任として追加で押し付けただけですね…
yumetodo

2016/08/08 14:13

>プログラマの責任として追加で押し付けただけ うーん、まあそういう見方もあるか・・・。まあC言語らしいというか。
guest

0

先入観のせいってのもある気がします。
ポインタは難しいってやたら誇張されてる気がします。それによって、ポインタを学ぶときに身構えてしまうんじゃないかと思います。

投稿2016/08/06 15:05

administrator

総合スコア20

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/06/04 01:29

なんだかんだ言ってるけど,多分これだと思う. 単に,触れるよりも前に「難しい」という刷り込みが成されている. 個人的には「ポインタで行き詰る」的な謎の話はネット上にしか存在しない都市伝説の類だと思っています. だって,"現実世界では"そんな人に一度も会ったことがない. 専門外な学科の1年生にいきなりCをやらせる講義のTAを数年やったことがありますけど,わからなくなるのはポインタではない感じ.
guest

0

私もポインタ苦手でした。

ポインタの苦手理由のパターンを考えてみました。

パターン1:
使い道がわからない。

パターン2:
通常の変数とポインタの違いがわからない。

パターン3:
ポインタはアドレスっていうけれど...
データ入っているじゃん!?

パターン4:
動的確保

パターン5:
使わなくてもプログラミングできる。
( ただし、グローバル変数等のように、エラー原因になることもよくある。 )

といったところでしょうか。

なぜ、変数があるのにポインタを使うかっていうのがわかりにくい。
私の認識では、

■ データは取得したりした場合、メモリ上に配置される
■ ポインタはコインロッカーの鍵のようなもの
■ 変数の場合は、コインロッカーから荷物を取り出してカゴに入れた状態

っていう感じ。

これなら、すんなり理解できるが、
「ポインタはアドレスである」とか、実際のアドレスを見たりとか。
訳わからん。
となります。

投稿2016/05/18 05:10

BeatStar

総合スコア4962

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

個人的にはポインタを習った後に理解が曖昧なまま構造体へ進み, そのまま構造体のポインタがでてきて
p->x, p->yのような記述を学ぶことでワケがわからなくなるのだと思いますw

他にもポインタと構造体の比較で
int p[5] について単なるpが先頭のアドレスを指す
int q について q はアドレスの入れ物, 実態を使う時はq ポインタ自体にもアドレスがあって...

といったようにいろいろな表記を学ぶせいでワケがわからなくなるのでしょうね

投稿2016/04/22 16:14

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2016/08/08 06:32 編集

(回答頂いた方は既に退会されてしまっていますが)構造体とポインタが組み合わさるときの、-> 演算子 および . 演算子 と * 演算子の組 も混乱に拍車をかけていますね。
guest

0

メモリーとそこに格納されている値のイメージさえ掴めたらそれほど難しいとは思いません。
皆さんが仰ってるように、私もアセンブラからやり始めましたから、すんなりとイメージで来ます。
ただ、ポインターのポインターとかポインターの配列とか構造体のポインターとか関数へのポインター
とかって使い方をするので、それでイメージできなくなって、わからなくなるんじゃないでしょうか?
おそらくですが。

投稿2015/07/14 09:31

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

例えば、256バイトのデータエリアに、257バイト書き込みをして、プログラムエリアに割当てられていた1バイト破壊や、環境の要素はあるかと思いますが、奇数バイト参照による1バイト桁ずれなど、原因不明に陥りやすい不具合が出やすい点ではないかと思います。

ただデータエリアを、ポインタで参照する分には、高速参照が出来るため重宝します。
なので、ポインタは読み取りだけに使う様に心がけていますが、

C言語の教則本では、配列とポインタを同義語のように受け取ってしまいがちなため、メモリ割当していないポインタを配列代わりに使ってプログラムクラッシュを引き起こしてしまって、原因がよくわからない。

そういったところではないでしょうか。

投稿2015/06/04 07:42

KenjiObata

総合スコア440

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2015/06/06 16:59

「メモリ割当していないポインタを配列代わりに使ってプログラムクラッシュ」はC言語学習で誰しもがはまる落とし穴ですね。ポインタ関連のバグは、特にデバッグがしづらいというのも影響していそうです。
guest

0

なぜプログラミング言語が必要なのか考えたことがある方はあまりいないと思います。

コンピュータに置けるプログラムとは単なる数値のやりとりを行うだけのものです。
コンピュータの内部動作を知らずにいきなりプログラミングを行おうとすると必ずつまずきます。

特にC言語はコンピュータの数値操作が得意な言語なのでなおさらです。

ポインタとは何か。
ーーーーーーーーーー
◯×◯×◯◯◯◯◯◯
ーーーーーーーーーー
1 2 3 4 5 6 7 8 9 10

メモリには上記のように細かい仕分けに電圧がそれぞれかかっている状態です。
(◯は電圧かかかっている状態、×は電圧がかかっていない状態)

このそれぞれの仕分けにはそれぞれアドレス(番地)が割り振られています。
この仕分けを指し示すのがポインタです。
(Pointerには指針と言う意味があるみたいです。)
そしてポインタを操作するというのがこの仕分けの中の電圧を操作するために使われています。
例えば1番の電圧をなしにする場合は

char *pointer; // アドレスを入れる入れ物を用意
pointer = 1; // 実際にアドレスを入れる
*pointer = 0; // そのアドレスの電圧を0にする

このような操作をすることにより以下のような状態になります。

ーーーーーーーーーー
××◯×◯◯◯◯◯◯
ーーーーーーーーーー
1 2 3 4 5 6 7 8 9 10

たったこれだけのことです。

結論:ポインタは難しくない。

質問者様の質問の意図とは違ったものになったと思いますが、
ポインタに関しての苦手意識を払拭していただけると幸いです。

私の文章に関しまして、間違いなど発見されたらぜひご指摘いただきたいと思います。
乱文・長文失礼致しました。

投稿2015/05/30 03:54

priNNy12

総合スコア50

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2015/05/30 12:57

「なぜプログラミング言語が必要なのか?」という事なら、機械語→アセンブラ→FORTRANあたりの言語の歴史、ひいてはなぜ高級言語が開発されたのかを話す必要があると思います。また、C言語についてはOS(UNIX)を開発するための言語であったためメモリ操作のようなかなり低水準な処理をする必要があったためポインタの実装が必要だった(Cが高級アセンブラといわれる所以です)ことからはじめなくてはならないと思いますが?
yohhoy

2015/06/01 12:23

面白いご意見だと思いました。とはいえ、現実を見ると「たったこれだけのこと」がC言語学習者全員に理解されるわけではないようです(残念ながら)。そのあたりの認識がどこから来るのだろうというのが本質問の意図でした。("私が"ポインタ苦手という質問ではないので、そこを誤解されていたらゴメンなさい)
priNNy12

2015/06/01 13:14

>cateyeさん 回答ありがとうございます。 cateyeさんの言う通り私の書いた記事についての理解を得るためにはかなり昔に遡り、歴史を見なければならないかもしれません。 「なぜプログラミング言語は必要か」については言語壮大でしたが、ただ、ポインタ操作に関してなら単なるメモリの操作なのですから、もっと簡単に考えてよいと思うのです。((ここではコントロールレジスタなどのお話は無しでお願いします。)いやCでは扱えなかったですかね?) そしてできるのであれば、低水準の知識から高水準言語までをカバーし、なおかつ理解しやすい書籍が発売していただけることを願っているのですが……(私が知らないだけかもしれません。もし知っていたらそのような書籍を紹介していただきたいです。)
priNNy12

2015/06/01 13:27

>yohhoyさん 回答ありがとうございます。 本当に残念だと私も感じております。 私にとっては高校数学の方がよほど理解し難いと感じております。 しかし、学校での学問は長い歴史の間に磨かれたものであり、コンピューターの教育はまだまだ手探り感があるように感じられます。 ポインタは単純なものですから、もし理解し難いと感じられる方がいるのであれば、それは教育者もしくは手にした書籍があまり良くなかったのでは、というのが私の考えですね。 ポインタが理解し難いと思ってる方は多いでしょうから、逆にそれがなぜなのかを考えてみたら面白いかもしれません。
cateye

2015/06/01 13:28

誤解されたと誤解されたのならごめんなさいmm かなり前に、某メーカで新人SE(?)にC言語を教える機会があったのですが、やっぱりポインタがネックでしたね。箱or引き出しwでは関数ポインタは説明できない。結局メモリとアドレスの説明になってしまったような記憶があります。 アセンブラでジャンプテーブルでも作った事があれば一発なんだけどなぁ・・・
Fritha

2015/07/16 14:29

やはり 最低限CPUがどうやって命令を実行しているかという知識をわかりやすく解説する必要があるのではないでしょうか? データを格納するためのメモリーにはアドレス(番地)がついていてその番地を指定することで読み書きができること。 同じメモリーの上に実行するためのプログラムも配置されていること。 プログラムのどの番地の命令が実行されるかを管理しているプログラムカウンタ(PC)レジスタのこと。 jump(goto)という命令は実はそのプログラムカウンタに実行位置を書き込むことだということ。 こういうことが理解できればデータのポインタや関数のポインタの説明を理解できるための準備ができるのではないでしょうか
guest

0

アセンブラをやったことがない人は、ポインタを使うべき場面を想像できないので、なぜこんなものがあるのか...しかもわかりにくいし...となるのではないでしょうか。私は先にアセンブラをやってたので、すんなりわかりましたが。

投稿2015/04/25 08:14

chokojori

総合スコア973

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Fritha

2015/07/16 14:14

アセンブラやっててもアドレッシングモードと言われてピンと来ない人も多いですよね 意外と厄介だけど一度目からウロコが落ちると難しい物ではないんですけどねぇ
sage

2019/06/04 04:16

370 アセンブラだとaddressing modeは24と31の2種類です。用語の意味が全く異なります。
guest

0

候補に挙げられている点はどれもこれも「そういう言語仕様だから」と割り切って慣れれば大した事では無いと思います。

言語仕様に馴染んだ後でも難しいと感じる点としては、メモリー空間におけるCPUやコンパイラの都合をnearとかfarとかいった修飾子で導入されている場合の相互代入の互換性とかがあります。

投稿2017/01/19 16:08

....

総合スコア102

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

1.ポインタの仕組みが理解できない.
2.ポインタをどう使えば良いのかわからない.
3.コードにする方法が良くわからない

投稿2016/08/08 06:08

hegomusi

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

私が思うに、「アドレス」の概念から欠落していると感じます。
そして多くの場合、「アドレス」の必要な場面が思い浮かばないのでモチベーションが上がらないというのもあると思います。

そしてこの概念を導入している(意識しなくてはならない)言語の少なさも影響していると思います。
私は組み込みソフトからソフトの道に入った人間なので、アセンブラをまず覚えねばなりませんでした。しかしアセンブラを知っていると、C言語のポインタなどは拍子抜けするほど簡単です。
でもそのアセンブラはさらに習得困難な言語として知られています。

  • ポインタの難しさ

・「アドレス」とは何ぞや、をきちんと説明できる人が少ない
・ある程度ハードウェアの知識がある人が少ない(上記と併せて、教育が充実しない)
・取っつきにくさから苦手意識を「食わず嫌い」で持ってしまう人が多い
・構文にも意味があることを理解しにくい

まとめるとこんな感じでしょうか。ハード周りから触っているようなレガシーなソフト屋がベテランになってきており、新人教育に関わるほど時間が取れないというのも大きい気がします。

投稿2016/08/06 22:09

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ポインタが難しいと言われるのは宣言時と参照時で記号「*」の意味が違うからだと思う。

投稿2016/05/18 05:15

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2016/05/18 13:56

え、同じでは無いんですか? int *a; aの「示す先」がint型になる、aを宣言。 *a = *b; aの「示す先」にbの「示す先」を代入。 という感じになると思っていたのですが…。
HogeAnimalLover

2016/05/18 18:13

「int* a」(「int *a」)→「『変数aはint領域を指し示すポインタである』と宣言」, 「*a」→「『関節参照演算子(*)を変数a』に適用」 のように私は解釈しています。まあ、「示す先」と解釈するところは同じなのですが、前者は演算子ではありません。このため、「a」が有効なメモリ領域を指し示さないと「*a」に代入することができません。さらに言えば掛け算記号と同一であることもややこしい要因だと思います。 ついでに「int* a」と「int *a」が同一視されることも不自然です。変数一個ならば問題はないとしても「int* a,b」と「int *a, b」も同一ですあり、bの型がわかりづらいです。
rubato6809

2016/05/18 20:30

普通(処理中?)のコードの中の *a = b; は、a の示す先のメモリに b を代入しますが、 宣言時の int *a = b; で行われる代入は a = b であって、aの示す先には代入しない。 どちらも「*a = b」なのに、代入する先が違うじゃないか、と言われて私は宣言と処理中では文法が違うと納得しました。
guest

0

ポインタを理解しようとすると、まずアドレスについては理解がいると思います。
次にコーディングするとき、ポインタが分かりにくい直接の原因ではないですが、そもそも構文についてどういう解釈をしているかも関係しているのではと思います。

1.変数宣言を左から解釈する。 int a; /* intのa */
ポインタが分からない人には、宣言について右から解釈するようにと説明してました。
int a; aという名前の器があって、そこにはint型の値が入る
int a; aという名前の器があって、そこにはアドレス()の値が入る。更にそのアドレスにはint型の器がある。

2.インクリメントは1増。 a++; /* 1なら2 */
インクリメントは、aの中身を「型の1単位分増」。
宣言が int a; int(整数)なので、0なら1。
宣言が int *a; *(ポインタ)なので、次のアドレス。元のアドレスにはint分のサイズが必要なので、intが4バイトの場合、0なら4。
更に、a+=2; は2単位分増やす。

あとは配列を理解して、ポインタのポインタ、構造体のポインタ、関数ポインタとか少し練習すれば、だいたい大丈夫な気がします。

投稿2015/06/07 16:13

tetsuyakuniyuki

総合スコア24

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

どなたかの回答にもありますが、C言語のポインタを完全に理解し、人に教えられるまでの
知識を得るにはアセンブラ・アーキテクチャーの理解なくして達成されません。

また、言語の歴史的な背景でいつのまにか許されてしまっている表現なども多く、
組み込み用コンパイラではポインタの概念がアーキテクチャーに依存するため、
「この本を読めば」という本は存在しません。

投稿2015/06/07 08:30

DeepDiveIntoSea

総合スコア33

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

変数に値が1つしか入らないて概念から、
変数アドレス、メモリーアドレスが出てきて、
2つ値をもってるて概念に急に変わるからじゃないですか?

なので、アドレスを指してるのか、中身の値を指してるのか
*の使い方で指してるものが変わるので、何を指してるのかが解れば難解でもなんでもないですね。
ポインタはただの矢印ですよ。

投稿2015/06/04 08:01

MasaakiIrie

総合スコア1021

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ポインタは別に難しいとは思いませんが、使い方を間違えると実行時エラーの原因になります。普通の変数と違って中の値によって不具合の状況が変化したりするので、解析を難しくする側面があるように感じます。

投稿2015/06/02 11:50

kiyoami

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問