- ベストアンサー
メモリ領域の確保の仕方
お世話になります。 メモリ領域の確保の仕方とポインタの動向についての質問です。 呼び出し側の関数testで領域Aを確保する。 関数test内で確保した領域に作業領域Bを加え作業をする。 関数testを抜けるときにreallocで呼び出し側から得た サイズに領域Aを戻す。 このときの動作についてなんですが //呼び出し側 void Main(){ DATA *data_p;//データ構造体 long datacount = 5;//データ数(5はテスト用の可変値 data_p = (DATA*)malloc(sizeof(DATA)*datacount); test(data_p,datacount); free((void*)(data_p); } //関数test test(DATA data[],long datacount){ DATA *sagyodata_p; long a = datacount+5; sagyodata_p = data; //作業用に領域を広げる sagyodata_p = (DATA*)malloc(sizeof(DATA)*a); //領域サイズを戻す realloc(((void*)sagyodata_p),sizeof(DATA)*datacount); } としたときに 関数testでdata_pを参照したポインタsagyodata_pの中身は問題ないでしょうか? 現在の実行環境 .NET2003 C++では問題なく動いているようですが。 sagyodata_p = data; sagyodata_p = (DATA*)malloc(sizeof(DATA)*a); とするより、 realloc(((void*)data),sizeof(DATA)*a); としたほうがよいのでしょうか? この2つの違いがどのくらいあるのかお教えいただけたら 助かります。 よろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
メモリリークしています。 > //作業用に領域を広げる > sagyodata_p = (DATA*)malloc(sizeof(DATA)*a); によって,以降(せっかく渡された)dataの指すオブジェクトではなく 新たに確保された領域に対して操作することになります。 しかも,freeしていません。 渡されたdataのサイズを変更したいのであればdataをreallocしましょう。 現状,Mainで確保したdata_pはtest使われずにそのままfreeされています。 ・キャストについて void*へのキャストは冗長なだけです。 # その逆はC++のことを考えるとしてもいいかも。 #include<stdlib.h> typedef int DATA; // 構造体の代わり void test(DATA ** data, long datacount){ long a = datacount + 5; void * tmp; //作業用に領域を広げる if ((tmp = realloc(*data, sizeof(DATA)*a)) == NULL){ return; // 適当に復旧 } *data = tmp; // ここでdataをごにょごにょ // : //領域サイズを戻す if((tmp = realloc(*data, sizeof(DATA)*datacount)) == NULL){ return; // 適当に復旧 } *data = tmp; } int main(void){ DATA *data_p; long datacount = 5; data_p = malloc(sizeof(DATA)*datacount); test(&data_p, datacount); free(data_p); }
その他の回答 (4)
失礼。ANo.4の下から3行目を修正します。 > memcpy(data, temporary, sizeof(DATA) * temporarySize); memcpy(data, temporary, sizeof(DATA) * datacount);
条件は次の通りでよろしいですか? 1.test関数の型は変更できない。 2.dataが指すDATA構造体(の配列)には変更を加える。 3.testを呼ぶ前とmainに帰ってきたときのサイズ(配列の要素数)は同じ だとしたらreallocを使わずにすみ, めんどくさい事(ポインタの書き換えとか)を一切する必要がなくなりますね。 #include<stdlib.h> #include<string.h> typedef int DATA; void test(DATA data[], long datacount){ const int temporarySize = datacount + 5; DATA * temporary = malloc(sizeof(DATA) * temporarySize); if (!temporary)return; memcpy(temporary, data, sizeof(DATA) * datacount); // ここでtemporaryをごにょごにょする memcpy(data, temporary, sizeof(DATA) * temporarySize); free(temporary); }
お礼
たびたびの御回答ありがとうございます。 その後考えた結果RISKさんと同じ方法で (memcpyを使う) 記述することにしました。 お力添え大変ありがとうございました。
- t_nojiri
- ベストアンサー率28% (595/2071)
このプログラムよく見たら、realloc(((void*)sagyodata_p),sizeof(DATA)*datacount); が、sagyodata_pと同じアドレス返却してるから、たまたま動いてるけど正しくは //呼び出し側 void Main(){ ・・・ test(&data_p,datacount); free((void*)(data_p); } //関数test test(DATA **data,long datacount){ ・・・ *data = realloc(((void*)*data ),sizeof(DATA)*datacount); } #必要部分しか書いてません。 ってしないと、変な所free()する可能性が有りそうです。
- t_nojiri
- ベストアンサー率28% (595/2071)
っていうか、realloc()の返却値はエラーチェックした方が良さそうです。 realloc()すれば、mallocした後、元の領域からコピーする手間が減るんじゃないですか?
お礼
早速の御回答どうもありがとうございます。 参考URL拝見しました。 成功してもアドレスが同じだとは限らないのですね・・・ >realloc()すれば、mallocした後、元の領域からコピーする手間が減るんじゃないですか? 元々作業領域のサイズを変えずに書いていたコードだったので コード記述上sagyodata_p = data;としていました。 No2に書いていただいた内容を自分でもう一度考えて見たいと思います。 test(DATA data[],long datacount)の引数型が現状変更できないのです。 後ほど補足させて頂くかも知れませんが、そのときにお時間が許せば 再度お力をお貸しいただけたら幸いです。 どうもありがとうございました。
お礼
御回答頂いた内容でずいぶんすっきりしました。 > sagyodata_p = (DATA*)malloc(sizeof(DATA)*a); によって,以降(せっかく渡された)dataの指すオブジェクトではなく 新たに確保された領域に対して操作することになります。 sagyodata_p=data;で作業領域はdataを指すけれども 関数testによって新たに追加された領域は 現状たまたまうまくいっているようにみえるだけで 実際どこに確保されるかは分からないということですね。 分かりやすい御回答どうもありがとうございました。