• ベストアンサー

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」などの表記を分解して教えていただけると嬉しいです。

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

  • ベストアンサー
  • BLK314
  • ベストアンサー率55% (84/152)
回答No.2

まず、"ポインタ”について理解できていますか? "ポインタ"はメモリの"アドレス"を指し示すものです。 次に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へのポインタとして解釈し その値を取り出せ ということです(右辺に書いた場合、左辺なら格納せよです) アドレスを”ポインタとして解釈せよ"というのは 全く合法です、 ポインタとは本来どこかのアドレスを指し示すものですから 何の問題も生じません。 お分かりになりましたか

muffler
質問者

お礼

ご回答ありがとうございます。 細かく説明していただいてどうもありがとうございます。 --------- int a=1; int *q; q=&a; --------- 例えば、以上に書いた、「&a」の部分が「(int *)p」で、「*q」が「*(int *)p」でアドレスの中にある値といった感じですね!?

その他の回答 (3)

  • S117
  • ベストアンサー率40% (18/45)
回答No.4

式が一見して理解しがたい場合は分解して読みましょう。 pはvoid*型の変数とします。 *(int *)p 識別子pは変数です。 (int *)は「キャスト演算子」です。 *は「間接演算子」です。 まずはpからいきましょう。pは単に格納している値を返します。 次に(int *)はキャストですので、pから得た値をint*型に型変換します。 最後の*は間接演算子なので型変換された後の値(ポインタ)が指す先の左辺値(int型)を返します。 *(int)p がエラーになる理由はわかるでしょうか。 解釈しようとするとpの値をint型に型変換して得た値を・・・ おかしいですね。ポインタじゃないのに指す先をみるんでしょうか? これはエラーにするしかありません。 わからない用語は調べてください。 いずれにせよ、式を理解するには一度分解して考えることです。もし分解できないようでしたら、参考書などに載っている演算子一覧を参考にしてみてください。(ある程度なれればJISの規格書などもありでしょう。) ポインタ関係の理解には左辺値の理解が重要になります。参考URLはwikipediaの左辺値を含む、「値」の概念を説明した記事です。

参考URL:
http://ja.wikipedia.org/wiki/%E5%80%A4_(%E6%83%85%E5%A0%B1%E5%B7%A5%E5%AD%A6)
muffler
質問者

お礼

ご回答ありがとうございます。 (int *)はキャスト演算子なんですね! *という間接演算子が先頭に付いていたので、理解できなかった感じです。 --------- int a=1; int *q; q=&a; --------- 例えば、以上に書いた、「&a」の部分が「(int *)p」で、「*q」が「*(int *)p」でアドレスの中にある値といった感じでいいんですかね??

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.3

冗長な定義をするのなら 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);   } } といった感じになります

muffler
質問者

お礼

ご回答ありがとうございます。 「int *pi = NULL;」などの記述は、アドレスが設定されていない、空ポインタというものですよね?? C初心者なもので、あまり詳しくはありませんが、こういう記述方法もあると分かって勉強になりました! ありがとうございます。

  • asuncion
  • ベストアンサー率33% (2126/6288)
回答No.1

pはもともとvoid *型ですので、それを int *型などの本来扱いたい型に変換する必要があります。 それが、(int *) pなどの部分です。 これで、pに入っている値をint型のアドレスとみなすことができました。 そうすると、頭に*を付けることで、当該アドレスに入っている値を参照できますね。 それが、*(int *) pなどの、先頭に付いている*の役目です。

muffler
質問者

お礼

ご回答ありがとうございます。 (int *) pなどで、pに入っている値をint型のアドレスとみなし、*(int *) pでアドレスに入っている値を参照する。 理解できました! ありがとうございます。

