お世話になります。
メモリ領域の確保の仕方とポインタの動向についての質問です。
呼び出し側の関数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つの違いがどのくらいあるのかお教えいただけたら
助かります。
よろしくお願いします。
No.3ベストアンサー
- 回答日時:
メモリリークしています。
> //作業用に領域を広げる
> 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);
}
御回答頂いた内容でずいぶんすっきりしました。
> sagyodata_p = (DATA*)malloc(sizeof(DATA)*a);
によって,以降(せっかく渡された)dataの指すオブジェクトではなく
新たに確保された領域に対して操作することになります。
sagyodata_p=data;で作業領域はdataを指すけれども
関数testによって新たに追加された領域は
現状たまたまうまくいっているようにみえるだけで
実際どこに確保されるかは分からないということですね。
分かりやすい御回答どうもありがとうございました。
No.5
- 回答日時:
失礼。
ANo.4の下から3行目を修正します。> memcpy(data, temporary, sizeof(DATA) * temporarySize);
memcpy(data, temporary, sizeof(DATA) * datacount);
No.4
- 回答日時:
条件は次の通りでよろしいですか?
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を使う)
記述することにしました。
お力添え大変ありがとうございました。
No.2
- 回答日時:
このプログラムよく見たら、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()する可能性が有りそうです。
No.1
- 回答日時:
っていうか、realloc()の返却値はエラーチェックした方が良さそうです。
realloc()すれば、mallocした後、元の領域からコピーする手間が減るんじゃないですか?
参考URL:http://www9.plala.or.jp/sgwr-t/lib/realloc.html
早速の御回答どうもありがとうございます。
参考URL拝見しました。
成功してもアドレスが同じだとは限らないのですね・・・
>realloc()すれば、mallocした後、元の領域からコピーする手間が減るんじゃないですか?
元々作業領域のサイズを変えずに書いていたコードだったので
コード記述上sagyodata_p = data;としていました。
No2に書いていただいた内容を自分でもう一度考えて見たいと思います。
test(DATA data[],long datacount)の引数型が現状変更できないのです。
後ほど補足させて頂くかも知れませんが、そのときにお時間が許せば
再度お力をお貸しいただけたら幸いです。
どうもありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
int型(2バイト)データの分割
-
PICNICのVB制御プログラム
-
stable diffusionのエラー
-
ポインター引数の関数でコンパ...
-
c言語の多次元配列で1から100ま...
-
POSTで配列のデータを渡す方法は?
-
C#でのswitch文
-
エクセルVBA:日付データの変換...
-
値によって組み分けを作成する...
-
パイプを用いたプロセス間通信...
-
C言語についてです! 同じ年の...
-
エクセルシート名の制限を変更...
-
10Mバイトて文字数に すると何...
-
CGIを勉強しています。¥n(改...
-
ListView重複データ削除
-
Javaで日本語1文字のバイト数
-
UTF-8で5~6バイトになる文字コ...
-
VB.NET LeftBの代用
-
Excel VBA メール作成について ...
-
【VB2005】テキストボックス内...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ポインター引数の関数でコンパ...
-
stable diffusionのエラー
-
printfの%eで指数部分の桁数を...
-
エクセルVBA:日付データの変換...
-
int型(2バイト)データの分割
-
【Excel VBA】10進数を2進数に...
-
C#でのswitch文
-
C言語についてです! 同じ年の...
-
pythonでDBのカラム名で取得し...
-
PINVOKEで構造体配列をマーシャ...
-
MySQLに登録すると文字化け
-
C言語 ファイル内のデータと入...
-
CreateProcessでの環境変数の設...
-
'dataType' 引数を Null にする...
-
linuxのシェルでファイル名に先...
-
Cのプログラムがどうしても動き...
-
POSTで配列のデータを渡す方法は?
-
マクロ登録したピボットが重い...
-
gnuplotの出力グラフ名を外部で...
-
離散フーリエ変換のプログラム...
おすすめ情報