• 締切済み

リス;ト構造のポインタ

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=⊤ while(scanf("%d",&x)==1){ *tail=cons(x,NULL);  tail=&((*tail)->next):         }  入力した順にリストに追加されるプログラムらしいのですが、void main(){}の中のプログラムの動きが よく分かりません。このプログラムの動作の流れを簡単に教えてください。漠然とした質問カと思いますが よろしくお願いします。

みんなの回答

回答No.6

mainで行われていることを簡単な図にしてみました。 1,2,3,…という順で入力したと仮定します。 topとtailの位置は現在指している所です。 NULL top NULL top tail 1回目のループ (1) ⇒ NULL top tail (1) ⇒ NULL top  tail 2回目のループ (1) ⇒ (2) ⇒ NULL top  tail (1) ⇒ (2) ⇒ NULL top       tail 3回目のループ (1) ⇒ (2) ⇒ (3) ⇒ NULL top      tail (1) ⇒ (2) ⇒ (3) ⇒ NULL top          tail 以降同じように続くと思います。

kimiko09
質問者

お礼

わかりやすい説明有難うございました

  • ency
  • ベストアンサー率39% (93/238)
回答No.5

まず、cons() で何をやっているのかはお分かりですか? 1. リンク構造体を生成。 2. 引数で渡された数値でメンバ変数 data を初期化。 3. 引数で渡されたリンク構造体を指すポインタでメンバ変数 next を初期化。 4. 初期化済みリンク構造体を指すポインタを返す。 と、こんな感じでしょうか。 で、main() の方でやっている処理ですが、こんな感じでしょうか。 1. キーボードから数字を入力。 2. cons() でリンク構造体を生成。  ここでキーボードから入力した数字と NULL ポインタを初期値として与える。  cons() の戻り値を *tail に格納する。  # tail ではなく、*tail であることに注意。 3. tail を置き換える。  # この置換えで、リンクが次々続いていきます。 4. 数値以外が入力されるまで 1~3 を繰り返す。 と、ここまではよろしいでしょうか。 では、実際の変数の動きを見ていきます。 -------------------------------------------------------- 1. tail = ⊤ 2. *tail = cons(x,NULL); ⇒ top = cons(x,NULL); と等価。   つまり、cons() で生成したリスト構造体を指すポインタが top に入る。  ちなみに、この時点では top->next == NULL。 3. tail = &((*tail)->next);  ⇒ tail = &(top->next); と等価。   つまり、「2 で生成したリスト構造体 (を指すポインタ==top ですよね?)」の next を指すポインタが tail に入る。 4. *tail = cons(x,NULL);  ⇒ top->next = cons(x,NULL); と等価。  ちなみに、この時点で (top->next)->next == NULL。 5. tail = &((*tail)->next);  ⇒ tail = &((top->next)->next); と等価。   つまり、「4 で生成したリスト構造体 (を指すポインタ==top->next ですよね?)」の next を指すポインタが tail に入る。 6. *tail = cons(x,NULL);  ⇒ (top->next)->next = cons(x,NULL); と等価。  ちなみに、この時点で ((top->next)->next)->next == NULL。 …… (以下省略。。。) -------------------------------------------------------- こんな感じで処理が進んでいくわけです。 つまり、リンクされていく段階で最後のリスト構造体の next は常に NULL で初期化されているわけです。 で、値を順次参照していく場合には、 top->data (top->next)->data ((top->next)->next)->data …… とリスト構造体の next == NULL になるまで続ければ良いわけで、ということはどうすれば良いかはお分かりですね。 こんな感じでいかがでしょうか。

kimiko09
質問者

お礼

レスが遅れて申し訳ありませんでした 分かりやすい説明有難うございました

  • hankyo
  • ベストアンサー率0% (0/0)
回答No.4

連結されていないと思いましたが、されてる見たいですね。。。 tailが一つ前の構造体のnextの参照位置を示しているのが、ポイントですね。 スレ汚し失礼しました。

  • hankyo
  • ベストアンサー率0% (0/0)
回答No.3

連結されていないと思いますが。。。 while文の中で一個前のstruct listへのポインターを持つ変数と、初めの一個目の構造体はwhile()の外で作る必要があると思います。

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.2

