• ベストアンサー

ポインタの宣言

ポインタを宣言するとメモリ上に、ポインタ変数を格納するための領域が確保されます。ポインタ=アドレスというのは大丈夫なのですが、 int *b のようにどうして、ポインタに型があるのでしょうか?単に変数のアドレスを表示するだけならば型はいらないと思うのですが。 またこのとき宣言された変数は *b ではなくて b であってますよね?

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.12

>初心者の自分にはハードルの高い内容ですね。 ハードルが高いとは思いませんが、むしろ初心者だからこそ、 そういった決まりを知っておく必要があると私は思います。 >>sizeof(char *)とsizeof(int *)とが同じであることと、 >>sizeof(char)とsizeof(int)とが異なることとを これをしようとしているのでしょうが、 No7さんの意図した所としては、 >>char a, *b; >>int c, *d; >>printf("%d",sizeof(a)); >>printf("%d",sizeof(b)); >>printf("%d",sizeof(c)); >>printf("%d",sizeof(d)); ということですよ? >>sizeof(char *型)とsizeof(int *型)とが同じであることと、 >>sizeof(char型)とsizeof(int型)とが異なることとを と読み替えるべきです。 >>どうして、ポインタに型があるのでしょうか? >まず大前提はこの質問です。 No2でも触れましたが、C言語では 型はその型分類によって特徴付けられ、 型によって表現範囲が異なり、 何byteでそれを表すかが処理系によって定義されます。 処理系は通常これを「型情報」として管理する為、 ポインタにも参照する為の、内訳をするための、 一種の方法として、型が存在しているものと思われます。 > これはデータが複数の番地にまたがって存在しているし、 > charとintでそれぞれサイズがことなるからですよね? そうです。 その内容を取り出すためには、 ポインタを参照する際に表現するのに使う、 実際のサイズが分からないと、 アドレスから値を取り出す場合に、 アドレス上から何バイトを取り出せば良いか 分からないということが一概にあります。 蛇足ですが。。。 例えば 1byte = 8bit の処理系で, 32ビット環境の番地に入っているビットを見ると。。。 aの番地を 10000 、paの番地を30000 とすると、 char a = 1; 10000 : 0000 0001 char *pa = &a 30000 : 0001 0000 30001 : 0010 0111 30002 : 0000 0000 30003 : 0000 0000 a = 10; 10000 : 0000 1010 *pa = 255; 30000 - 30003 ↓ 0000 0000 0000 0000 0010 0111 0001 0000 (BE) ↓ 10000 から型情報により 1byte ↓ 10000 : 1111 1111 bの番地を 20000 , pbの番地を40000 とすると、 int b = 1; 20000 : 0000 0001 20001 : 0000 0000 20002 : 0000 0000 20003 : 0000 0000 int *pb = &b; 40000 : 0010 0000 40001 : 0100 1110 40002 : 0000 0000 40003 : 0000 0000 b = 256; 20000 : 0000 0000 20001 : 0000 0001 20002 : 0000 0000 20003 : 0000 0000 *pb = 65535; 40000 - 40003 ↓ 0000 0000 0000 0000 0100 1110 0010 0000(BE) ↓ 20000 から型情報により 4byte ↓ 20000 : 1111 1111 20001 : 1111 1111 20002 : 0000 0000 20003 : 0000 0000 ってイメージでしょうか。 #あくまでも処理系によっては異なるのですが。。。 型情報で多くあるミスは、配列型のサイズです。 文字列などの配列をC言語上で言うと char型配列などになりますが、 関数などにこれを渡すときに暗黙の変換が行われ、 型情報が失われsizeofを使用しても渡した元の配列の サイズを取得することができなくなります。 #include <stdio.h> int sub( char [] ); int main( void ) {  char str[] = "hogehoge";  printf( "%d\n", sizeof(str)); // strの型情報は char[9]  sub( str ); // 暗黙の変換により型情報が失われて渡される  return 0; } int sub( char str[] ) {  printf( "%d\n", sizeof(str)); // strの型情報は ポインタ  printf( "%d\n", sizeof(*str)); // *strの型情報は char になる }