関連するQ&A

  • 型変換がうまく出来ない

     今晩は、Cの初心者です、宜しくお願いします。  下のようなコードを書きましたが、正常に表示されません。  一体何処が悪いのでしょう。 =========================================================== #include <stdio.h> #include <string.h> #include <ctype.h> int main(void) { char s2[20] = "0.789"; double ddt = atof(s2) ; printf("ddt = %lf\n\n" , ddt); printf("atof(s2) = %lf\n\n" , atof(s2)); printf("(float)idt + atof(s2)) = %lf\n\n" , ((float)idt + atof(s2))); return 0; }

  • ポインタ定義は必要なんですか?

    #include <stdio.h> int main( void ) { int x; int *p; p = &x; printf("Address = %p\t\n", p ); return 0; } を #include <stdio.h> int main( void ) { int x; int p;←ここを上とはかえた p = &x; printf("Address = %p\t\n", p ); return 0; } にしたところコンパイル時に p = &x に関して 移植性のないポインタ変換と表記されますが 結果は同じだったのでポインタ定義というのは結局必要なんですか? 移植性のないポインタ変換とはなんなんですか? よければ詳しく教えてください

  • (void *)と&の違い

    #include<stdio.h> void * func(void *p){ printf("□■□func開始□■□\n"); printf("pのアドレス = %p\n",p); printf("p = %d\n",(int)p); (int)p += 100; printf("p = %d\n",(int)p); printf("□■□func開始□■□\n"); return NULL; } int main(void){ int number = 30; printf("numberのアドレス = %p\n",&number); func((void *)number);★1 return 0; } -------------------------------------------------------------- #include<stdio.h> void * func(int *p){ printf("□■□func開始□■□\n"); printf("pのアドレス = %p\n",p); printf("p = %d\n",*p); *p += 100; printf("p = %d\n",*p); printf("□■□func開始□■□\n"); return NULL; } int main(void){ int number = 30; printf("numberのアドレス = %p\n",&number); func(&number);★2 return 0; } 上記の2つは同じ結果になるのですが★1と★2のそれぞれの違いがわかりません。どなたかご教授をお願いします。

  • 【C言語】別関数でポインタの値を変えたのに変わらない。

    【C言語】別関数でポインタの値を変えたのに変わらない。 メイン関数のポインタの値を、別関数で書き換えるプログラムを作りました。 以下がそのプログラムになります。 そのままだと、ダブルポインタを操作する必要があるので分かり辛いです。なので、ダブルポインタをシングルポインタにしてからポインタの書き換えを行うようにしました。その結果、きちんとポインタの書き換えが出来なくなってしまいました。 なぜ出来なくなってしまったのでしょうか。 2つのプログラムの違いは、 >  *pp = &dummy; が >  p = *pp;      // ダブルポインタをシングルポインタにした >  p = &dummy; に変わっただけです。 【参考】http://www.kouno.jp/home/c_faq/c4.html#8 -----------------正しいプログラム---------------- // 以下プログラムは、正しく動作する // 実行結果は、 //   p = 5 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   *pp = &dummy; } ---------------------------------------------- -----------------間違いプログラム---------------- // 以下プログラムは、正しく動作しない // 実行結果は、 //   p = 0 // と表示される void func( int **pp ); int main (void){   int *p;   int a = 0;   p = &a;   func( &p );   printf("p = %d\n", *p);   return 0; } void func( int **pp ){   static int dummy = 5;   int *p;   p = *pp;      // ダブルポインタをシングルポインタにした   p = &dummy; } ----------------------------------------

  • ポインタ?

    #include <stdio.h> main() { char s[] = "I love cat and dog."; char c = 'a'; char *p = s; int n = 0; printf("\"%s\"の中から\'%c\'をさがします。\n", s, c); while(*p != '\0') { if(*p == c) { printf("%d番目で発見しました。\n", p - s + 1); ++n; } ++p; } if(n == 0) { printf("1つも見つかりませんでした。\n"); } else printf("全部で%d個見つかりました。\n", n); return 0; } わからないので質問したいのですが、これは「Cの絵本」という、 本に出ているサンプルプログラムです。 わからないところは、 12行目の、printf("%d番目で発見しました。\n", p - s + 1); ところです。その、「p - s」のところが特にわかりません。 ポインタって言うのは、アドレスを格納する変数ですよね? その、pからsを引いても0になるんじゃないかと思って、理解が できません。どうして、このp-sで、cの位置が発見できるのかが 理解できません。最後の+1は配列が0から始まるんで+1にすれば いいのはわかるんですが、p-sでどんなことが起きているかが 理解できなくて。ポインタをちゃんと理解できていないから、 こういった疑問が出てくるんですかね? ほかの参考書も本屋さんに行って見てみようと思っているんですが、 どなたか教えていただけませんか? よろしくお願いします。

  • ポインタのポインタ

    こんにちは。 C言語の「ポインタのポインタ」の学習中なのですが、以下のプラグラムがエラーが出てしまします。 if文が間違っていると思うのですが、具体的に何がどう間違っているのがわかりません。 ご教示お願いいたします! #include<stdio.h> int main(void) { int date = 300; int *pdate = NULL; int **ppdate = NULL; printf("dateの値は%d<\n", date); pdate = &date; printf("*pdateの値は%d<\n", *pdate); if(**ppdate = NULL){ printf("**ppdateには何も与えられていません。\n"); } else{ return 0; } ppdate = &pdate; if(**ppdate == 300){ printf("**ppdateの値は%dになりました。正常です。\n", **ppdate); } /*強制終了を避けるためのプログラム*/ int i; scanf("%d", &i); return 0; }

  • ポインタについて

    今初めてポインタというものを勉強しております。 よろしくお願いします。 ◎1---------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt; pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } --------------------------------------- ◎1のようにmydtのアドレスをポインタptに代入すれば、このプログラムは正常に動きました。 ◎2----------------------------------- #include<stdio.h> int main(void) { int mydt=1234; int *pt=&mydt; printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } ---------------------------------------- ◎2で「int *pt=&mydt;」があまりどういう意味かはわかりませんが、これも正常に動きました。 ◎3------------------------------------ #include<stdio.h> int main(void) { int mydt=1234; int *pt; *pt=&mydt printf("*pt=%d\n",*pt); printf("&mydt=%p\n",&mydt); return 0; } -------------------------------------- ◎3のように◎2と違って「*pt=&mydt」の代入を後から行うと、「'=' : 'int *__w64 ' から 'int' に変換できません。」といったようなエラーが起きてしまいます。 ◎1と◎2の違い、後何故◎3はダメなのかがわかりません。 教えていただけると嬉しいです。 後補足として、配列とポインタについてですが、 ◎4------------------------------ char ss[10]="ABCDE"; char *ssp=ss; --------------------------------- ◎5---------------------------- char ss[10]="ABCDE"; char *ssp; ssp=ss; -------------------------------- ◎4と◎5も同じような事だとは思いますが違いを教えていただけると嬉しいです。 よろしくお願いします。

  • voidポインタ

    教えて頂けますか? 環境は mac osx です。 とあるページのサンプルコード #include <stdio.h> void outString(void *); int main() { int i = 65 ; double d = 10.101; outString(&i); outString(&d); outString("Kitty on your lap"); return 0; } void outString(void *text) { char *str = (char *)text; printf("%s\n" , str); } を実行した次のように表示されました A \301ʡE\2663$@\234\367\377\277A Kitty on your lap 二行目はどういう事になっているのでしょう? ちなみに d = 65.0; で実行しましたが A とは表示されませんでした。 自分の環境のせいでしょうか? よろしくお願いします

  • void型へのポインタ

    というのがC言語にありますよね? このvoid型へのポインタというのは、 どのようにイメージすればいいのでしょうか? 例えばchar型へのポインタなら、 指している領域は 1バイトの領域ですよね? ではvoid型は? また malloc関数を 使って char *p; p=(char *)malloc(1000); とするとでchar型にキャストしているから、 1個1バイト分の領域が1000個用意して、 先頭アドレスをpに格納するのですよね? では、 int *q; q=(int *)malloc(1000); としたら、用意されるのは、int型にキャストしているから 1個2バイト分の領域が500個用意されるのでしょうか? お願いします。

  • ポインタいついて教えてください

    ポインタがわかりません。 教えてください。 下の二つは、共に「100」を表記すると思いますが、 どこがどのように違うのですか。 また、f1()という関数をつくって、ここで scanfを使って、5つぐらい値を代入させて、 他の関数でこの値を使おうと思っています。 この場合下のどちらを使うのが、よろしいのでしょうか。 よろしくお願いします #include <stdio.h> int main(void) { int *p, q; q = 100; /* q に100を代入 */ p = &q; /* p にq のアドレスを割り当てる */ printf("%d", *p); return 0; } #include <stdio.h> int main(void) { int *p, q; p = &q; /* q のアドレスを得る */ *p = 100; /* ポインタを使ってq に値を代入する */ printf("%d", q); return 0; }

専門家に質問してみよう