ポインタと構造体

このQ&Aのポイント
  • C言語初心者のためのポインタと構造体に関する基本的な内容について解説します
  • リスト構造を使ったサンプルコードを元にポインタと構造体の基本的な使い方を説明します
  • コードの説明や疑問点についてわかりやすく解説します
回答を見る
  • ベストアンサー

ポインタと構造体

C言語初心者です。 下のコードはリスト構造のサンプルコードを元に自分で書き直そうとしているコードです。(なので、現時点では不完全なところ(例えばfreeしてないとか)があるのと、自分で理解出来ていない箇所があります。) 実行すると、8から3までの値が一応表示されるようになったですが、その過程の仕組みが自分でもよく理解出来ていません。 (1)tra *q = NULL; 通常、構造体のポインタを使用するときはq = &___のように他の構造体のアドレスを渡して使用出来るようにすると思いますが、ここではなぜ*qに、NULLを代入する必要があるのでしょうか。 (2)そのNULL状態のポインタqを関数printingdudeに突っ込んで結果的に8、7、6、、と出力されるまでの過程がよくわかりません。簡単に解説して頂けると助かります。(ちょっと雑な質問になってしまい申し訳ありません) typedef struct transcript{ int no; struct transcript *next; } tra; void printingdude(struct transcript *m); tra* noud(int v, tra* c); int main(){ tra *q = NULL; int i; for(i = 8; i>1; i--){ printingdude(q); q = noud(i, q); } return; } void printingdude(struct transcript *m){ if(m ==NULL) return; printf("%d\n", m->no); } tra* noud(int v, tra* c){ tra *a = (tra *) malloc(sizeof(tra)); a->no = v; a->next = c; return a; }

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

  • ベストアンサー
回答No.1

・printingdudeはノードの値を表示する関数 ・noudeは新しいノードを作ってリストの最初につなぐ関数 ですね? 最初にNULLを入れているのは、trがNULLならリストが終わりという意味にしようとしているのでしょう。 forの中の動きですが、 i=8の時:printingdudeはmがNULLなので何も表示しない、noudeはnoが8のノードを新しく作ってリストの最初に挿入 i=7の時:printingdudeはさっき作ったノードのnoを表示(8が表示される)、noudeはnoが7のノードを新しく作ってリストの最初に挿入 i=6~2も同様で、最後はno=2のノードを作って終わり ですね。

redhat_001
質問者

お礼

有り難うございました。

