- ベストアンサー
C言語のポインタとコンパイルエラーの解消法
- C言語のポインタを意識せずに使用するとコンパイルエラーが発生することがあります。
- ポインタを正しく扱うためには、変数の宣言やメモリの割り当てに注意する必要があります。
- typedefを使用することでポインタの扱いを簡潔にすることができ、エラーを回避することができます。
- みんなの回答 (12)
- 専門家の回答
質問者が選んだベストアンサー
「スキっとした答え」と「そうでない答え」というのはどこで線を引けばいいでしょうか>#7. 「言語仕様」というのはある意味「スキっとした答え」と言えそうですが.... ということで #7 の疑問に対する説明: まず「宣言」の基本形は type-specifier declarator, declarator, ...; です. で type-specifier (型指定子) は基本型/void/構造体・共用体/列挙型/typedef名のいずれか. declarator は間接参照の「*」や配列を指定する「[]」や関数を表す「()」などなどを含みます. つまり int は型指定子だけど int * は (型だけど) 型指定子ではありません. 「int *」は字面の空白の有無とは無関係に (つまり「int*」だろうと「int *」だろうと) ・型指定子である int ・宣言子の一部である * と分けて考えなければなりません. その結果, int* p, q; は ・型指定子 int ・2つの宣言子 *p, q と分解できて ・p は int へのポインタ ・q は int と解釈されます. 余談ですが宣言の文脈で「*」や「,」を「演算子」と思っちゃダメです. 「*」は宣言子の一部だし, 「,」は宣言子と宣言子の区切りです. 関数を呼び出すときに printf("%d\n", *q); の「,」を「演算子」とは思わないよね. それと同じこと. ちなみに「p と q の両方をポインタにしたい」というときに int *p, *q; とした方が int *p, q; とするよりも混乱は少ないと思います. つまり int *p; とだけあったときに*何かの事情で* int の変数 q を追加するときに, 思わず int *p, q; ってやりたくなりませんか?
その他の回答 (11)
- KAZUMI2003
- ベストアンサー率37% (77/208)
おやおや、私の発言でお気を悪くされた方がいらっしゃったのなら、申し訳ありません。 私自身、はっきりと判っていなかったので、まさしく#8様のような解説を期待しておりました。 よく理解できた気がします。 ありがとうございました。
- Tacosan
- ベストアンサー率23% (3656/15482)
「typedef でなぜいけるのか」の話: typedef名は「typedef がなければその型である」ような型です. つまり, typedef int *ptr_int; の場合 typedef を消して int *ptr_int; なら ptr_int は int * 型なのでptr_int という typedef名は int * と同じものを表します. なお, 「typedef の書式」は「typedef 既存の型 別名」ではありません. typedef名が (新たな, 別の型ではなく) 既存の型の別名として扱われるのはその通りですが, 複雑な型を考えると「typedef 既存の型 別名」ではうまくいきません. 例えば「int を要素とする大きさ 5 の配列」という型を typedef int IntArray[5]; と作ることができるのですが, これは明らかに「typedef 既存の型 別名」のような形式にはなっていません.
- jjk65536
- ベストアンサー率59% (66/111)
typedef int* ptr_int; ptr_int p, q; と int *p, q; では意味が違います。 typedefは新しい「型」を定義します。 この場合はintポインタ型ですね。 前者はintポインタ型としてpとqを宣言しています。 一方でint *p,q;はあくまでもint型です。 修飾子として*がついているpだけが ポインタとして解釈され、qは純粋なint型 として解釈されます。 > typedefすることでなぜエラーを回避することができるのでしょうか? typedefのそういった仕様により、エラーが発生しなくなったと言えます。
- a_kwn
- ベストアンサー率34% (8/23)
文法的にはA No.8の方の説明が正確なんですけど…誰が説明したってスッキリはしないんじゃないかな。 そういうルールだってことで、納得してもらえないですかね? もちろん <int *> という型はありますよ。でも、 int *a; という宣言が、<int *> までが型名で a が変数名という『型名 変数名;』って認識に当てはめたいのでしょうが実際のCのコンパイラの構文解析はそういう風にはとらえないんですよ。 例えば、 int a, *b; とか、 int *c, **d; という宣言がなされたら、どう解釈すればよいのでしょう。 もちろん、正解は <a : int型> <b : int *型> <c : int *型> <d : int **型> なんですが、あなたの最初の認識だと、d なんて <int *> の ** になって訳分からないでしょ。 でも、<int *> 型はありますし、typedef してちゃんとその型で定義できますよ。 (あなたが質問で指摘されているように int* 型を int_ptr と typedef して、 ptr_int p, q; と宣言する方法は、全く正しいやり方です。)
- KAZUMI2003
- ベストアンサー率37% (77/208)
回答者諸氏もスキっとした答えが出せないでいるようですね。気になっていた質問で、回答ではないですが、ちょっと思ったことを書いてみます。 今質問のキモは、 int *p,q; は、何故、 (int *)型のpとq、と解釈されないのか?と言うことですよね? 宣言時の構文解釈が、 変数の名前はpであり、それは(*が付いてるので)ポインタであり、その指し示しているのは、intである。 変数の名前はqであり、(*が付いていないので)直接の変数でその型は、intである。 となっているのですね。 考えづらいですが、int *というのは、型として解釈されていない、と言うことですよね。 演算子の優先順位的には、*の方が,より優先順位が高いから、とも思えますが、変数宣言の文脈でこれを演算子として考えていいのか?ちょっと断言できません。 より詳しい説明は、どなたか詳しい人が現れるのを期待しています。、 typedefすると、完全にint *がptr_intという型として解釈されるので、構文上双方に効くのは、当然なんでしょうね。
- asuncion
- ベストアンサー率33% (2127/6289)
>int *p, q; 邪道かもしれませんが、 *pはint型(よって、pはintへのポインター) qはint型 って読んでみると、今回の間違いの原因に気づきやすくなるかもしれません。
- kmee
- ベストアンサー率55% (1857/3366)
int a,b ;→ int a; int b; int *c,d ;→ int *c; int d ; int_ptr e, f ; → int_ptr e; int_ptr f ;→ int *e ; int * f ; この例でわかるといいのですが。
- asuncion
- ベストアンサー率33% (2127/6289)
>typedefすることでなぜエラーを回避することができるのでしょうか? それは、「intへのポインター」という型にptr_intという別名を付けているからです。
- KEIS050162
- ベストアンサー率47% (890/1879)
int型、char型、float型などは、変数の形そのものですが、 ポインターとはその名のごとく、指し示すものということです。 なので、intのポインター、charのポインター、floatのポインターなどがあります。 intのポインターというのは、intの変数が入っている場所を指し示すもの、と考えれば良いですね。 意識せずポインターを使っておられるとのことですが、今のうちにポインターをしっかり復習されておいた方が良いですね。 積極的にポインターを使うと、コーディングの幅がぐっと広がります。 http://www9.plala.or.jp/sgwr-t/c/sec10.html ご参考に。
- KEIS050162
- ベストアンサー率47% (890/1879)
単純な記述のミスと思えるのですが、 int *p, q; を int *p, *q; として試してみてください。 int *p, q; のままだと、 p はintのポインター型、q はint型 として定義されてしまいます。 ご参考に。
補足
int *型というものがあるというわけではなくint型でポインタが定義できるということでしょうか?
- 1
- 2
お礼
int* q,p;の解釈は理解できましたが,なぜtypedefはとおるのでしょうか? typedefの書式はtypedef 既存の型 別名だった気がするのですが・・・ そうだったらint*は型として扱われますよね?