構造体内のポインタのポインタについて

このQ&Aのポイント
  • ポインタを理解するために以下のようなテストプログラムを作成。
  • 38,39行目をコメントアウトするとコンパイルは通るが、そのままだとコンパイルエラーになる。
  • なぜいけないのか、理由を教えてください。
回答を見る
  • ベストアンサー

構造体内のポインタのポインタについて

ポインタを理解するために以下のようなテストプログラムを作りました。 test.h --- typedef struct i_info{ int i_id; char i_name[64]; } I_INFO; typedef struct j_info{ int j_id; char j_name[64]; } J_INFO; typedef struct k_info{ int k_id; char k_name[64]; } K_INFO; typedef struct info{ int id; char name[64]; I_INFO iinfo; J_INFO *jinfo; K_INFO **kinfo; } INFO; --- test.c --- 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include "./test.h" 4 5 int main(int argc, char **argv) 6 { 7 INFO info; 8 J_INFO j; 9 K_INFO k; 10 K_INFO *pk=NULL; 11 12 memset (&info,NULL,sizeof(info)); 13 memset (&j,NULL,sizeof(j)); 14 memset (&k,NULL,sizeof(k)); 15 16 info.id = 1; 17 memcpy(info.name,"***",3); 18 19 info.iinfo.i_id = 2; 20 memcpy(info.iinfo.i_name,"*i*",3); 21 22 info.jinfo = &j; 23 j.j_id = 3; 24 memcpy(j.j_name,"*j*",3); 25 26 info.kinfo = &pk; 27 pk= &k; 28 k.k_id = 4; 29 memcpy(k.k_name,"*k*",3); 30 31 printf( "%d\n",info.id); 32 printf( "%s\n",info.name); 33 printf( "%d\n",info.iinfo.i_id); 34 printf( "%s\n",info.iinfo.i_name); 35 printf( "%d\n",info.jinfo->j_id); 36 printf( "%s\n",info.jinfo->j_name); 37 /* 38 printf( "%d\n",info.kinfo->k_id); 39 printf( "%s\n",info.kinfo->k_name); 40 */ 41 } --- 38,39行目をコメントアウトするとコンパイルは通るのですが、 そのままだとコンパイルエラーになります。 なぜいけないのでしょうか?理由を教えてください。

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

  • ベストアンサー
noname#6581
noname#6581
回答No.5

ポインタのポインタというのはどういうときに使うかと言いますと、多くの場合「ポインタ変数の配列」を扱いたいときに使用します。(もちろんそうでない場合もあります) yumi-mikaさんのプログラム例は、要素が一つしかないポインタ変数の配列と考えることができます。そのため、#3の回答を書きました。 ポインタのポインタを説明するには図がないときついのでここには書けませんが、yahooで「ポインタのポインタ」で検索すると解説ページがいっぱい出てきますので、そちらをご覧になってください。 ではC言語の習得頑張ってください。

yumi-mika
質問者

お礼

yahooだとずいぶんと見つかるものですね。#文章なのに 度々ありがとうございました。今後ともよろしくお願いいたします。

その他の回答 (4)

noname#6581
noname#6581
回答No.4

すいません、分かりにくかったらこうでもいいです。 printf( "%d\n",(*info.kinfo)->k_id); printf( "%s\n",(*info.kinfo)->k_name);

yumi-mika
質問者

お礼

希望どおりに動作することを確認しました。どうもありがとうございました! ただどうも理由が理解できません。 ポインタまでならわかるのですが(本当はわかっていないのかもしれません)、 ポインタのポインタ(しかも構造体)となると急にわからなくなってしまいます。 また似たような壁にぶつかりそうな気がします。 よろしければ、どうやったら上のような文法になるのか理由を教えてください。 ここで説明するには長くなりすぎるということであれば、 ポインタについてShigureさんご自身が参考とした本や URLなどございましたら教えていただけると助かります。 よろしくお願いいたします。

noname#6581
noname#6581
回答No.3

正しくはこうですね。 printf( "%d\n",info.kinfo[0]->k_id); printf( "%s\n",info.kinfo[0]->k_name);

  • nagare
  • ベストアンサー率33% (280/831)
