- ベストアンサー
二次元文字列をポインタで操作するには
お世話になります、フジと申します。今回皆様にお聞きしたいことは、かなり基本的な部分なのですがどうしても理解できず質問させて頂きます。 まず以下のようなプログラムを作成しました。 char *data[10]; void func(char* d) { static int i=0; data[i] = d; i++; } int main(void) { int i = 0; char a[10]; while(1){ if(i>2)break; if(i==0) strcpy(a,"Hello"); if(i==1) strcpy(a,"Morning"); if(i==2) strcpy(a,"Night"); func(a); i++; } i = 0; while(1){ if(i>2)break; printf("data is %s\n",data[i]); i++; } return 0; } すると出力されるdata[]の値は全て"Night"になります。これはポインタを使っているから当たり前だと思います。 これをどうにしかして上のようにポインタを用いて, data is Hello data is Morning data is Evening と出力させることが出来ないでしょうか? 大変基本的な部分とは思いますが、宜しくお願い致します。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
結局、data[0]もdata[1]もdata[2]も、aのポインタを指しているので、aに最後に入ってた文字列「Night」が表示される。 data配列が指す文字列を書き換えないなら、 char *data[10]; void func(char* d) { static int i=0; data[i] = d; i++; } int main(void) { int i = 0; char *p; while(1){ if(i>2)break; if(i==0) p="Hello"; if(i==1) p="Morning"; if(i==2) p="Night"; func(p); i++; } i = 0; while(1){ if(i>2)break; printf("data is %s\n",data[i]); i++; } return 0; } data配列が指す文字列を書き換える可能性があるなら、 char data[10][10]; void func(char* d) { static int i=0; strcpy(data[i],d); i++; } int main(void) { int i = 0; char *p; while(1){ if(i>2)break; if(i==0) p="Hello"; if(i==1) p="Morning"; if(i==2) p="Night"; func(p); i++; } i = 0; while(1){ if(i>2)break; printf("data is %s\n",data[i]); i++; } return 0; } となる。 ここで注意しないとならないのは「charポインタの配列と、charの2次元配列は、まったくの別物」って事。 これは「charポインタと、charの配列は、まったくの別物」ってのと同じ。 「charポインタは文字列はどっか別のトコにあるが、charの配列には文字列が入ってる」と言う違いがあるのは判ると思う。 同様に「charポインタの配列は文字列はどっか別のトコにあるが、charの2次元配列には文字列が入ってる」と言う違いがある。 「charポインタの配列」で、つまり「char *data[10]」って書きたいなら「文字列は、すべて、別々の場所に格納されてるのを、それぞれ用意しないとならない」って事。 質問者さんのプログラムは「別々の文字列を、毎回、a配列に格納し、data[0]もdata[1]もdata[2]も、a配列を指すようにしている」ので、結局は char *data[10]; int main(void) { int i = 0; char a[10]; strcpy(a,"Hello"); data[0]=a; strcpy(a,"Morning"); data[1]=a; strcpy(a,"Night"); data[2]=a; printf("data is %s\n",data[0]); printf("data is %s\n",data[1]); printf("data is %s\n",data[2]); return 0; } というプログラムと等しい。 strcpy処理と、data配列にaを代入する処理には、依存関係は無いから、順序を入れ替えても同じ。つまり char *data[10]; int main(void) { int i = 0; char a[10]; strcpy(a,"Hello"); strcpy(a,"Morning"); strcpy(a,"Night"); data[0]=a; data[1]=a; data[2]=a; printf("data is %s\n",data[0]); printf("data is %s\n",data[1]); printf("data is %s\n",data[2]); return 0; } と同じ。この時、 strcpy(a,"Hello"); strcpy(a,"Morning"); は strcpy(a,"Night"); で上書きされるので無いのと等しい。最終的には char *data[10]; int main(void) { int i = 0; char a[10]; strcpy(a,"Night"); data[0]=a; data[1]=a; data[2]=a; printf("data is %s\n",data[0]); printf("data is %s\n",data[1]); printf("data is %s\n",data[2]); return 0; } と同じになる。 これじゃ「Nightが3回表示されて当然」でしょう。
その他の回答 (1)
- php504
- ベストアンサー率42% (926/2160)
while(1){ if(i>2)break; if(i==0) func("Hello"); if(i==1) func("Morning"); if(i==2) func("Night"); i++; }
お礼
変数を間にはさまず、直接ポインタ配列に代入すると出力されるのですね。 ありがとうございます。
お礼
とても分かりやすい説明ありがとうございます。 私は完璧にcharポインタの配列は二次元の文字列配列の別の表現の方法だと勘違いしていました。 確かに、ポインタを外部関数の引数にした場合に、返り値なしで、値の変化が反映されるという考えから考えても、何か違うんじゃないかと思っていました。 今回の件で、配列とポインタの違いをさらに認識できました。本当にありがとうございました。