- ベストアンサー
文字列ポインタの配列の扱い方
毎度お世話になります。 構造体のメンバが、文字列ポインタの配列だった場合、それに文字列をコピーすることは可能なのでしょうか? とりあえず下記のように書いてみたのですが、実行エラーで終了してしまいます。 typedef struct data{ char name[30]; int age; char *ss[2]; }DATA; int main() { DATA dt[3] = {{"AA",10}, //ssも初期化出来るのか? {"BB",15}, {"CC",20}}; int i,j; for(i=0;i<3;i++){ for(j=0;j<2;j++) strcpy(dt[i].ss[j],"なし"); //それとも、ここでstrcpyで文字列を入れるのか? } よろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
★strdup() を使えば良いと思います。 >文字列ポインタの配列だった場合、それに文字列をコピーすることは可能なのでしょうか? ↑ 直接コピーは出来ません。文字列ポインタですから。 でも確保された領域がポインタにセットされていればその領域に対してはコピーできます。 ・文字列をコピーではなく文字列領域を確保してからそのポインタをセットすればよい。 方法は malloc() 関数でメモリを確保してから文字列をコピーするか、strdup() 関数を 利用して下さい。strdup() 関数の方が楽ですので紹介します。 サンプル: int main( void ) { DATA dt[ 3 ] = { { "AA", 10 }, { "BB", 15 }, { "CC", 20 }, }; int i, j; for ( i = 0 ; i < 3 ; i++ ){ dt[ i ].ss[ 0 ] = strdup( "なし" ); dt[ i ].ss[ 1 ] = strdup( "なし" ); } : 処理 : /* 必要に応じて ss にセットされた領域を free します。 main() から抜けるだけなら自動的に解放されます。 でも malloc()、free() や strdup()、free() は対で処理した方が良いかな。 */ return 0; } その他: ・構造体の ss に固定の文字列をセットするだけなら直接文字列のポインタをセットできます。 つまりコピーというよりはセット。 dt[ i ].ss[ 0 ] = "なし"; dt[ i ].ss[ 1 ] = "なし"; ↑ これだけでよい。 ・問題は ss のポインタはどのような使われ方をするかです。 最終的にどんな事したいの? そうしないと適切な回答が出せません。 ・以上。補足要求します。
その他の回答 (4)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★どうしても文字列にしたいの? ・回答者 No.3 さんのアドバイスに『列挙型』となっていますがフラグ情報でもいいのでは。 その方が『あり』、『なし』の状態を判定しやすいと思いますけど。 もちろん文字列でも行えますがその場合は同じ『あり』と『なし』の文字列ポインタを 使った方が良いです。つまり、 // 記号定数として定義 #define STR_NO yesno[0] #define STR_YES yesno[1] // あり/なし状態の文字列テーブル static const char *yesno[] = { "なし", "あり", }; int main( void ) { DATA dt[ 3 ] = { { "AA", 10, STR_NO, STR_NO }, ←初期化可能。 { "BB", 15, STR_NO, STR_NO }, { "CC", 20, STR_NO, STR_NO }, }; int i, j; for ( i = 0 ; i < 3 ; i++ ){ // 判定 switch ( dt[i].ss[0] ){ ←ss[0]に対して判定 case STR_NO: /* 『なし』と判定した処理 */ break; case STR_YES: /* 『あり』と判定した処理 */ break; default: /* 設定エラーの処理 */ } } return 0; } その他: ・決まった文字列リテラルを使うことでポインタ値で『あり』、『なし』をチェックできます。 比較や代入は記号定数 STR_NO、STR_YES で行います。 st[n].ss[0] を直接 printf() すれば文字列ですので表示も可能です。 フラグを使っても同じように出来ますがどうしても文字列でセットしたい場合は static const char *yesno[] という決まった文字列を用意して使います。 ・以上。
お礼
確かにフラグでやるのも考えましたが、そっちが完成したので今度は文字列でやろうとしていたのです。 教えていただいたのを参考に、頑張ります。 ありがとうございました。
- mikaemi
- ベストアンサー率50% (33/65)
”あり”か”なし”だけ入れるならポインタの配列のままで、 文字列リテラルのアドレスをそのまま代入するだけでいいでしょう。 そうすれば、メモリリークもないですし。 てか、それなら、”あり”か”なし”かを示す値(列挙型とか)でもいいのか^^
- maku_x
- ベストアンサー率44% (164/371)
こんな感じで書けば、data 構造体のメンバ ss も初期化できます。 int main() { DATA dt[3] = {{"AA",10,{"aa1","aa2"}}, //ssも初期化出来るのか? {"BB",15,{"bb1","bb2"}}, {"CC",20,{"cc1","bb2"}}}; int i,j; for (i=0;i<3;i++) { for (j=0;j<2;j++) { dt[i].ss[j] = "なし"; //それとも、ここでstrcpyで文字列を入れるのか? } } } なお、strcpy は確保されたメモリが無い場合には使えませんので、この場合は直接文字列のポインタを ss に代入します。
お礼
的確なアドバイス、ありがとうございました。
- mikaemi
- ベストアンサー率50% (33/65)
char *ss[2] は文字へのポインタ2つの要素からなる配列です。 領域をとっておいてあげないと strcpy(dt[i].ss[j],"...")は無理ですね。 ss の初期化はできるので、 DATA dt[3] = { { "AA", 10, { malloc(30), malloc(30) } }, { "BB", 15, { malloc(30), malloc(30) } }, { "CC", 20, { malloc(30), malloc(30) } }, }; とかしておきますか?^^ strcpy したいということは、 あとで何か作り出した文字列を入れたいということですよね? わたしなら、NULL で初期化しておいて、 使う段になったらアロケートするか、すでにアロケートしている 文字列のアドレスを入れますけど。 free() し忘れたりしないように…でも、妙なアドレスを free() に 渡すより、メモリリークの方がマシですか?^^
お礼
ご回答ありがとうございます そういうやり方もあるんですね。また一つ勉強になりました。
補足
いつも回答ありがとうございます。 ただ単に、ss[4][10]と二次元配列にしてもいいのですが、*ss[4]も使えるのでなかなか使わない方で試してみようと思っただけなので、ポインタにする必要性は本当はないのですが(汗) ssは、今は"なし"ですが、条件判定で当てはまれば、要素別に"あり"にして"あり"の場合の処理をします。 例えば、 if(flg == 1){ dt[0].ss[0] = "あり"; dt[0].ss[1] = "なし"; dt[0].ss[2] = "あり"; } みたいな感じに使いたいのです。