なかなかいい線を来ています。考え方はしっかり合っています。 (*1)  *tail=cons(x,NULL); (*2)  tail=&((*tail)->next): のところが分かりづらいですよね。これは例題の出来が悪いせいですから、気に病む必要はありません。 さて肝心のリスト構造(順番に連結された構造)を作成している場所ですが、ちゃんと(*1)と(*2)で連結しています。(cons関数に渡しているNULLは単なる目くらましで、データを連結する役には立っていません。) (*1)と(*2)で行っていることは、こういうことです。 (*1): cons関数が返す「構造体へのポインタ」(cons関数がmallocで取得したメモリへのポインタ)を「tailが指す変数」に格納する。 (*2): 「tailが指す変数の値」(すなわち、(*1)でcons関数が返した「構造体へのポインタ」)が指す構造体のメンバ変数next、へのポインタを変数tailに格納する。 「tailが指す変数」は最初はtopですが、2回目以降は「リスト構造の最後の構造体の中にあるメンバ変数next」であることに注意してください。 また、ループを回るごとにリストに構造体がどんどん追加されるので、「リスト構造の最後の構造体」はループを回るごとに変化します。 すごーく分かりづらいと思いますが、何となく意味が掴めるでしょうか。

kimiko09
質問者

補足

やっぱりtail=&((*tail)->next)が良く分からないんので、連結が良くわからないんですけど、ポインタのポインタ構造体tailっていうのはポインタの構造体topに対応させると **tail=*top 、*tail=&topに対応するんでしょうか? それならtail=&((*tail)->next)のtailが何を示して いるのか良く分からないんです。又、=&((*tail)->next)はループが一回目の場合(*tail)->nextの指している物(=null?)のアドレスってことでしょうか? 最後にもう一つ、このプログラムを表示させる場合は for(struct list *p=top;p!=null;p=p->next) printf("%D",p->date); でokなんでしょうか? ゴチャゴチャしてて読みにくいと思いますが、よろしくお願いします。

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.1

どこまで分かっているのか書いてもらえれば、説明するのが楽になるので助かるのですが。 まず変数の内容を紙に書き出して、1行ずつ順を追って動作を確認してみてください。3回くらいループしてみてください。 その上で、分かったことと分からないことを箇条書きに書いてみてください。そうしてもらえれば答えやすいです。

kimiko09
質問者

補足

全体的に間違ってそうなんですけど 一回目のループの場合は >struct list *top=NULL; 構造体のポインタtopのアドレスをNULLにする >struct list **tail=⊤  構造体のポインタのポインタtailのアドレスをtopの  アドレス=NULLにする >while(scanf("%d",&x)==1){  入力された値が一つならループする >*tail=cons(x,NULL);  構造体のポインタのポインタtailにxの値と、  次の場所(=NULL)を入れる。またtopのアドレスが  かわる? >tail=&((*tail)->next):  ここの記述が良く分かりません、一応書いてみると  構造体のポインタのポインタtailの次のデータの  場所=NULLをtailのアドレスとする?       }  3回ほどループして見たんですけど、入力される値のつながりがない(リストになっていない)ような気がします。

