• ベストアンサー

ポインタと動的確保について

#include <stdio.h> #include <stdlib.h> typedef struct LIST{ int number; char name[30]; }list; void test(list** ls) { list *tmp; tmp=*ls; //tmpに*lsのアドレスを参照させる printf("%d\n",(*ls)->number); //5と表示 printf("%d\n",tmp->number); //5と表示 (*ls)->number=10; //lsの指すものを10に変更 printf("%d\n",(*ls)->number); //10と表示 printf("%d\n",tmp->number); //10と表示 *ls=(list *)calloc(1,sizeof(list)); //lsを動的確保 printf("%d\n",(*ls)->number); //callocで初期化されるので0 printf("%d\n",tmp->number); //10と表示 ← なぜ指すもののlsの値が変わったの //に値が変わらないのか } int main(void) { char input[12]; list *ls,ls2; ls2.number=5; ls=&ls2; test(&ls); scanf("%s",input); return 0; } void test(list **)の内容の動的確保後にポインタ変数tmpが 刺しているはずの**lsの内容が変わったのにtmpの内容が変わらない 理由がわかりません。 よろしくお願いします

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

  • ベストアンサー
  • venzou
  • ベストアンサー率71% (311/435)
回答No.2

main関数と、test関数で同名の変数名を使っていますが、 紛らわしいので、main関数の方を下記の様に変更して説明します。 (説明のための変更です、実際に書き換える必要はありません。) list *ls1,ls2; -------------------------------------------------- test関数が呼ばれたとき、変数の状態は ls = &ls1 *ls == ls1 == &ls2 **ls == *ls1 == ls2 >tmp=*ls; //tmpに*lsのアドレスを参照させる この行ですが、コメントは間違いですね。 tmpに代入しているのは*lsです。つまりls2のアドレス。 ls1のアドレスではありません。 *ls == ls1 ですので、*ls を calloc() で更新しても、 tmpは変化しません。ls2のアドレスを指したままです。 コメント通りに代入するなら tmp = &(*ls) つまり、 tmp = ls です。 (tmpの宣言は list **tmp になります。) この代入後の変数の状態は tmp == ls == &ls1 *tmp == *ls == ls1 == &ls2 **tmp == **ls == *ls1 == ls2 >*ls=(list *)calloc(1,sizeof(list)); //lsを動的確保 この代入の後の変数の状態は tmp == ls == &ls1 *tmp == *ls == ls1 == (動的に確保されたlistのアドレス) **tmp == **ls == *ls1 == (動的に確保されたlist) 下記の様に書き直せば期待通りの動作になると思います。 -------------------------------------------------- void test(list** ls) { list **tmp; tmp=ls; //tmpに*lsのアドレスを参照させる printf("%d\n",(*ls)->number); //5と表示 printf("%d\n",(*tmp)->number); //5と表示 (*ls)->number=10; //lsの指すものを10に変更 printf("%d\n",(*ls)->number); //10と表示 printf("%d\n",(*tmp)->number); //10と表示 *ls=(list *)calloc(1,sizeof(list)); //lsを動的確保 printf("%d\n",(*ls)->number); //callocで初期化されるので0 printf("%d\n",(*tmp)->number); //0と表示 } --------------------------------------------------

JIF0131
質問者

お礼

参照先が違ったんですね、納得できました。

その他の回答 (1)

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

下記のコードを実行してみると、*lsをcallocしたときに、 当初の*ls(つまりtmp)とはアドレスが異なっていることがわかります。 #include <stdio.h> #include <stdlib.h> typedef struct LIST {   int number;   char name[30]; } list; void test(list **ls) {   list *tmp;      tmp = *ls;              // tmpに*lsのアドレスを参照させる      printf("%p %p\n", tmp, *ls);      printf("%d\n", (*ls)->number);    // 5と表示   printf("%d\n", tmp->number);    // 5と表示      printf("%p %p\n", tmp, *ls);      (*ls)->number = 10;          // *lsの指すものを10に変更   printf("%d\n", (*ls)->number);    // 10と表示   printf("%d\n", tmp->number);    // 10と表示      *ls = (list *) calloc(1, sizeof(list));    // *lsを動的確保      printf("%p %p\n", tmp, *ls);    // *lsのアドレスは、当初とは異なる(※)      printf("%d\n", (*ls)->number);    // callocで初期化されるので0   printf("%d\n", tmp->number);    // 10と表示 ← なぜ指すもののlsの値が                     // 変わったのに値が変わらないのか } int main(void) {   list *ls, ls2;      ls2.number = 5;   ls = &ls2;   test(&ls);   return 0; } (注)インデントのため、全角空白を使っています。