関連するQ&A

  • リスト構造を双方向リスト構造に書き換えたいです

    C言語初心者です。以下のリスト構造を双方向リストに書き換えたいです。 構造体にstruct transcript *prvs;を追加するのはいいとして、その後どのように変更したらよいでしょうか。関数printingdudeのprvs版を追加し、メイン部でprintingdude_prvs(Z)をすればよいでしょうか。詳しい方、お手数ですがご教示頂きたいです。。 #include <stdio.h> #include <stdlib.h> typedef struct transcript { int no; struct transcript *next; } tra; void printingdude(tra *x) { if (x == NULL) return; printf("%d",x->no); if (x->next != NULL) { printf(", "); printingdude(x->next); } else { printf("\n"); } return; } void free_noud(tra *x) { while (x != NULL) { tra *t = x->next; free(x); x = t; } return; } tra* nnoud(int v, tra* c) { tra *x = (tra *) malloc(sizeof(tra)); if (!x) { printf("\ncan't allocate memory for a new node"); exit(EXIT_FAILURE); } x->no = v; x->next = c; return x; } int main() { tra *Z = NULL; for (int n = 10; n>0; n--) { printingdude(Z); Z = nnoud(n, Z); } printingdude(Z); free_noud(Z); return 0; }

  • 構造体へのポインタ

    すみません、構造体へのポインタの配列の扱いに困っています。 下記ソースの 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( ); }

  • 構造体のポインタ

    なぜかprevのほうが表示されません。 問題としては関数を作成し gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END と表示させるのが目的です gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] ここまではうまく表示できているのですが・・・ #include <stdio.h> void printoufuku(struct kara *p); struct kara { char name[16]; int age; struct kara *next; struct kara *prev; }; int main() { struct kara a, x, f, m, c, *start; strcpy(a.name, "gyuri"); a.age = 23; strcpy(x.name, "sunyon"); x.age = 23; strcpy(f.name, "nicole"); f.age = 20; strcpy(m.name, "hara"); m.age = 20; strcpy(c.name, "jiyon"); c.age = 17; a.next = &x; x.next = &f; f.next = &m; m.next = &c; c.next = NULL; /********************* 5 lines */ c.prev = &m; m.prev = &f; f.prev = &x; x.prev = &a; a.prev = NULL; /*********************/ start = &a; printoufuku(start); return 0; } void printoufuku(struct kara *p) { for(p->next; p != NULL;p = p->next){ printf("%s[%d] ->",p->name,p->age); } for(p->prev; p != NULL; p = p->prev){ printf("%s[%d] ->",p->name,p->age); } }

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

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

  • 構造体のポインタ参照

    構造体のプログラムを作成しており、コンパイルを行った際にエラーが起きてしまいました。 以下に構造体宣言とメイン関数のプログラムをとエラーが出てしまった部分を記述します。 エラー表示の内容として「不完全型ポインタへの間接参照」と出ました。 自分なりに考えた結果、ポインタの参照部分に間違いがあるためエラーが起こったと思います。そのエラーが生じた部分のプログラムをどのように修正すればコンパイルが成功するか、ご教授のほうお願いします。 /* 構造体宣言 */ typedef struct { int m; double *a; double *alpha; }PREDICTOR; int main(){ struct PREDICTOR *pred; int i; /* ここでエラーが起きました */ pred -> a[0] = pred -> a[1] =0; pred -> m = 0; pred -> alpha = r(0);  /* ここまで */ for(i = 0; i < M; i++){ pred = levin(pred); } return 0; }

  • ポインタの扱い

    すみません、構造体へのポインタの配列の扱いに困っています。 下記ソースの 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; }; struct list *hashtable[HASHSIZE]; 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->next = NULL; } else { q = hashtable[hashval]; while (q->next != NULL) { q = q->next; } q->next = p; p->next = 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); return (FALSE); } void ListKeyWord(void) { int i; struct list *p; for (i = 0; i < HASHSIZE; i++) for (p = hashtable[i]; p != NULL; p = p->next) printf("予約語:%s ハッシュ値:%d:\n", (*p).keyword, Hash((*p).keyword)); } void FreeKeyWord(void) { int i; struct list *p, *q; for (i = 0; i < HASHSIZE; i++) for (p = hashtable[i]; p != NULL; ) { q = p->next; free(p); p = q; } } 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( ); }

  • ポインタを使って構造体の配列を戻り値にするには

    関数の戻り値を構造体の配列(アドレスを受け渡しを利用して)にしたいのですがうまくゆきません。 以下のプログラムではコンパイルはできるのですが、 a0 = 2 a1 = 4198512 a2 = 4329332 と表示されてしまいa1,a2がうまくゆきません。 ********************************************* #include<stdio.h> struct test{ int a; }; struct test *func(void); void main(void) { struct test *data;//構造体ポインタ int i; data = func(); //ポインタにtest関数の戻り値(アドレス)を代入 for(i=0;i<=2;i++){   printf("a%d = %d\n",i,(data+i)->a); //構造体要素を表示 } } struct test *func(void) { struct test data[3]={1,2,3}; //構造体配列を定義 return (&data[0]); //構造体配列の先頭アドレスを返す } ************************************************* test関数から受ける取ったアドレス(&data[0])をポインタ(data)に代入して1づつずらして表示させれば a0=1,a1=2,a=3 となると思ったのですがどこが間違っているのでしょうか? よろしくお願いします。

  • 構造体のリスト削除

    かれこれ1時間くらい悩んでいて 問題として 関数delete()を作成し、プログラムを完成させよ(~yabuki/p7.c)。 関数delete()は、与えられたデータをリストから削除するものである。 ただし、データが先頭であっても動作しなければならない。 次のように出力されるはずである。 NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> END PREV jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> END PREV hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END NEXT sunyon[23] -> END PREV sunyon[23] -> END list ha nakunarimasita /*******/の間に5行のプログラムを入れる。それ以外にmain()関数を 変更してはならない。 .........;の部分に構造体のメンバーを定義せよ。 というもので、Deleteしていくプログラムをつくりたいのですが NEXT gyuri[23] -> sunyon[23] -> nicole[20] -> hara[20] -> jiyon[17] -> END PREV jiyon[17] -> hara[20] -> nicole[20] -> sunyon[23] -> gyuri[23] -> END セグメントエラー となり、続きができていません。 delete関数のif(p->next != NULL){ のところだけやると 最後まで出るみたいですが、うまくいってません よろしくおねがいします。 ↓ソースです・・・ #include <stdio.h> #include <string.h> struct kara { char name[16]; int age; struct kara *next; struct kara *prev; }; struct kara * delete(struct kara *,struct kara *); struct kara * findend(struct kara *); void* printforw(struct kara *); void* printback(struct kara *); int main() { struct kara a, x, f, m, c, *start, *end, *p; char name[128]; strcpy(a.name, "gyuri"); a.age = 23; strcpy(x.name, "sunyon"); x.age = 23; strcpy(f.name, "nicole"); f.age = 20; strcpy(m.name, "hara"); m.age = 20; strcpy(c.name, "jiyon"); c.age = 17; a.next = &x; x.next = &f; f.next = &m; m.next = &c; c.next = NULL; /********************* 5 lines */ a.prev = NULL; x.prev = &a; f.prev = &x; m.prev = &f; c.prev = &m; /*********************/ start = &a; end = findend(start); printforw(start); printback(end); printf("\n"); p = &c; start = delete(start, p); if (start == NULL) { printf("list ha nakunarimasita\n"); return 0; } else { end = findend(start); printforw(start); printback(end); } printf("\n"); x.next = NULL; p = &a; start = delete(start, p); if (start == NULL) { printf("list ha nakunarimasita\n"); return 0; } else { end = findend(start); printforw(start); printback(end); } printf("\n"); p = start; start = delete(start, p); //de senntou wo kaesu if (start == NULL) { printf("list ha nakunarimasita\n"); return 0; } else { end = findend(start); printforw(start); printback(end); } return 0; } struct kara * delete (struct kara *start,struct kara *p) { /*if(p->next->next->next->next) { start = p->next->next->next->next; } */ for(p = start;p != NULL;p = p->next) { start = p->next->next->next; p = start; } /* if(p->next) { start = p->next; } if(p->prev) { start = p->prev; } if(p->next != NULL){ p->next->prev = p->prev; } } */ return p; } struct kara * findend(struct kara *start) { struct kara *pl; for(pl = start;pl != NULL; pl = pl->next){ start = pl; } return start; } void* printforw(struct kara *aa) { struct kara *pl; printf("NEXT "); for ( pl = aa; pl != NULL; pl = pl->next) { printf("%s[%d] -> ", pl->name, pl->age); } printf("END\n"); } void* printback(struct kara *cc) { struct kara *pl; printf("PREV "); //for( ; cc != NULL;cc = cc->prev){ for (pl = cc; pl != NULL; pl = pl->prev) { printf("%s[%d] ->", pl->name,pl->age); } printf("END\n"); }

  • リス;ト構造のポインタ

    struct list{ int data; struct list *next; }; struct list *cons(int x,struct list *n){ struct list *ans; ans=(struct list*)malloc(sizeof(struct list)); if(ans!=null) ans->date=x; ans->next=n; } return ans;} void main(){ int x; struct list *top=NULL; struct list **tail=&top; while(scanf("%d",&x)==1){ *tail=cons(x,NULL);  tail=&((*tail)->next):         }  入力した順にリストに追加されるプログラムらしいのですが、void main(){}の中のプログラムの動きが よく分かりません。このプログラムの動作の流れを簡単に教えてください。漠然とした質問カと思いますが よろしくお願いします。

  • C言語の構造体についてなんですが。

    struct LIST {     struct Num* number;     struct LIST* next;/* 次の要素へのポインタ */ }*root; struct Num{     int a;     struct Num* next; /* 次の要素へのポインタ */ }*numroot; と構造体を定義したときに、 main(){     struct LIST *p;     for(p = root; p != NULL; p = p->next) ; } とすれば、pの先頭からNULLまでを参照していくことは分かるんですが、pのnumberの先頭からNULLまでの参照方法(プログラムのfor文の記述方法)がイマイチわかりません。つまり、構造体の構造体をどのように参照するかということです。 これを実現したい理由は、構造体内での数の格納を配列(固定長)ではなく可変長で格納したいからです。 分かる方は解答をお願いします。

専門家に質問してみよう