- ベストアンサー
char *data[20]; のデータの行方
ファイルからデータを1行ずつ読み取り、 その行をコンマで分割して 1行毎の一時保管にこのchar型ポインタの配列を使っているのですが、 この場合データはどうなるのでしょうか? 以前、 >char *p = "文字列"; >等とすると、そのデータはメモリのどこかに静的に置かれてしまう >constを付けて保護しなければならない。 的な注意を見たのですが 1.この使い方は危険なのでしょうか? 2.ポインタで受け取ると、全ファイル分のデータが静的メモリとして どこかに漂ってしまったりするのでしょうか? わかる方、いらっしゃいましたら教えて下さると幸いです。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
#3のzwiですが、心配した通りポインタとメモリ実体の把握が曖昧な様です。 token = strtok_s(buff, DELIMITER, &nexttoken); で得るtokenですが、あくまでも文字列のポインタだけです。 なので、実際の文字列は char buff[256]; のbuffに記録されいます。 で、 data[count] = token; と代入していますが data配列に記憶されるのも文字列のポインタだけで実体はbuff上です。 問題なのは、 /* ここでdata[n]を別の受け皿へ代入し、保存しています */ とありますが、data配列の中身をコピーしただけでは文字列の実体はそのままbuffに残されていますので、次にfgetsされた場合はbuffの内容は書き換わりますので、保存しておいた前のdata[n]が指すべき文字列は上書きされて無くなってしまいます。 なのでデータとして保存するには、 #define KEEPLINE 2000/*保存行数を2000行と仮定*/ char *keepdata[KEEPLINE][20];//tokenの保存。 int keepcount[KEEPLINE];//カウントの保存。 int keepdata_num = 0; int i; /* ここでdata[n]を別の受け皿へ代入し、保存しています */ for( i=0 ; i<count ; i++ ) { //文字列コピー用のバッファのサイズを求める。 int mojilen=strlen(data[i])+1;//一を足すのは文字列の終端コード(\0)の分。 //まず文字列をコピーするメモリを確保。mallocしたメモリはプログラム終了時に必ずfreeする事。 keepdata[keepdata_num][i] = (char*)malloc(mojilen); //文字列をコピーする。 strcpy_s(keepdata[keepdata_num][i],mojilen,data[i]; } keepcount[keepdata_num] = count; keepdata_num++; 以上です。 あとバグですが、countをfgets毎にクリアしてくださいね。
その他の回答 (8)
- titokani
- ベストアンサー率19% (341/1726)
>以前、 >>char *p = "文字列"; >>等とすると、そのデータはメモリのどこかに静的に置かれてしまう >>constを付けて保護しなければならない。 >的な注意を見たのですが これは、「文字列リテラル」を扱う際の注意事項です。ポインタで受け取る云々とは別の話。 なので、 >2.ポインタで受け取ると、全ファイル分のデータが静的メモリとして > どこかに漂ってしまったりするのでしょうか? もちろん、こんなこともありません。
お礼
なるほど。 ""で囲った文字列そのものの行方の話だったのですね。 ありがとうございます。
- Tacosan
- ベストアンサー率23% (3656/15482)
とりあえず #3 のプログラム中の「fgets ごとに count をクリアしなきゃならない」は while じゃなくて for にすれば解決しますね. token = strtok_s(buff, DELIMITER, &nexttoken); for (count = 0; data[count] = token; ++count) { token = strtok_s(NULL, DELIMITER, &nexttoken); } という感じ. もともと count を定義したところで 0 に初期化するだけというのが問題で, 使う直前に初期化することにすれば (今の場合は) 解決する.
お礼
forでもいけるのですね。 他の問題があるとできるだけ他のコードは触らないようにしてしまい; ご助言ありがとうございました。
- asuncion
- ベストアンサー率33% (2127/6289)
>とりあえず、データの受け皿はポインタでは危険なのですね。 そんなことはないでしょう。 プログラムのつくりによります。
お礼
「ポインタが指すデータが上書きされていないか」 をちゃんと意識して作れば問題ないのですよね; そうなれるよう頑張ります。 ありがとうございました
- asuncion
- ベストアンサー率33% (2127/6289)
>char data[10][20]; の受け皿に >data[count] = (char)token; で受け取ろうとして出ました。 >(charからchar[20]に変換できません のエラー) strcpy(data[count], token);
お礼
そのままではアドレスの文字に対する変換になるのですね; strcpy strcpy_s atoi atofで移すようにしました。 有難うございます。
- SilverThaw
- ベストアンサー率32% (260/806)
No.1お礼について >ポインタが指す実体は毎回どこに置かれているのやら・・。 メモリ上の「どこか」にあります。 それと、 >そして早速、 >char型の2次元配列に、charポインタ型が指すデータの代入をしようとしたものの >charからchar[20]に変換できない等エラーが出て上手く行かず。。 >charのポインタからの型変換方法から調べなおしかな・・ と、質問文 >1行毎の一時保管にこのchar型ポインタの配列を使っているのですが、 からだと、いろいろと別の問題てもあるようですので、そのエラーが出るソースを開示してみてください。
お礼
>いろいろと別の問題てもあるようですので、そのエラーが出るソースを開示してみてください。 このエラーは char *token; が受け取る分割した部分のデータを 元のソースでは char *data[10]; の受け皿に data[count] = token; で受け取っていたのを char data[10][20]; の受け皿に data[count] = (char)token; で受け取ろうとして出ました。 (charからchar[20]に変換できません のエラー)
- zwi
- ベストアンサー率56% (730/1282)
char *data[20]; だとポインタ変数が確保されただけですね。 なのでdataは未知のアドレスを指しています。 1.この使い方は危険なのでしょうか? 宣言自体は問題ないですが、ポインタ値(=アドレスが未定義)なのが問題です。 >charのポインタからの型変換方法から調べなおしかな・・。 かなり無茶な事をしてる気配なのでプログラムを載せてもらった方が的確にアドバイスできます。 2.ポインタで受け取ると、全ファイル分のデータが静的メモリとして どこかに漂ってしまったりするのでしょうか? いえ、もし動いたとしたら何処かの書き変えてはいけないメモリの内容を書き換えてしまっています。偶然動き続けえることはありますが、データ化け等の問題なく動くことはありえません。
お礼
>もし動いたとしたら何処かの書き変えてはいけないメモリの内容を >書き換えてしまっています。偶然動き続けえることはありますが、 >データ化け等の問題なく動くことはありえません。 そうなのですね・・。そこまで危険なのですね。 >プログラムを載せる ほぼWebに有ったサンプルそのままですが -------------------------------------- #define DELIMITER "/ ," char buff[256]; char *token, *nexttoken; char *data[10]; int count = 0; FILE* pFile; fopen_s(&pFile, "skin.txt", "r"); if ( !pFile ){ return; } while (fgets(buff, 256, pFile) != NULL) { token = strtok_s(buff, DELIMITER, &nexttoken); while (token != NULL) { data[count] = token; token = strtok_s(NULL, DELIMITER, &nexttoken); count++; } /* ここでdata[n]を別の受け皿へ代入し、保存しています */ } fclose(pFile); -------------------------------------- といった感じになっています。
- Tacosan
- ベストアンサー率23% (3656/15482)
ポインタしか確保してないので, 「データがどこにあるか」という情報は持ってるけど「実際のデータ」は持ってません. ということで, 具体的な処理によって OK とも NG ともいえます. たとえば, 各行をコンマで分割したそれぞれのトークンを持つだけなら (データそのものをきちんと配列なり malloc でとってきたところなりに入れているという前提で) うまくいきます. もちろん「malloc などによるメモリの確保をせず, いきなりファイルから読み込む」とかやると大体アウト. それにしてもどこから「20」が出てきたんだろう.
お礼
20は1行あたりの分割数として でした。 >各行をコンマで分割したそれぞれのトークンを持つだけなら (中略) うまくいきます Webで見つけたサンプルから取り込み、質問点の疑問を抱いて その範囲の利用に留めているので、恐らく、ここまでなら安全なのですね。 >具体的な処理によって OK とも NG ともいえます >「malloc などによるメモリの確保をせず, いきなりファイルから読み込む」とかやると大体アウト. ここはおそらく自分に足りない知識が有るのでしょう、 まだうまく理解できないようです; あまり・・シンプルな問題では無さそうですね。 ご回答、ありがとうございました。
- wolf03
- ベストアンサー率22% (241/1086)
char型ポインタが20個確保されるだけ。 其のまま使えばエラーになるか暴走するかは状況次第。 1行分が収まるだけのメモリを確保、ポインタへセットを20回やらないと駄目。 最後に開放も忘れない事。
お礼
暴走する可能性も有るのですね・・。 ポインタが指す実体は毎回どこに置かれているのやら・・。 そして早速、 char型の2次元配列に、charポインタ型が指すデータの代入をしようとしたものの charからchar[20]に変換できない等エラーが出て上手く行かず。。 charのポインタからの型変換方法から調べなおしかな・・。 とりあえず、データの受け皿はポインタでは危険なのですね。 ご回答ありがとうございました
お礼
手前で送ったコードのバグ、失礼しました。 関係ない仕様や試行錯誤中のログ消して貼ったらうっかりしたようです。 そしてサンプルありがとうございます。 コードを参考にさせて頂き、 構造体の受け皿に全てデータをポインタじゃない形で移し込む形にしました。 有難うございました。