関連するQ&A

  • ポインタ

    質問なのですが、このソースのchar *str_copy(char *d, const char *s)関数内のchar *p=d;はなんで、*pにdを入れるか分かりません。それと、このdは、*dなのですか?どうして、while (*d++ = *s++) みたいに*dをつけないんですか?教えてください。宜しくお願いします。 #include <stdio.h> char *str_copy(char *d, const char *s) { char *p=d; while (*d++ = *s++) ; return (p); } int main(void) { char tmp[100]; char st1[100], st2[100],st3[100]; printf("文字列を入力してください:"); scanf("%s",tmp); str_copy(st1,str_copy(st2,tmp)); printf("文字列st1は%sです。\n", st1); printf("文字列st2は%sです。\n", st2); printf("文字列st3は%sです。\n", str_copy(st3,tmp)); return (0); }

  • ポインタです

    #include <stdio.h> char *msg = "This is an apple."; void exchange(char *); int main(void){ char *mm = "This is a test."; char *p = msg; printf("%s\n", p);//This is an apple. p = mm; printf("%s\n", p);//This is a test. exchange(p); printf("%s\n", p); return 0; } void exchange(char *q){ q[0] = 't'; } としたら"This is a test." が "this is a test." に変わっているはずなんですがCygwinでの表示は Segmentation fault (core dumped)と表示されてしまいます・・・ なにが原因なんでしょうか?

  • ポインタが全く分かりません。

    今C言語を勉強していて、先日やっとポインタに取り組み始めました。でもいきなりわけ分からなくなってしまいました。自分なりに本やホームページで調べてみたのですが、説明が全く載っていなかったので、質問させてもらいました。 /* 2つの値の交換 (正) */ #include<stdio.h> void swap(int *px, int *py) { int tmp; tmp = *px; *px = *py; *py = tmp; } void main() { int a=3, b=5; printf("a=%d, b=%d\n", a, b); swap(&a, &b); printf("a=%d, b=%d\n", a, b); return 0; } 実行結果  a=3, b=5         a=5, b=3 /* 2つの値の交換 (誤) */ #include<stdio.h> void swap(int *px, int *py) { int tmp; *px = tmp; *px = *py; *py = tmp; } void main() { int a=3, b=5; printf("a=%d, b=%d\n", a, b); swap(&a, &b); printf("a=%d, b=%d\n", a, b); return 0; } エラーメッセージ 『Warning:'tmp' used before set』 実行結果  a=3, b=5         a=5, b=4404 tmp = *px と *px = tmp は同じに見えるのですが、なぜ tmp = *px だとちゃんとできて、*px = tmp とした時はエラーが出るのでしょうか。 分かる人には申し訳ないほどの初歩的な質問でしょうが、全く分からないのでめちゃくちゃ困ってます。初心者にも分かりやすいように、なるべく詳しく回答していただけると、とても嬉しいです。

  • ポインタについて

    今初めてポインタというものを勉強しております。 よろしくお願いします。 ◎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も同じような事だとは思いますが違いを教えていただけると嬉しいです。 よろしくお願いします。

  • ポインタについてです。

    #include <stdio.h> int main (void){ char (*a)[3]; printf("a: %d\n", sizeof(a)); printf("a[0]: %d\n", sizeof(a[0])); printf("a[0][0]: %d\n", sizeof(a[0][0])); return 0; } このようなプログラムがあったとして a: 4 a[0]: 3 a[0][0]: 1 のような結果が得られました。a[]が3であるのは理解できたんですが、その他の結果があんまり理解できません・・・・ 解説をお願いします。

  • ポインタ

    #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;の部分でバグが出てしまうのですがアロー演算子と通常の演算子を同時に使うことができないなどのような規則があるのでしょうか、それとも俺がバカなだけなのでしょうか?ご指摘お願いします。

  • 分割コンパイルについて

    現在分割コンパイルが分からずに苦戦しています。 下記のリストは構造体を使わなければコンパイラを通すことができましたが、 使うとなぜか通りません。 あれこれ試しましたがどうしても分かりません。 何がおかしいのでしょうか? *define.hで全てのファイルへの定義や宣言を行わせています。 ////////////// //Main.cpp ////////////// #include <stdio.h> #include <conio.h> #include "define.h" int main( void ){ Tmp[0].c = 15; printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); aaa(); bbb(); getch(); return 0; } ////////////////// // A.cpp ///////////////// #include <stdio.h> #include "define.h" void aaa( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // B.cpp ///////////////// #include <stdio.h> #include "define.h" void bbb( void ){ printf("a: %d\n", a); printf("b: %d\n", b); printf("c: %d\n", Tmp[0].c); printf("NUM:%d\n", NUM); } ////////////////// // define.cpp ///////////////// #include "define.h" int a = 10; int b = 20; struct Parameter { int c; }; struct Parameter Tmp[NUM]; ////////////////// // define.h ///////////////// #define NUM 100 extern int a; extern int b; extern struct Parameter Tmp[NUM]; void aaa( void ); void bbb( void );

  • 配列の動的確保

    No.847223 reallocについて No.847300 ポインタについて と質問させてもらい、御回答をいただき、理解した(つもりな)のですが、以下のことが実現できなくこまっております。 (以前の質問はこれを実現するために質問しました。) まず配列array[1][20]を用意します(つまり文字列最高20字格納できる要素数1個の配列を用意)。 そして動的にこの配列のサイズを変更して、なにか文字列を入力する毎に、代入するスペースを逐次確保したいわけです。(メモリが溢れない限りスペースを確保しまくる) そこでcallocやreallocの記述の仕方に困っています。 まず、callocについて char array[1][20]; char *pn, *pn2; pn = (char *)calloc(sizeof(array)/sizeof(char),sizeof(char)); このボイドポインタをキャストする部分にchar* と char** のどちらを使えばいいか、です。 そしてreallocについて、 if( (pn2 = (char *)realloc(pn, sizeof(array)*cnt)) == NULL ){ printf("メモリの確保失敗!\n"); exit(0); } pn=pn2; strcpy(pn[cnt],input); 【ただし、cntは毎回1づつ増加する。】 【inputはchar型の配列で、なんらかの文字列がはいっている。】 としているのですが、これもキャストの仕方がわかりませんし、strcpyで、セグメンテーションフォルトになります。構造体を使ったリスト形式も考えたのですが、reallocの使いかたを覚えたいのであえてこの形式で実現しようとしています。 結局どうしたいかというと、realloc部をforループさせて、cntを1ずつ増加させ、 pn[1][20] つぎは pn[2][20] つぎは pn[3][20] とどんどん増やしていきたいわけデス。 すこしわかりにくい説明だとおもいますが、不明点や、言い回しがオカシイ箇所があればご指摘下さい。

  • ポインタを用いてドット演算子で表示させる方法について

    普通、下記のような処理の場合sp->noで表示させるのですが、ドット演算子を用いても表示できると聞きましたので試してみましたが無理でした。どうすればいいでしょうか? #include<stdio.h> struct list{ int no; }list={1}; void main(void) { struct list *sp; sp = &list; printf("sp = %d\n", sp->no);//OK printf("sp = %d\n", (*sp).no);//NG }

  • ポインタについて

    #include <stdio.h> int main( void ) { intx; printf("x = %p\n", &x); printf("x = %d\n", &x); printf("x = %p\n", x); printf("x = %d\n", x); return 0; } 一応僕が使っている参考書によると printf("x = %p\n", &x); はxのアドレスを表示するようですが 他の三つは何を表示するのでしょうか? よければ詳しい説明をつけてくれるとうれしいです (~が~だから~と表示される)みたいなかんじで お願いします

専門家に質問してみよう