szatmari
質問者

お礼

丁寧な回答ありがとうございます。皆様の指摘でだいぶ理解が深まりました。

その他の回答 (11)

  • Wr5
  • ベストアンサー率53% (2173/4061)
回答No.11

>printf("%d",sizeof(a)); >printf("%d",sizeof(*b)); >printf("%d",sizeof(c)); >printf("%d",sizeof(*d)); >でためしたらそれぞれ4411でintとcharのサイズが同じになりました。どこが間違えでしょうか? 1番目のsizeofはint型のサイズを、 2番目のsizeofはint型へのポインタが「指し示す先」(=int型)のサイズを、 3番目のsizeofはchar型のサイズを、 4番目のsizeofはchar型へのポインタが「指し示す先」(=char型)のサイズを それぞれ返しています。 ポインタ変数を使用するときに変数名の前に*を付けると、指し示す先の内容ということになります。 ポインタ変数自体のサイズが欲しい場合は、*は付けません。

szatmari
質問者

お礼

回答ありがとうございます。知りませんでした。

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.10

>どうして、ポインタに型があるのでしょうか? >単に変数のアドレスを表示するだけならば型はいらないと思うのですが。 ポインタが指すアドレスからデータを出したり、データを入れたりする場合や、ポインタを動かす場合に、データサイズが判らないと困ります。 例えば、ポインタが1254番地を指している場合「ポインタが指す1254番地からデータを取り出して」と言われた場合、そこにあるデータが「charのデータ」なのか「intのデータ」なのか判らないと、取り出せません。 また、ポインタが1254番地を指している時「1つ進めて」と、ポインタに1を足した場合、アドレスを幾つ進めれば良いか判りません。 なので「ポインタにも型が必要」なのです。

szatmari
質問者

お礼

回答ありがとうございます。 「ポインタが指す1254番地からデータを取り出して」と言われた場合、そこにあるデータが「charのデータ」なのか「intのデータ」なのか判らないと、取り出せません。 (初歩的なことですが)これはデータが複数の番地にまたがって存在しているし、charとintでそれぞれサイズがことなるからですよね?

回答No.9

>No6さん 私のコンパイラではワーニングになりました。 例えが悪かったみたいですね、その点はすみませんでした。 しかし質問への回答として、本質的な部分で間違えているとは思いません。 勿論実行する上で支障はないでしょうが、型について語る時に3.14(float)と3(int型)が同じ扱いで良いわけがありません。 >No.7さん >どうして、ポインタに型があるのでしょうか? まず大前提はこの質問です。 >ではdoubleやcharの型の場合だとintと何が異なるのでしょうか? >メモリ上で確保する領域のサイズは同じはずですよね? だとすれば、doubleやcharは暗黙的にcouble*やchar*と解釈できると思うのですが。 No.7さんが仰るとおり、double*もchar*もint*も確保するサイズは同じはずです。

szatmari
質問者

お礼

回答ありがとうございます。 double*もchar*もint*も確保するサイズは同じはずです とのことですが、よく考えたらそうですよね。 しかし #include <stdio.h> #include <stdlib.h> /* * */ int main(int argc, char** argv) { int a; int *b; char c; char *d; printf("%d",sizeof(a)); printf("%d",sizeof(*b)); printf("%d",sizeof(c)); printf("%d",sizeof(*d)); return (EXIT_SUCCESS); } でためしたらそれぞれ4411でintとcharのサイズが同じになりました。どこが間違えでしょうか?

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.8

>#4さん >私流に言うと「int a = 3.14;」これがエラーになるのと同じ理由です。 そもそも、これがエラーを起こすというのが間違いの始まりですね。 コンパイルすると警告は出るかもしれませんが、 int型の変数aに3という値を「正しく」格納します。

