• ベストアンサー

参照の参照、struct record **start, の使い方は?

Linked List を作ってるのですが、 addRecord のプロトタイプが以下のようになってます。 int addRecord(struct record **start, char name[], char address[], int age); こうなると start->age = age; start.age = age; *start->age = age; ともコンパイルエラーになるのですが、対処法ありますでしょうか? ちなみに、これはポインタのアドレスを示すものですよね? これを参照の参照と呼ぶのかは確かではありませんが。。。

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

  • ベストアンサー
  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

明示的にかかれていませんが、struct recordにageというメンバがあるのですね? それならageにアクセスするには、 (*start)->age とする必要があります。 (**start).age でも同じ。 *start->ageではアロー演算子の優先順位が高いために *(start->age)と解釈されてしまいます。 参照の参照でも間違いではないと思いますが、 C言語ならポインタのポインタで良いと思います。

yasu182
質問者

お礼

できました! いろいろ調べたんですが 今見ても 自分の本には載ってなく、ほんとに助かりました。 もう一つリンクリストについてお伺いしたいのですが、 この code の修正の仕方をご存知でしょうか? while((*start)->next != NULL) *start = (*start)->next; list = (struct record *) malloc(sizeof(struct record)); if (list == NULL) { printf("malloc error\n"); exit(1); } strcpy(list->name, name); strcpy(list->address, address); list->age = age; (*start)->next = list; 3つの record を追加すると最後の2つだけが残ってしまいます。 *start = (*start)->next; 恐らくこれのおかげで start が変わるためだとは思うんですが、 うまく修正できません。 まだポインタのポインタの使い方に慣れてないので。。。

その他の回答 (5)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

「リストの末尾にデータを追加する」場合でも, ポインタのポインタを使って「リストの末尾」を覚えておくと無駄な時間を使わなくていいので便利~.

yasu182
質問者

お礼

そういう使い方もあるんですね。 ありがとうございます!

回答No.5

  >あえて「ポインタのポインタ」を使うメリットはなんでしょうか?  提示されたソースのように、リストの末尾にDATAを追加する方法では、 メリットはありません。 しかし、リストの先頭に追加する方法だと"ポインタのポインタ"を使えば、 関数内でのリストの変更が、呼び出しもとの関数に直接反映されます。 この場合でも、変更後のリストの先頭のポインタを関数の戻り値にしてやれば、 "ポインタのポインタ"を使う必要はありません。  

yasu182
質問者

お礼

勉強になりました。 ありがとうございます!

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

基本的には次のようにすればいいんだけど.... while (*start) { start = &(*start)->next; } *start = malloc(sizeof(struct record)); /* (*start)->age など設定 */ (*start)->next = NULL; なお, 「新たなデータはリストの最後に追加する」ということであれば, 毎回「リストの最後」を探すのは (O(n^2) 時間かかるので) 無駄です. そのためには「リストの最後」を示す変数を作っておくのが得策. もちろん, そのような変数を作るのであれば, 「リスト」という構造体を作ることも検討した方がよいかと.

yasu182
質問者

お礼

Big-O notation ですね。 ありがとうございます。

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.3

長さ0のリストに最初の1コをaddするとき(*start==NULL の場合)の処理も必要では?

yasu182
質問者

お礼