回答No.2

ごめんなさいミスりました printf( "%d\n",**(info.kinfo)->k_id); printf( "%s\n",**(info.kinfo)->k_name);

yumi-mika
質問者

お礼

やはりだめのようです。 jinfoとkinfoの違いはポイント先が1回増えるだけですよね? iinfoとjinfoはうまくいく表示できるのですが・・・。

  • nagare
  • ベストアンサー率33% (280/831)
回答No.1

printf( "%d\n",*(info.kinfo)->k_id); printf( "%s\n",*(info.kinfo)->k_name); これでどうでしょう メモリ上 info.kinfo->pk->k_id となっているからです

yumi-mika
質問者

補足

お返事ありがとうございます。 早速ためしてみましたが、エラーメッセージはいままでと変わりません。 #質問時には800文字の制限にひっかかり、 エラーメッセージまで記載できなかったので今回記載します gcc test.c test.c: In function `main': test.c:37: request for member `k_id' in something not a structure or union test.c:38: request for member `k_name' in something not a structure or union

関連するQ&A

  • 構造体とポインタについて教えてください。

    #include <stdio.h> typedef struct ningen { char *name; char *sex; int age; } NINGEN; NINGEN data = {"牧村 五郎",NULL,30}; char mf[2][3] = {"男","女"}; void main(void) { data.sex=mf[0]; printf("%s (%s) %d歳\n", data.name, data.sex, data.age); } このプログラムで実行結果は 牧村 五郎 (男) 30歳 となるのですが、最初の typedef struct ningen { char *name; char *sex; int age; } NINGEN; のところで、nameとsexはアドレスで宣言しているので printf("%s (%s) %d歳\n", data.naem, data.sex, data.age);でのdata.naem, data.sexでの対象もアドレスを示していると思うのですが、 結果は値を表示しているのはなぜでしょうか?

  • 構造体の配列のアロケート等の方法

    基本的な事かもしれないのですが、 構造体の配列をダブルポインタで返すような関数を作成したいのですが、アロケートの仕方と、そもそも配列をダブルポインタで扱う方法が良く分かってないのかもしれません。 どなたかご教授頂けないでしょうか? Webで調べてもなかなか合ったものが見つからないため、こちらに質問させて頂きました。 イメージしているものを↓に途中まで作ってみました。これも合っていない部分があるかもですが。。。 要はアロケートして構造体の配列を作成する部分と、それをfor文で回して参照する方法が、分かっていない主なところです。 #include <stdio.h> #include <memory> typedef struct member{   int  id;   char*  name; } *member_t; int get_result(member_t *pobj) {   member_t* obj = NULL;   obj = (member_t*)malloc(sizeof(member_t));   memset(obj, 0x00, sizeof(member_t));   char* nm = NULL;   char cnmtmp[] = "nakayama";   nm = (char*)malloc(strlen(cnmtmp)+1);   memset(nm, 0x00, strlen(cnmtmp)+1);   memcpy(nm, cnmtmp, strlen(cnmtmp));   obj->id = 100;   obj->name = nm;   *pobj = obj;   return 0; } int get_resultList(member_t **ppobj) {   /*    * ココ    */   return 0; } void main() {   member_t* obj = NULL;   get_resultList(&obj);   for(int i = 0;;){     /*      * ココ      */     printf("[%d]\n",i+1);     printf("ID : %d\n", ->id);     printf("NAME : %s\n", ->name);     free( ->name);     free( );   }   free(obj); } 長々とすみません。

  • 構造体についてです。

    typedef struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }STUDENT; と、 struct student{ int id; char name[20]; int kokugo; int sansu; int eigo; }; の違いはなんでしょう? 私は下記をよく使うのですが・・・。 typedefについて詳しく知りたいです。

  • 構造体のポインタにNULLが入らない

    typedef struct tag{ int number; char name[10]; struct tag *next; }DATA; という構造体があって、 DATA *p; と宣言し、 p->next == NULL; とすることはできないんですか? セグメンテーション違反になってしまうのですが。 pが指すnextにNULLを入れるにはどうしたらいいのでしょうか?

  • ファイル操作やポインタ、構造体について(C言語)

    C言語の課題で詰まってしまいました。宜しければ助言を宜しくお願いします。 コマンド選択で,0) 終了,1) 追加,2) 検索(id),3)変更 が行える学生成績管理プログラムを作成する。 データは,学生の番号 名前 GP 総単位数 形で学生のデータを持っているファイルである。 #include<stdio.h> #include<stdlib.h> #include<string.h> struct student{ int id; char name[25]; int gp; int credit; }; void add(char *, struct student);//追加 int search(char *, struct student *);//検索 void change(char *, struct student);//指定したidの学生の情報を変更 main(int argc,char *argv[]) { FILE *fp; int i = 0; int num; struct student students; if(argc == 1){ printf("set filename\n"); return 1; } while(1) { printf("1)add 2)search 0)quit "); scanf("%d",&num); if(num == 0) break; /* 追加 */ if(num == 1) { printf("id name gp credit ? "); scanf("%d %s %d %d", &students.id, students.name, &students.gp, &students.credit); add(argv[1], students); } /* 検索 */ if(num == 2) { printf("id ? "); scanf("%d", &students.id); if(search(argv[1],&students)){ printf("%d %s %d %d\n", students.id, students.name, students.gp, students.credit); } else{ printf("ID %d Not Found.\n",students.id); } } if(num == 3){ //変更 } } } /* 追加ルーチン */ void add(char *filename, struct student students) { FILE *fp; if((fp = fopen(filename, "a")) == NULL){ printf("can't open %s\n", filename); exit(1); } fprintf(fp,"%d %s %d %d\n", students.id, students.name, students.gp, students.credit); fclose(fp); } /* 検索ルーチン */ int search(char *filename, struct student *students) { FILE *fp; int id; char name[25]; int gp; int credit; if((fp = fopen(filename, "r")) == NULL){ printf("can't open %s\n", filename); exit(1); } while(fscanf(fp,"%d %s %d %d", &id, name, &gp, &credit) != EOF) { if(id == students->id){ students->id = id; strcpy(students->name ,name); students->gp = gp; students->credit = credit; return 1; } } return 0; fclose(fp); } /* 変更ルーチン */ void add(char *filename, struct student students){ } ------------ここまで------------ ファイルの操作での入出力は"a"や"r"、また"w"を利用するのかとも思いましたが、 指定したIDの内容を書き換えるにはポインタを2つ使う方法しか思いつかないのですが、与えられた問題で、変更のプロトタイプは void change(char *, struct student); となっていて、どうやるのかまったく見当もつきません。 稚拙な文で伝わりにくいかもしれませんが、 変更のやり方についてご教授願います。 見難くて申し訳ありません。 どうか宜しくお願いします。

  • C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成して

    C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成しています。 一応目的の動作はするのですが、プログラミングとして正しいか教えて頂ければと 思います。 <test.c> int main() { /* ---------------------------------------- */ /* 構造体のメンバ(NULL保障無し)がNULLか */ /* 比較するサンプル */ /* ---------------------------------------- */ char buf[50]; /* サンプル構造体 */ struct ST_test { int cd; char name[10]; int no; }; struct ST_test st_test; /* 構造体定義 */ memset(&st_test,0x00,sizeof(st_test)); /* 構造体初期化 */ memset(&buf[0],0x00,sizeof(buf)); /* 構造体初期化 */ /* 構造体に値セット */ st_test.cd = 12; memcpy(&st_test.name[0],"aabbccddee",sizeof(st_test.name)); st_test.no = 999; /* NULL判定 */ if(*st_test.name == 0x00) { printf("NULLです\n"); } else { printf("NULLではないです\n"); } return (0); }

  • 構造体型のポインタ変数を含む構造体

    struct seiseki_tag { Int32 math ; Int32 english ; Int32 science; } ; typedef struct seiseki_tag SEISEKI ; struct personal_tag { Char name ; Int32 num ; SEISEKI *sptr } : typedef struct personal_tag PERSONAL ; struct info_tag { PERSONAL person_info ; } ; typedef struct info_tag INFO ; たとえば、上記のように3つの構造体があり、PERSONAL構造体のメンバーに SEISEKI構造体の型を持つポインタ変数が含まれているような場合で、下記のように INFO型のポインタ変数からSEISEKI構造体のメンバーを参照する方法を教えてください。 PERSONAL構造体メンバーのnameやnumは INFO *info ; info->person_info.name ; info->person_info.num ; のように参照すると思いますが、sptrが示すSEISEKI構造体のメンバーへの アクセスができません。下記のように参照を試みたのですがコンパイルは 通るのですが、実際に参照できていませんでした。 INFO *info ; SEISEKI *seiseki ; seiseki = info->person_info.sptr ; seiseki->math ; 判りにくい説明で申し訳ありませんが、どなたか教えていただければと思います。 よろしくお願いいたします。

  • 構造体を動的変数とポインタを使い表を作る

    学校の改題で「人数を入力して、その人数分の名前と点数を入力して一覧にしろ」という課題がでたのですが、どこから手を付けていいのか解りません。 内容は「任意の人数を設定して、その分ループして名前と点数をいれ、その構造体を頭からループして一覧を作れ」ということなので以下のようにやってみたのですが、結果が「(null) 0」としかなりません。 手の打ちようがないので助言お願いします。 #include <stdio.h> #include <stdlib.h> struct ty_i{ char *name; int point; }; int main(void){ int n,i; struct ty_i *main_ty,*copy_ty; printf("n = ");scanf("%d",&n); main_ty=(struct ty_i *)malloc(sizeof(struct ty_i)*n); if(main_ty==NULL){ printf("Error\n"); exit(1); } for(i=0;i<n;i++){ printf("%d:",i);scanf("%s,%d",&main_ty++->name,&main_ty++->point); } copy_ty=main_ty; for(i=0;i<n;i++){ printf("%s\t%d\n",copy_ty++->name,copy_ty++->point); } exit(0); }

  • ポインタと構造体の利用について

    samplefile.txtの中身 c03888 工大八郎 90 a03111 工大一郎 100 a03222 工大二郎 30 b03666 工大六郎 70 b03555 工大五郎 60 a03333 工大三郎 80 c03777 工大七郎 40 c03999 工大九郎 20 b03444 工大四郎 50 このデータをfscanfで取り込んで構造体に代入 typedef struct { char code[7]; char name[21]; int score; }REC; そしてこのデータを昇順にソートして結果を出力したいのですが 問題はここから work52.cというファイルとbubble.cというファイルとmy_sort.hというファイルがあり、work52.cからmy_sortという関数(バブルソート)を使いたい。 work52.cの中身 #include <stdio.h> #include "my_sort.h" #define MAX_NUM 500 int main(int argc, char *argv[]){ FILE *fp; REC rec[MAX_NUM]; int i, sum , min, max , n; if (argc != 2) { printf("ファイル名を指定してください\n"); return(-1); } if ((fp = fopen(argv[1], "r")) == NULL) { printf("ファイルを開けませんでした\n"); return(-1); } i = 0; while (fscanf(fp, "%s %s %d", rec[i].code, rec[i].name, &rec[i].score) != EOF){ i++; } fclose(fp); n = i; /* 初期値の設定 */ min = rec[0].score; max = rec[0].score; sum = rec[0].score; for (i = 1; i < n; i++){ sum += rec[i].score; if (rec[i].score < min) { min = rec[i].score; } if (rec[i].score > max) { max = rec[i].score; } } my_sort(rec, n); printf("最高点:%3d\n", max); printf("最低点:%3d\n", min); printf("平均点:%5.1f\n", (double) sum / n); for (i = 0; i < n; i++){ printf("%3d\t%s\t%s\n", rec[i].score, rec[i].code, rec[i].name); } return(0); } my_sort.hの中身 typedef struct { char code[7]; char name[21]; int score; }REC; void my_sort(REC *rec,int n); バブルソートで整列 #include <stdio.h> #include "my_sort.h" #define MAX 50 void my_sort(REC *rec, int n){ for(i = 0;i < n - 1; i++){ for(j = n - 1;j > i;j--){ /*この中身が問題----1*/ } } } 1の部分でchar codeとchar nameとint scoreの値を交換するときにどうすればいけるでしょうか?ご教授ください。

  • 構造体へのポインタ

    すみません、構造体へのポインタの配列の扱いに困っています。 下記ソースの struct list *hashtable[HASHSIZE]; の箇所をmain部に入れた場合の 他の関数内での使用の仕方が全くわかりません。 どのように修正すれば良いのでしょうか。 申し訳ありませんが教えてください。 --------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 40 #define MAX_KW_LEN 256 #define NUM_KW 23 #define TRUE 1 #define FALSE 0 struct list {  char keyword[MAX_KW_LEN];  struct list *next;   /* 次の list へのポインタ */ }; struct list *hashtable[HASHSIZE]; /* ハッシュテーブル */ /* キーワード ( Cの予約語 ) */ static char kw[NUM_KW][MAX_KW_LEN] = {   "auto", "break", "double",   "enum", "char", "continue", "extern", "float", "for", "int",   "long", "register", "short", "signed", "static",   "struct", "typedef", "union", "unsigned", "return",   "void", "volatile", "while" }; int Hash(char *key); void InitHTable(void); int FindKeyWord(char *key); void ListKeyWord(void); void FreeKeyWord(void); int main(void); int Hash(char *key) {  int hashval = 0;  while (*key != '\0')   hashval += *key++;  return (hashval % HASHSIZE); } void InitHTable(void) {  int i;  struct list *p, *q;  int hashval;  for (i = 0; i < NUM_KW; i++) {   printf("%d\n",i);   if ((FindKeyWord(kw[i])) == FALSE) { /* 登録されていなかったら */             /* メモリを割り付ける */    if ((p = (struct list *)malloc(sizeof(struct list))) == NULL) {     fprintf(stderr, "メモリ不足です。\n");     exit(2);    }    strcpy((*p).keyword, kw[i]);    hashval = Hash(kw[i]);    /* ハッシュ値を求めて */        if (hashtable[hashval] == NULL) { /* 未登録なら */     hashtable[hashval] = p;  /* p の指すアドレスを登録 */     p->next = NULL;    /* リストの末尾に NULL を追加 */    }    else {        /* 既に登録していたら */     q = hashtable[hashval];     while (q->next != NULL) {  /* データがなくなるまで */      q = q->next;    /* リストをたどる */     }     q->next = p;     /* リストの末尾に p の指すアドレスを登録 */     p->next = NULL;    /* その末尾に NULL を追加 */    }   }  } } int FindKeyWord(char *key) {  struct list *p;  for (p = hashtable[Hash(key)]; p != NULL; p = p->next)   if (!strcmp(key, (*p).keyword))  /* 登録済みなら */    return (TRUE);     /* TRUE を返す */   return (FALSE);      /* 未登録ならFALSE を返す */ } void ListKeyWord(void) {  int i;  struct list *p;  for (i = 0; i < HASHSIZE; i++)   for (p = hashtable[i]; p != NULL; p = p->next) /* p が NULL でなければ */               /* ハッシュ値とキーワードを表示 */    printf("予約語:%s ハッシュ値:%d:\n", (*p).keyword, Hash((*p).keyword)); } /* malloc( ) で割り付けたメモリを解放 */ void FreeKeyWord(void) {  int i;  struct list *p, *q;  for (i = 0; i < HASHSIZE; i++)   for (p = hashtable[i]; p != NULL; ) { /* p が NULL でなければ */    q = p->next;      /* p->next を保存 */    free(p);       /* メモリを解放 */    p = q;        /* p->next を p に代入 */   } } int main(void) {  char word[MAX_KW_LEN];  int i;  InitHTable( );  ListKeyWord( );  for (i = 0; i < 4; i++) {   printf("Cの予約語を入力して下さい ");   fgets(word, 128, stdin);   if ((FindKeyWord(word)) == TRUE)    printf("%s は登録済みです。\n", word);   else    printf("%s は未登録です。\n", word);  }  FreeKeyWord( ); }

専門家に質問してみよう