関連するQ&A

  • 線形リスト

    こんにちわ。今、大学で線形リストの勉強してるのですがよくわかりません。 ↓のプログラムで (1)10個のIDを受け取って受け取った順にリストを作るプログラム(各要素の値のアドレスとそのnextの値を表示してリストになっていることを確認する。) (2) (1)のプログラムを拡張して、リストを作ったあと、1から10までの間の整数nを入力として受け取り、リストのn番目の要素のIDを表示プログラムを書け。 の2つのことをしたいんですけど、どのようにすればいいのですか?どなたか回答おねがいします。 #include<stdio.h> #include<stdlib.h> struct list{ int ID; struct list *next; }; int main(int argc, char* argv[]) { struct list *top; top=(struct list *)malloc(sizeof(struct list)); //struct list 型の大きさの領域を1つ確保 //topがそこを指している状態にする //printf("IDを10個入力してください"); if(top == NULL){ //メモリが足りないと値がNULLになってします printf("メモリは確保できません\n"); exit(1); //強制終了。プログラムはココで終わってしまいます } top->next=NULL; top->ID=1; //ポインタtopが指している構造体のIDの値を変えている top->next=(struct list*)malloc(sizeof(struct list)); //もう1つ作ります //top->next==NULL (メモリ確保に失敗)の処理は省略 (top->next)->next=NULL; (top->next)->ID=5; //これで下図のような状態になります; 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( ); }

  • リスト構造のプログラミング

    #include<stdio.h> #include<stdlib.h> typedef struct number{ float x; struct number *next; }Num; void append_list(Num **, float); int main(void) { Num *start,*p; float i,d; start=NULL; for(i=0.0;i<10.0;i++){ append_list(&start,i); } p=start; while(p!=NULL){ printf("%f\n",p->x); p=p->next; } p=start; while(p !=NULL){ Num *q; q=p; p=p->next; free(q); } return 0; } void append_list(Num **s, float n) { Num *end, *new; if(*s==NULL){ *s=(Num *)malloc(sizeof(Num)*1); (*s)->x=n; (*s)->next=NULL; return; }end=(*s); while(end->next !=NULL){ end=end->next; } new=(Num *)malloc(sizeof(Num)*1); new->x=n; new->next=NULL; end->next=new; } 0~9までの数値を順番に追加してリスト構造のデータ構造で 保存するプログラミングを作ったのですが、これにキーボード から入力した1つの実数(0~9)を数値の順序を乱さないよう にその数値を持つ要素を追加するにはどうすればよいのでしょうか?

  • ポインタを使った連結リストへの挿入

    siteiで指定されているポインタの直後に要素xを挿入する関数insertをポインタの連結リストを用いて作成したのですが、実行するとセグメンテーション違反がでて上手く動きません。何処に問題があるのでしょうか?topの初期値が不定になるのが問題と思い、topをNULLで初期化して実行してみたのですが、結果は変わりませんでした。 宜しければ回答または問題点を指摘していただけますでしょうか?宜しくお願いします。 typedef struct{ int data; struct DATA *next; }DATA; DATA top; int insert(int x,DATA *sitei) { DATA *p,*buf; p=&top; while( p!=NULL && p!=sitei) p=p->next; buf=malloc(sizeof(DATA)); buf->next=p->next; p->next=buf; buf2->data=x; return 0; }

  • ポインタと構造体

    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; }

  • list構造。。。

    リストの末尾にデータを追加すると、最後に追加したデータで今までのリストのデータが上書きされてしまいます。。 以下に、ソースを掲載させていただきます。 void SetNode(List* node_first, List* node_second, int *data) { node_first->move = data; node_first->next = node_second; return ; } /*末尾に挿入*/ void Insert_Tail(List **head, int* data) { List *ptr = *head; if(ptr == NULL){ *head = (List*)calloc(1,sizeof(List)); SetNode(*head, NULL, data); return ; }else{ while(ptr->next != NULL){ ptr = ptr->next; } ptr->next = (List*)calloc(1,sizeof(List)); SetNode(ptr->next, NULL, data); } return ; } void show_list(List *list) { List *ptr = list; while(ptr != NULL){ printf("%d\n",*(ptr->move)); ptr = ptr->next; } return ; } int main(int argc, char** argv) { /*宣言*/ Node* root; /**/ List* top; /* 手順のリスト */ int judge; top = NULL; do{ printf("num:"); scanf("%d",&judge); switch(judge){ case 1: /*データを末尾に追加*/ printf("mem:"); scanf("%d",mem); root->board = mem; Insert_Tail(&top, root->board); break; case 2: /*リストを頭から表示*/ show_list(top); break; default: break; } }while(judge != 0); return 0; } 自分は最後のリストまでたどって、callocしたつもりなのですが、どうもそうではないようで、困っています。 どうか、御指導の程、お願いします。

  • リストの削除について(構造体)

    リストの削除のプログラムを実行して行ってみると、リストの削除処理中にプログラムが終わって変更後処理がうまく表示されません。どこが間違っているかが分からないしだいです。返答のほどよろしくお願いいたします。 #include<stdio.h> #include<malloc.h> #include<string.h> struct list{ char name[20]; int age; struct list *next; }; void main(void) { struct list *head, *p, *n, *old; char key[20]; /*ダミーノード作成*/ head = (struct list*)malloc(sizeof(struct list)); old = head; while(p = (struct list*)malloc(sizeof(struct list)), printf("name age入力\n"), scanf("%s %d", p -> name, &p -> age) != EOF){ old -> next = p; old = p; } free(p); old -> next = NULL; p = head -> next; printf("変更前リスト\n"); while(p != NULL){ printf("name:%s age:%d\n",p -> name, p -> age); p = p -> next; } printf("削除key入力(name)\n"); gets(key); n = head; while(n != NULL){ old = n; n = n -> next; //printf("n -> name %s\n", n -> name); if(strcmp(n -> name, key) == 0){ printf("%s削除\n", key); //printf("n -> name %s old -> name %s\n", n -> name, old -> name); old -> next = n -> next; } } p = head -> next; printf("変更後リスト\n"); while(p != NULL){ printf("name:%s age:%d\n", p -> name, p -> age); p = p -> next; } }

  • ポインタ

    #include<stdio.h> #include<stdlib.h> struct number{ int value; struct number *next; }; int main(void){ FILE *f; struct number *p; int n=0,i; f=fopen("number.txt","r"); p=malloc(sizeof(struct number)); if(p==NULL){ printf("error"); return 1; } while(fscanf(f,"%d",&(p+n)->value)!=EOF){ (p+n)->next=malloc(sizeof(struct number)); if(p+n==NULL){ printf("error"); return 1; } p+n=(p+n)->next; n++; } for(i=0;i<n;i++) printf("%d\n",(p+i)->value); free(p); fclose(f); return 0; } のp+n=(p+n)->next;の部分でバグが出てしまうのですがアロー演算子と通常の演算子を同時に使うことができないなどのような規則があるのでしょうか、それとも俺がバカなだけなのでしょうか?ご指摘お願いします。

  • C言語のリストのソートについて質問します。

    C言語のリストのソートについて質問します。 こんばんは、aida13です。以前の質問が自己解決しました。回答者のみなさん本当にすみませんでした。 今回はそのアルゴリズムで改善したい点がありましたので投稿させていただきました。以下のソートを実行するとソート自体はうまくいくのですが、見ての通りwhileやifなどを使って何度も実行しなおさないと完全にソートできません(「5 4 3 2 1」→「4 3 2 1 5」(一回ソート))。これを一回でソートできるようにしたいのです。また、降順も同様にそのままsecondとheadを入れ替えたのですが…今度は何度やっても「1 2 3 4 5」→「2 1 3 4 5」(一回ソート)からそれ以上動きません。アドバイスをお願いします。また、出来る限りこの形を保てる形でお願いします。 以下自作ソート #include < stdio.h > #include < stdlib.h > struct ans { int data; struct ans *next; }; struct ans *sort_up(struct ans *head) { int temp; struct ans *second_head; second_head = (struct ans *)malloc(sizeof(struct ans)); second_head = head->next; if( head->next == NULL ) { return head; } else { if( head->data > second_head->data ) { temp = head->data; head->data = second_head->data; second_head->data = temp; sort_up(head->next); } else { sort_up(head->next); } return head; } } struct ans *add_list(int x, struct ans *head) { struct ans *new_head; new_head = (struct ans *)malloc(sizeof(struct ans)); new_head->data = x; new_head->next = head; return new_head; } void show_list(struct ans *head) { if( head == NULL ) { printf("\n\n"); } else { printf("%d ",head->data); show_list(head->next); } } void main() { struct ans *head; head = NULL; head = add_list(1,head); head = add_list(2,head); head = add_list(3,head); head = add_list(4,head); head = add_list(5,head); do { printf("input:"); scanf("%d",&a); if(a==0) { head = sort_up(head); show_list(head); } } while(a==0); }

  • リスト

    リスト構造にしたいのですがどうすればいいでしょうか。 #include <stdio.h> #include <stdlib.h> #include <string.h> struct toy { char name[10]; int number; struct toy next; }; /*プロトタイプ宣言*/ void omocha_toy(struct toy *x); int main( void ) { struct toy *x; if((x =(struct toy *)malloc(sizeof(struct toy))) == NULL) { fprintf(stderr,"エラー\n"); exit(1); } sprintf("x -> name,"Osarusan"); x->score = 12; omocha_toy(x); return 0; } void omocha_toy(struct toy *x) } printf("%s",x->name); printf("%d\n",x->number); } このプログラムで2つ目3つ目をリスト構造を使って作りたいんです。 お願いします。

専門家に質問してみよう