- ベストアンサー
C言語にて ポインタ渡しで数値が消えてしまう
すいません。構造体に入力した値が消えてしまうため、困っています。 分かる方がいらっしゃいましたら、アドバイスをください。 C言語で作図を作成するつもりでPGをはじめました。 情報の関係から、構造体を作成しました。 struct CLS{ int Snsr[2]; : float *Data; //:数値配列へのポインタ };DataGrp (Str1はグローバル変数です) main関数とは別の関数から構造体の数値配列に数値を入力させました。 入力させる関数定義 void PickUpData(float inputData,struct CLS *Str1){ : Str1->Data[1]=inputData; (<-値代入) } main関数内のPG main(){ : PickUpData(inputData,&Str1); printf("%f",Str1.Data[1]); //1回目の内容確認 printf("%f",Str1.Data[1]); //2回目の内容確認 } 1回目の内容確認部では、ちゃんとinputDataの値が入力されていたのですが、2回目の内容確認部では、値が0になっていました。ちなみに1回目と2回目は立て続けに行いました。(inputDataが消えていた)。原因がよくつかめず、考えてしまいました。もし分かる方がいらっしゃったら、アドバイスを下さい。宜しくお願い致します。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>領域確保は、sizeof(float)*40 位で記述した それ(malloc()の引数)を定数で確保したのならそれを信用する限り大丈夫そうですね。何か変数が入っている式だとすれば、本当にその式の値がsizeof(float)*40くらいになっているのか確認する必要があります。 >実際にはどのように確認すればよろしいのでしょうか?『実際、2つ分のアドレスがNULLでないか』のような確認でいいのでしょうか? コード上でかんたんに確認できるのはmalloc()の返値がNULLでないかどうかくらいまでです。サイズは(標準的な方法で)簡単にはわからないと思います。その意味でmalloc()の引数が正しいことを確認するのは重要です。 (参考:size_t malloc_size(void *)などのインタフェースを持つシステムなら簡単に確認できますが、一般にあるとは限りません。その他、ヒープの管理領域をのぞくとか引き続きのmalloc()で確保されたアドレスとの差分をみるとかdmallocなどのデバッグ用malloc()を使うとか調べる(or推測する)方法は多々あります。) malloc()の引数が正しい(十分大きい)とすると、あとはそれをどこかで解放(free())してはいないか、という疑いはあります。 机上デバッグするのが正しいと思いますが、仮にグローバル変数として float global_floats[40]; などと定義しておいて、 Str1.Data = (float *) malloc(...); の代わりに Str1.Data = global_floats; としてみることはできますか。 これで通るとしたらどこかでfree()してしまっている可能性があります。(global_floats[]を使うようにした場合、free()では解放できないのでどこかでfree()しようとしてもそれ自体はエラーになり、領域は(当然)解放されずに残ります。) 念のために確認しますけれど、マルチスレッドだったりはしないですよね。
その他の回答 (2)
- dummyplug
- ベストアンサー率58% (134/230)
t4tさんへの補足の中で、malloc()で領域確保していると書いていますが、この領域はきちんとsizeof(float)*2(または2以上)だけとっていますか? おそらく1つ(またはそれ以下)しかとれていないのではないでしょうか。 float *p = (float *) malloc(sizeof(float)); として確保された領域(float一個分)にアクセスするなら p[0] = 3.14; のように添え字は0からスタートです。float一個分しか確保していないのに p[1] = 1.0; のようにアクセスするとそれは使ってはいけない場所にアクセスしていることになります。 今回はたまたまそれでも実行を続けることができて、おそらくprintf()(一つめ)の実行中、内部でmalloc()に相当するheap領域を取得&解放するような処理が行われて(勝手に使っていた)Str1.Data[1]に相当する領域が破壊されたのだと推察します。 きちんと必要なだけの領域(質問のプログラムの場合だとData[0]とData[1]に相当する少なくとも要素2つぶんの領域)が確保されていることを確認してください。
お礼
ご回答ありがとうございます。 >t4tさんへの補足の中で、malloc()で領域確保していると書いていますが、この領域はきちんとsizeof(float)*2(または2以上)だけとっていますか? 領域確保時の戻り値がNULLではなかったこと、領域確保は、sizeof(float)*40 位で記述したので、領域は確保されたものとばかり考えておりました。確かに、領域確保がうまくいっていない可能性もありますね。 すいません、もう一点教えてください。 >きちんと必要なだけの領域(質問のプログラムの場合だとData[0]とData[1]に相当する少なくとも要素2つぶんの領域)が確保されていることを確認してください。 とありましたが、実際にはどのように確認すればよろしいのでしょうか?『実際、2つ分のアドレスがNULLでないか』のような確認でいいのでしょうか?
- t4t
- ベストアンサー率55% (47/84)
グローバル変数のStr1のDataポインタはきちんとfloatの実体を指していますか? 「配列」へのポインタ、とわざわざあるのでご理解なさっているとも思うのですが…。 struct CLS Str1; float floatArray[10]; // 10は例 Str1.Data = floatArray; というようにStr1.Dataをポインタとして最初に初期化しているでしょうか?
お礼
ご回答ありがとうございます。 >グローバル変数のStr1のDataポインタはきちんとfloatの実体を指していますか? 別の箇所なのですが、動的に確保しています。 Str1->Data=(float *)malloc(・・・); 動的確保で領域も確保されていました。
お礼
ご回答、ありがとうございます。 >float global_floats[40]; >などと定義しておいて、 >Str1.Data = (float *) malloc(...); >の代わりに >Str1.Data = global_floats; >としてみることはできますか。 早速行ってみたところ、2回目でも消えませんでした。 どこかで開放されてしまっているようですね。 また、構造体内に struct CLS{ int Snsr[2]; : float *Data; //:数値配列へのポインタ float *Data2; //:数値配列へのポインタ }; とし、mallocの戻り値(アドレス)を確認したところ、127、126といったような連続数値でした。このあたりにも問題があるのかもしれません。 よって、可能性として、『1.確保した領域が開放されてしまっている可能性が高い。』と感じました。もう少し、確認を取ってから閉じたいと思います。ありがとうございました。
補足
すいません。回答者様からの質問にちゃんと答えてなかったので、ここであわせてご報告します。 >念のために確認しますけれど、マルチスレッドだったりはしないですよね。 マルチスレッドではありません。 >Str1.Data = global_floats; >としてみることはできますか。 >これで通るとしたらどこかでfree()してしまっている可能性があります。(global_floats[]を使うようにした場合、free()では解放できないのでどこかでfree()しようとしてもそれ自体はエラーになり、領域は(当然)解放されずに残ります。) やり方がスマートではなかったかもしれませんが、エラーは出ませんでした。たぶん、領域確保の部分でちょっとめんどくさいコードの記述をしていたためと思っています。 領域確保がうまくいっていないことがわかり、ここが原因であることがわかったので、もう少し自分のほうで考えてみたいと思います。 ありがとうございました。