- ベストアンサー
void型ポインタについて
-------------------------------- #include<stdio.h> void uni_disp(void *p,int typ); int main() { int idt=123456; double ddt=56.789; char ss[]="abcdef"; uni_disp(&idt,'I'); uni_disp(&ddt,'D'); uni_disp(ss,'S'); uni_disp("STRING",'S'); return 0; } void uni_disp(void *p,int typ) { if(typ=='I'){ printf("%d\n",*(int *)p); } else if(typ=='D'){ printf("%f\n",*(double *)p); } else if(typ=='S'){ printf("%s\n",(char *)p); } } ----------------------------------- 以上のプログラム等で、void型ポインタをint型ポインタ、double型ポインタとみなす場合の、「*(int *)p」や「*(double *)p」の表記がどういう仕組みになっているか分かりません。 「*(int)p」などはエラーが出るのですが、やはり表記の意味を理解していないため何故か分かりません。 「*(int *)p」などの表記を分解して教えていただけると嬉しいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
まず、"ポインタ”について理解できていますか? "ポインタ"はメモリの"アドレス"を指し示すものです。 次にchar型へのポインタ(char*)とint型へのポインタ(int*)の違いはわかりますか?(ここではintは32ビットとします) たとえば char* pで pが0xFF00 (面倒なのでアドレスは16ビットとします。ポインタが16ビットでintが32ビットとは変なシステムということです) このとき p + 1はどこを指すでしょう 当然 0xFF01 です。 では int* qが同じアドレス0xFF00を指すとき q + 1はどこを指すでしょう 同じく 0xFF01 ではありません。 0xFF04 です。 コンパイラはqのポインタが指し示す変数(オブジェクト)の型を認識しており その型の大きさずつ移動します。 void* という特別のものもあり これは例外的に型を認識しません。 どんな変数のアドレスも指すことができます。 実際に使うときは何かへのポインタ (たとえばchar*)にキャストして使います。 *(int)pとは pの内容(アドレス)をintとして解釈し、 さらにそのintの値をそのままアドレスと解釈し、 その値を取り出せ ということです(右辺に書いた場合、左辺なら格納せよです) おそらく int n = *(int)p とでも書きたいのでしょうが、これはとても危険な行為を内包しています。 intの値を"そのまま"アドレスとして扱う行為は アクセス違反を起こす可能性もあるなどの理由で禁じられています。 *(int *)pの場合は pの内容(アドレス)を(intの値ではなく)intへのポインタとして解釈し その値を取り出せ ということです(右辺に書いた場合、左辺なら格納せよです) アドレスを”ポインタとして解釈せよ"というのは 全く合法です、 ポインタとは本来どこかのアドレスを指し示すものですから 何の問題も生じません。 お分かりになりましたか
その他の回答 (3)
- S117
- ベストアンサー率40% (18/45)
式が一見して理解しがたい場合は分解して読みましょう。 pはvoid*型の変数とします。 *(int *)p 識別子pは変数です。 (int *)は「キャスト演算子」です。 *は「間接演算子」です。 まずはpからいきましょう。pは単に格納している値を返します。 次に(int *)はキャストですので、pから得た値をint*型に型変換します。 最後の*は間接演算子なので型変換された後の値(ポインタ)が指す先の左辺値(int型)を返します。 *(int)p がエラーになる理由はわかるでしょうか。 解釈しようとするとpの値をint型に型変換して得た値を・・・ おかしいですね。ポインタじゃないのに指す先をみるんでしょうか? これはエラーにするしかありません。 わからない用語は調べてください。 いずれにせよ、式を理解するには一度分解して考えることです。もし分解できないようでしたら、参考書などに載っている演算子一覧を参考にしてみてください。(ある程度なれればJISの規格書などもありでしょう。) ポインタ関係の理解には左辺値の理解が重要になります。参考URLはwikipediaの左辺値を含む、「値」の概念を説明した記事です。
お礼
ご回答ありがとうございます。 (int *)はキャスト演算子なんですね! *という間接演算子が先頭に付いていたので、理解できなかった感じです。 --------- int a=1; int *q; q=&a; --------- 例えば、以上に書いた、「&a」の部分が「(int *)p」で、「*q」が「*(int *)p」でアドレスの中にある値といった感じでいいんですかね??
- redfox63
- ベストアンサー率71% (1325/1856)
冗長な定義をするのなら void uni_disp(void *p,int typ) { // 変換後のポインタ型変数を用意する int *pi = NULL; double *pd = NULL; char *ps = NULL; if(typ=='I'){ pi = (int*)p; printf("%d\n",*pi); //printf("%d\n",*(int *)p); } else if(typ=='D'){ pd = (double*)p; printf("%f\n",*pd); //printf("%d\n",*(double *)p); } else if(typ=='S'){ ps = (char*)p; printf("%s\n",ps); //printf("%d\n",(char *)p); } } といった感じになります
お礼
ご回答ありがとうございます。 「int *pi = NULL;」などの記述は、アドレスが設定されていない、空ポインタというものですよね?? C初心者なもので、あまり詳しくはありませんが、こういう記述方法もあると分かって勉強になりました! ありがとうございます。
- asuncion
- ベストアンサー率33% (2127/6289)
pはもともとvoid *型ですので、それを int *型などの本来扱いたい型に変換する必要があります。 それが、(int *) pなどの部分です。 これで、pに入っている値をint型のアドレスとみなすことができました。 そうすると、頭に*を付けることで、当該アドレスに入っている値を参照できますね。 それが、*(int *) pなどの、先頭に付いている*の役目です。
お礼
ご回答ありがとうございます。 (int *) pなどで、pに入っている値をint型のアドレスとみなし、*(int *) pでアドレスに入っている値を参照する。 理解できました! ありがとうございます。
お礼
ご回答ありがとうございます。 細かく説明していただいてどうもありがとうございます。 --------- int a=1; int *q; q=&a; --------- 例えば、以上に書いた、「&a」の部分が「(int *)p」で、「*q」が「*(int *)p」でアドレスの中にある値といった感じですね!?