[C]関数から返したアドレスを後から参照すると値がおかしい
現象
C言語で関数(func_a)を作成。引数の内容をもとにある構造体のインスタンスを作成し、そのアドレスを返す。
そのアドレスはその後別の関数(func_b)の引数に使用。アドレスを参照し、func_aで作成した構造体の内容をもとに規定の処理を行う。
typedef struct {
int a;
int b;
}SAMPLE_STRUCT
SAMPLE_STRUCT* func_a(int a, int b){
SAMPLE_STRUCT s;
s.a = a;
s.b = b;
return &s;
}
void func_b(SAMPLE_STRUCT *smpl){
int a =(*smpl).a; //aの値がおかしい
}
func_bでメンバaの値を取り出すと、func_aで設定したのと異なる値が入っている。
問題:上記コードでどこがおかしいでしょう?
原因
答え:関数(func_a)のローカル変数として確保したアドレスを返しているから。
関数のローカル変数はスタックに取られる。そのアドレスを後から参照しても、スタックは別の関数でも使われているから、そのアドレスに格納されている値は順次変更される。
解決策
1 構造体そのものを返す
2 mallocなどでヒープに確保した変数のアドレスを返す
3 グローバル変数として確保した変数のアドレスを返す
SAMPLE_STRUCT* func_a(int a, int b){
SAMPLE_STRUCT *s =
(SAMPLE_STRUCT *)malloc(sizeof(SAMPLE_STRUCT));
s->a = a;
s->b = b;
return s;
}
最後に
メモリをちゃんと理解していないとこういうミスが起こるんですね
最新記事
すべて表示やりたいこと 2次元配列に作用する処理がある 処理の対象となる配列が複数ある このような場合、この処理は関数化したいが、引数をどう定義するのかちょっと迷った やり方 配列サイズは固定とすれば、以下のようにすればよい // Define a typedef for the...
やりたいこと 掲題の通りだが、関数ポインタの配列を定義したい。 具体的にどう使うかというと、例えばpthread_createの第3引数は新規スレッドで実行したい関数のポインタを渡す。複数の関数に対してそれぞれ新規スレッドを割り当てる場合、それらのポインタを配列にしてまとめ...
Bình luận