忘れてました (^^; ありがとうございます。

回答No.2

  >この code の修正の仕方をご存知でしょうか? struct record *work; work = *start; 以下、"*start"を"work"に変更。  

yasu182
質問者

補足

できました! ありがとうございます。 ちなみに、自分は Java から入ったのですが ポインタのポインタにまだなじめず、軽く解説 していただけないでしょうか? http://www9.plala.or.jp/sgwr-t/c/sec15-5.html 例えばこのサイトでは「ポインタのポインタ」でなく 「ポインタ」でリンクリストを作ってるわけですが、 あえて「ポインタのポインタ」を使うメリットはなんでしょうか? それと、**start が示すものは 「start に対するポインタ」の アドレスですよね? 呼ぶ時はこうだったので。 struct record *start = NULL; addRecord(&start, name, address, age); * を使うことでそのアドレスの value を取得した時があったので、 あるいは start の value を取得してるのかな、と思ったのですが。

関連するQ&A

  • structでvoid*型を利用して中身を動的に変化させる

    構造体の中にvoid*型のポインタを作り、そこの中身を替えることでデータを変えたいと思っています。 例 struct DATA{ void* p; } struct PROF_1{ char* name; int age; } struct PROF_2{ char* name; int age; int level; } void main(){ struct DATA data; struct PROF_1 p1={"HATOYAMA", 60}; struct PROF_2 p2={"OBAMA", 60, 1}; data.p = p1; printf("Name[%s] Age[%d]\n", (PROF_1)(data.p)->name, (PROF_1)(data.p)->age); data.p = p2; printf"Name[%s] Age[%d] Lv[%d]\n", (PROF_2)(data.p)->name, (PROF_2)(data.p)->age, (PROF_2)(data.p)->level); } このような感じで構造体の中にあるvoid*型のポインタの参照する場所を変えるだけで構造体の中身を変化させることが出来ないでしょうか?

  • C言語の自己参照型プログラムについて

    #include <stdio.h> #include <string.h> #include <stdlib.h> struct list { int key; /* キー */ char name[20]; /* 名前 */ struct list *next; /* 次のデータへのポインタ */ }; struct list *add_list(int key, char *name, struct list *head); void show_list(struct list *p); void free_list(struct list *p); int main(void) { struct list *head; /* 先頭ポインタ */ char name[20]; int key = 0; head = NULL; /* 先頭ポインタにNULLを設定 */ printf("キーと名前(MAX:19文字)を入力(終了:CTRL+Z)\n"); while (scanf("%d %s", &key, name) != EOF) { /* リストにデータを登録 */ head = add_list(key, name, head); } /* リストの表示 */ show_list(head); /* リストの開放 */ free_list(head); return 0; } /*** リストにデータを登録 ***/ struct list *add_list(int key, char *name, struct list *head) { struct list *p; /* 記憶領域の確保 */ if ((p = (struct list *) malloc(sizeof(struct list))) == NULL) { printf("malloc error\n"); exit(EXIT_FAILURE); } /* リストにデータを登録 */ p->key = key; strcpy(p->name, name); /* ポインタのつなぎ換え */ p->next = head; /* 今までの先頭ポインタを次ポインタに */ head = p; /* 新たな領域を先頭ポインタに */ return head; } /*** リストの表示 ***/ void show_list(struct list *p) { while (p != NULL) { /* 次ポインタがNULLまで処理 */ printf("%3d %s\n", p->key, p->name); p = p->next; } } /*** リストの開放 ***/ void free_list(struct list *p) { struct list *p2; while (p != NULL) { /* 次ポインタがNULLまで処理 */ p2 = p->next; free(p); p = p2; } } これを実行すると、 新しく入力された順にリストが表示されます。 そうではなく、キーの昇順に表示したいです。 どなたかそのように実行できるようにプログラムを書き換えてくれませんか? 図々しいですがよろしくお願いいたします。m(_ _)m

  • アルゴリズム 線形リスト

    最近リストについて習い始めました。入力したデータと同順に並ぶリストを作成しようと思い、コードを打ったのですが…動作中止の表示がでてしまいました。どこが間違っているのか、ずっと悪戦苦闘して組んでいるのですが、全く出口が見えてきません。何が間違えているのか、はたまた根本的に違うのか、ご指導して頂けると有難いです。 以下、コードです。 #include <stdio.h> #include <stdlib.h> #include <string.h> struct hito{ char name[20]; int age; struct hito *next; }; void main(void){ struct hito *p, *head, *dummy; char new_name[20]; int new_age; dummy = (struct hito *)malloc(sizeof(struct hito)); head = dummy; dummy->next = p; dummy = p; while (scanf("%s %d" , new_name, &new_age) != EOF) { p = (struct hito *)malloc(sizeof(struct hito)); strcpy(p->name, new_name); p->age = new_age; p->next = head; head = p; } while(p != NULL) { printf("\t%-20s %3d\n" , p->name, p->age); p = p->next; } }

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

    #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での対象もアドレスを示していると思うのですが、 結果は値を表示しているのはなぜでしょうか?

  • このプログラムのポインタを配列に変換したいんですけど

    C言語初心者です。助けてください。 途中までがんばったのですがどうしてもできません。問題はこの構造体の*name→name[25],*email→email[30]に変換させたいのですが、そのまま変換すると左辺値が必要や移植性のないポインタ変換などのエラーが出てしまいます。どうすればいいですか?教えてください。あと関数getlineと構造体は変えないでください。(指定した部分は除く) このプログラムは名前、メールアドレス、年齢を保存していき-1を入力した時出力されるというものです。 よろしくお願いします。 入力例 10 hakata abc@・・・ 12 yokohama dfg@・・・ -1 -1 -1 出力例 -1 -1 -1 12 yokohama dfg@・・・ 10 hakata abc@・・・ #include <stdio.h> #include<stdlib.h> struct node { char *name; char *email; int age; struct node *next; } heap[100], *hp = heap; void getline(char *s,int n) { int c; while(--n>0&&((c=getchar())!=EOF && c!='\n')) *s++=c; *s='\0'; } char* dupstr(char* strg) { char* newstr; newstr=(char*)malloc(sizeof(char)*strlen(strg)); strcpy(newstr,strg); return newstr; } struct node *new(int n ,char* a, char* b) { hp->age=n; hp->email=a; hp->name=b; hp->next=NULL; return hp++; } struct node *add(struct node *p, struct node *q) { q->next=p; p=q; return p ; } void print_list(struct node *p) { while (p != NULL) { printf("%d ", p->age); printf("%s ", p->name); printf("%s ", p->email); p=p->next; } printf("\n"); } main() { int age,p; char buf[80],a[80],b[80],*email,*name; struct node *root=NULL; while(getline!=NULL) { getline(buf,sizeof(buf)); age=atoi(buf); getline(b,sizeof(b)); getline(a,sizeof(a)); email=dupstr(b); name=dupstr(a); root=add(root,new(age,email,name)); if(age==-1) break; } print_list(root); }

  • ファイル読込時に構造体の文字列ポインタに割当てたいと

    ファイル読込時に構造体の文字列ポインタに割当てたいと思っています。 (new 演算子を使用します。) 文字列の長さが不定です。 どうすれば、文字列の長さを知ることができますか? 以下のようなところまでは作れましたが、 困っています。 void loaddata()のfscanf関数の部分です。 ほかにも関数の void outputdata() void deletedata() がありますが、長いので省略しました。 ********************************************************** #include<stdio.h> #include<string.h> class data { public: struct basic { char *name; int age; struct basic *next; }; private: struct basic *base; struct basic *base_top; int cnt; public: data::data() { cnt=0; } void inputdata(char *name,int age) { if(cnt==0) { base=new basic; base_top=base; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } else { base->next=new basic; base=base->next; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } } void savedata() { base=base_top; FILE *fp; fp=fopen("dat.txt","w"); for(int i=0;i<cnt;i++) { fprintf(fp,"%s\t%d\n",base->name,base->age); base=base->next; } fclose(fp); } void loaddata() { if(cnt!=0){deletedata();} cnt=0; FILE *fp; fp=fopen("dat.txt","r"); while(1) { fscanf(fp,"%s\t%d\n",base->name,base->age); } } };

  • [C言語]ソート関数の作成

    現在受け取った構造体を受け取ってソートしてポインタで書き換える関数を作成しています。 構造体の配列 typedef struct{ char name[50]; int age; }member; member seito[10] strcpy(seito[0].name,"yamada") seito[0].age = 15; strcpy(seito[2].name,"ito") seito[2].age = 17; strcpy(seito[3].name,"saito") seito[3].age = 19; こちらの構造体は例です。 seito[2]の情報を[1]に seito[3]の情報を[2]に移動させたいのですが、上手くいきません。 構造体配列を、1引いてあげれば良いと思ったのですが、そうすると[0]までマイナスしてしまい上手く判定が出来ません。 どうかアドバイスお願いいたします。

  • scanfの\nの意味

    タイトルの通りです。 #include<stdio.h> struct Person{ char name[100]; char gender; int age; }; int main(void) { struct Person person1; printf("名前は:"); scanf("%s",person1.name); printf("\n年齢は:"); scanf("%d",&person1.age); printf("\n性別は:"); scanf("\n%c",&person1.gender); printf("\n{name=%s,age=%d,gender=%c}",person1.name,person1.age,person1.gender); return 0; } 上記において aaa , 11 , M と入力すると {name=aaa,age=11,gender=M} と表示されますが、 scanf("\n%c",&person1.gender); を scanf("%c",&person1.gender); に変えると {name=aaa,age=11,gender= } となってしまいます。 この理由と、/nの意味を教えてください。

  • 配列の中を変更

    入力したnameに、入力したageの数だけ文字を進める(例えばnameがOda、ageが12→表示結果がAmp)にする関数を作成しようとしたのですが、やり方がまったくわかりません。 そもそもこのような場合、文字1つ1つに別の配列を使わなければならないのでしょうか? #include <stdio.h> #define N 1 #define NAME 20 typedef struct{ char name[NAME]; char age; } person; int main(void){ int i; person persons[N]; for(i=0;i<N;i++){ printf("name > "); scanf("%s" , persons[i].name); printf("age > "); scanf("%d" , &persons[i].age); } for(i=0;i<N;i++){ printf("name = %s\n" , persons[i].name); printf("age = %d\n" , persons[i].age); } return 0; }

  • 名簿作成 表示について

    名簿作成のプログラム、コンパイルしたときに 自分で入れた名簿を全て表示させたいのですが main関数をどう変えれば出来るでしょうか? このままだと、1人分しか表示されません。 初心者なので丁寧に教えてくださればと思います。 #include<stdio.h> #define NAMELEN 30 #define NOLEN 10 char s; struct gakuseki{ char no[NOLEN]; char name[NAMELEN]; int age; }; struct gakuseki input_data(void){ struct gakuseki st; printf("input student number>"); scanf("%s",&st.no); /*getchar(); fgets(st.no,NOLEN,stdin);*/ printf("input name>"); getchar(); fgets(st.name,NAMELEN,stdin); printf("input age>"); scanf("%d",&st.age); printf("continue?(y/n)"); scanf("%s",&s); return st; }; void output_data(struct gakuseki g){ printf("----------------------------------\n"); printf("student number : %s\n",g.no); printf("name : %s\n",g.name); printf("age : %d\n",g.age); }; int main(){ int i,j; struct gakuseki stud; for(i=0;i<3;i++){ /* struct gakuseki stud;*/ stud=input_data(); if(s=='n') { break; }; }; output_data(stud); };