szatmari
質問者

お礼

回答ありがとうございました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.7

>メモリ上で確保する領域のサイズは同じはずですよね? sizeof(char *)とsizeof(int *)とが同じであることと、 sizeof(char)とsizeof(int)とが異なることとを 混同なさっていませんか?

szatmari
質問者

お礼

回答ありがとうございました。 僕の環境ではsizeof(char *)とsizeof(int *)は違いました。それぞれ4、1でした。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.6

>#4さん >*p = 3.14; //a=3.14;これはエラーにしないとまずいですよね? だから整数を示すためにint*が必要。 なぜエラーにしないとまずいのですか? pが指すint型の領域に、3.14の小数点以下を切り捨てた3が正しく入りますよ。 何か勘違いされてませんか?

szatmari
質問者

お礼

回答ありがとうございました。

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.5

> メモリ上で確保する領域のサイズは同じはず えーと…… sizeof(char) sizeof(int) sizeof(double) さてそれぞれいくつになるでしょうか。 問題なのは「アドレスのサイズ」じゃなくて「アドレスが指す先にあるもののサイズ」なのです。

szatmari
質問者

お礼

回答ありがとうございました。

回答No.4

この疑問は核心をついたというか、考え方は間違ってないと思います。 むしろ私も、文字はchar、整数はint、だったらアドレスはint*とかじゃなくてpoint型だろうと思うんですよね。 ちなみに漠然とアドレスを渡したい場合が実際ありまして、そういう場合は「void*」という宣言を使います。 型が必要な理由は、もう既に十分な回答が出ているようですね。 私流に言うと「int a = 3.14;」これがエラーになるのと同じ理由です。 int a=0; int* p = &a; *p = 100; //a=100; *p = 3.14; //a=3.14;これはエラーにしないとまずいですよね? だから整数を示すためにint*が必要。

szatmari
質問者

お礼

回答ありがとうございました。

回答No.3

こんばんは. ポインタに型がある理由の一つは「ポインタ演算」のためです. int num[2], *pnum; なる宣言があるとして, pnum = num; とすれば *pnum はnumの先頭の値を参照します. 次に pnum++; とすると *pnum はnumの2番目の値を参照します. ごく普通にやっていることですが,上記のことを行うには pnum = pnum + 1 という演算が「pnumをint型のサイズだけ移動する」ことでなければなりません. 単純に pnum がアドレスの値だけを格納していて,それを1加算する意味しか持たないなら, pnum++ はint型(大体は32bit)の変数の「途中」を指してしまいます. 要するにポインタに型があることで「加減算のときの飛び幅」を自動的に調整できます. 実際, double *pdnum; に関して, pdnum++; としたときと pnum++;としたとき, それぞれがdouble型要素一つ分,int型要素一つ分ジャンプしてくれることでしょう. ですが,型がなければ上記の演算は pdnum += sizeof(double) pnum += sizeof(int) と書かねばならないということです.

szatmari
質問者

お礼

回答ありがとうございました。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.2

>単に変数のアドレスを表示するだけならば型はいらない C言語では、型はその型分類によって特徴付けるという 前提があるからです。 # JIS X3010 - 6.2.5 あたり それぞれの型分類は規約で規定されるか処理系に 依存するかのいづれかとなります。 ポインタにも型分類がないと、関数なのか、 整数なのか配列なのかといったような分類ができないからでしょう。 #ポインタ型については規約に規定されていると思います。 >どうして ポインタに型があるのでしょうか? そういう細かいところが気になるのでしたら、 C言語やC++の規格書などを一読する事をお勧めします。 >またこのとき宣言された変数は *b ではなくて bであってますよね? あっていると思います。 # int* 型の d という変数になります。

szatmari
質問者

お礼

回答ありがとうございます。初心者の自分にはハードルの高い内容ですね。いつかチャレンジしたいと思います。

関連するQ&A

専門家に質問してみよう