• ベストアンサー

文字列配列を動的に割り当てるアルゴリズムはこのようなものであっていますか?

結果的に char strs[10][10]; と同じ領域を確保しようというものです。 ちなみにコンパイル時に warning C4700: local variable 'strs' used without having been initialized という警告がでますが、きちんと動作します。 この警告の意味することがわからないのと、今回のようなアルゴリズムとして適当なものであるのか教えてほしいです。 ↓以下ソース↓ #include <stdio.h> #include <stdlib.h> int main(){ char **strs; *strs = (char *)malloc(10); for( int i=0 ; i < 10 ; i++ ){ strs[i] = (char *)malloc(10); } strs[0] = "maiueo"; strs[1] = "kakiku"; printf("%s", strs[0] ); printf("%s", strs[1] ); for( int i=0 ; i < 10 ; i++ ){ free(strs[i]); } free( *strs ); return 0; }

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

>*strs = (char *)malloc(10); の部分strs は、ポインタへのポインタですけど、 その指し示すポインタがありません。(なので初期化せずに使っていると怒られます) >strs[0] = "maiueo"; >strs[1] = "kakiku"; mallocで確保したのとは別のポインタが代入されているので、 このあとのfree が(正常には)できません。 以上に注意して書き直したもの ---------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> int main(){ char **strs; strs = (char **)malloc(sizeof(char*)*10); for( int i=0 ; i < 10 ; i++ ){ strs[i] = (char *)malloc(10); } strcpy(strs[0],"maiueo"); strcpy(strs[1], "kakiku"); printf("%s\n", strs[0] ); printf("%s\n", strs[1] ); for( int i=0 ; i < 10 ; i++ ){ free(strs[i]); } free( strs ); return 0; }

ggaogg
質問者

お礼

ソースありがとうございます。 や、やっと理解できました。 ソースを見ながら考えて、やっとこさわかりました。 概念としては strs (char *)[0]--"string" (char *)[1]--"string" (char *)[2]--"string" (char *)[3]--"string" といったかんじでしょうか。 しかし、よくよく考えてみると、私のソースでも (char **)strs ↓(アドレス) (char *)[0]--"string0" (char *)[1]--"string1" (char *)[2]--"string2" (char *)[3]--"string3" となり、この場合[0]を開放すると、"string0"の領域のみが開放されるのであり、[0]はいぜんとして(char *)のままだと思います。よってstrs領域は開放されないままであり、最後にfree(strs)としても成功するような気が。 それでも警告をださずにコンパイルするとなると、BLUEPIXYさんの示してくれたソースのようにする以外はなさそうですが、、、 私の考えはいぜんとして間違ったままでしょうか?

その他の回答 (3)

  • rickky
  • ベストアンサー率66% (2/3)
回答No.4

buf[10][10]ではわかりにくいので、  char buf[100][80]; で説明します。 「配列へのポインタ」を1個宣言します。  char (*p)[80]; malloc関数で領域を取ります  p = (char (*)[80])malloc(100*80); そうすれば、   p[1][2]='A'; などのように、ご自由にお使い下さい。 プログラムの中で、 strs[0] = "maiueo"; strs[1] = "kakiku"; このような代入をしたいのであれば、それは「ポインタ配列」宣言です。 char **strs; strs = (char **)malloc(10*sizeof(char *)); strs[0] = "ABCDE"; strs[1] = "FGHIJ"; 普通は、 strs[0] = (char *)malloc(計算された文字数); のように、さらにmalloc関数を使います。 (1文字1バイトの場合)。

ggaogg
質問者

お礼

p = (char (*)[80])malloc(100*80); こ、こんな使い方もできるんですね・・。 なんとなく読むことくらいはできるのですが、こんな表現はじめて見ました。 これで素直にp[0]からp[n]まで100個ずつ割り当てられるなんて~すごい。 ちょっと私のレベルを超えた表現みたいですが、参考になりました。ありがとうございます。 それと、 strs[0] = "maiueo"; としてたのは、私のよく犯すミスで、本当はstrcpyでコピーしたような感じを頭で思い描いてソースかいていたりします・・。 質問でまぎらわしい間違いをしてすみませんでした。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

>この場合[0]を開放すると、… #1で言う、「その指し示すポインタがありません。」は、 >*strs = (char *)malloc(10); で、確保された領域のアドレスはどこに格納されているのか? ということが問題です。 例えば、 char area1[10]; char *p1; の時 p1=&area1[0]; とか p1=area1; とするわけですが、この場合は、 area1[10]の領域の先頭アドレスがポインタp1 に格納されるワケです。 ここで、 char **pp1; とした場合、 pp1=&p1; とした場合は、 *pp1=area1; は、p1=area1 と同じ意味になりますが、 pp1=&p1; とせずに *pp1=area1; とすると、まだその指している場所(先述で言うとp1 にあたる)がありません。 by the way... 「このあとのfree が(正常には)できません」ですが strs[0] = (char *)malloc(10); とした場合、strs[0] には、malloc で確保した領域のアドレスが入っています。 これは、 free(strs[0]) で解放できます。 が、しかし strs[0] = "maiueo"; とした場合には、strs[0] には、定数としてあらかじめ確保された領域のアドレスが設定されているのであって free("maiueo"); ができないように strs[0] = "maiueo"; としてしまったら free(strs[0]) ; とはできません

ggaogg
質問者

お礼

あ、なるほど。 そもそもstrcpyを使ってコピーするということを忘れてたんですね。 char **ppstr; があって *ppstr = (char *)malloc( 10 ); としたのでは、最終的に指し示す部分に割り当てられるのに対して ppstr = (char **)malloc( (char *) * 10 ); とすれば、2次元配列の列を割り当てることができる、ということだったんですね・・。 ありがとうございます。頭スパークしてたみたいで、こんな単純なことがわからなかったみたいです。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

#1の方の指摘されている内容以前に.. > char strs[10][10]; ということであれば、 char (*strs)[10] = malloc(sizeof(char[10][10])); ではないでしょうか?

ggaogg
質問者

お礼

回答どうもです。 いまだに#1の方の書いてある内容が把握できず考え中なのですが、動的に割り当てるのは使用するメモリは極力抑えておいて、必要になったら後から付け足していくためのものなので、列と番を同時に宣言しては意味がないのです。 例えば、 (char *)[0] (char *)[1] . . (char *)[50] といったかんじでメモリ確保しておき、必要になったらそれぞれをそれぞれの長さでメモリ確保する必要があるので。

関連するQ&A