2017-07-15 21 views
1

誰かがなぜ次のコード6の出力は5ではないのですか?私はhooの呼び出しがm-> xの値をどのように変更したか理解していません。 コードを実行した後でも、各ステップを実行した後でさえ、依然として私には分かりません。構造体とポインタ。不明な出力

#include <stdio.h> 
#include <stdlib.h> 

typedef struct a { 
    int x; 
    struct a* next; 
}a_t; 

a_t* foo() { 
    a_t* varp, var = { 5,NULL }; 
    varp = &var; 
    return varp; 
} 

a_t* hoo() { 
    a_t* varp, var = { 6,NULL }; 
    varp = &var; 
    return varp; 
} 

void main() 
{ 
    a_t* m = foo(); 
    hoo(); 
    printf("%d", m->x); 
} 
+1

コードは未定義の動作です。 – tilz0R

+1

'var.x'は' foo'の外側では無効です。 – BLUEPIXY

+1

関数からローカル変数を返すことができないためです。ポインタは、アクセスしようとすると割り当てが解除されたデータを指します。 SOには多くの重複があります。 –

答えて

2

あなたの機能hoofooは*の定義により、未定義behavior`あるローカル変数へのポインタを返すされています。

これらはどちらも異なる構造(2つのコピー)を実装しており、最初のものから値を印刷しています。

最初に関数fooをスタックに作成したので、同じ場所のスタック上に関数hooも作成されていて、幸運でした。

したがって、オーバーライドしました。

関数からポインタを返す場合はstaticを使用するか、mallocを使用してヒープに動的にメモリを割り当てます。

a_t* foo() { 
    a_t* varp = malloc(sizeof(*varp)); 
    varp->m = 5; 
    return varp; 
} 

void main() 
{ 
    a_t* m = foo(); 
    hoo(); 
    printf("%d", m->x); 
    free(m); 
} 

ここでは、スタック外にメモリを割り当てています。これは、期待どおりに動作します。

+0

明確な答えをありがとう。コードは意図的に間違っています、それは私が見つけた練習の一部です。私はちょうど出力のための説明を持っていなかったし、メモリ内で正確に何が起こったのかを知りたがっていました。 – roy360

+0

ローカル変数へのポインタを返すだけでは、定義されていない動作が発生しません。そのようなポインタを間接参照しようとする呼び出し元の試みはすべて行います。 – Peter

+0

@Peterはい、私はあなたに同意します。 – tilz0R

2

コードには未定義の動作があります。なぜか見てみましょう。

a_t* foo() { 
    // creates a variable on the stack 
    a_t* varp, var = { 5,NULL }; 
    // sets address of variable on stack to another variable on the stack 
    varp = &var; 
    // you return that address on the stack 
    return varp; 
} 

a_t* hoo() { 
    // creates a variable on the stack 
    a_t* varp, var = { 6,NULL }; 
    // sets address of variable on stack to another variable on the stack 
    varp = &var; 
    // you return that address on the stack 
    return varp; 
} 

なぜ次のコードが原因でundefined behaviorになるのですか?関数の最後にhoofooを呼び出した後に、自分が所有していない変数(アドレスを含む)を返すことになります。 システムはそのメモリを今所有しています! コンピュータは愚かで、あなたが与えたコマンドを盲目的に実行します。私はmallocを使用して、ヒープへの関数呼び出しの外で保持したい変数を保存しようと考えたと思います。

a_t* foo() { 
    a_t *varp = malloc(sizeof(struct a_t)); 
    varp->x = 5; 
    varp->next = NULL; 
    return varp; 
} 

もう1つ修正できますか?

+0

ありがとう、非常に明確な説明。 – roy360

2

基本的に、hoo()を呼び出すと、fooを使用して変数mに格納する前に、作成したものとは異なるvarpとvarが作成されました。しかし、この新しいvarpは、mのvarpと同じメモリアドレスに作成され、その値を上書きします。

F5を使用して1行ずつ移動し、mainの行に3つのブレークポイントを追加する場合は、変数mにウォッチを追加してからhoo()に移動し、varpに割り当てられたメモリアドレスがあなたがhoo()を残してメインに戻ると、上書きされたmに格納された値が失われます。notice the cursor is still at line 22 and didn't overwrite yet

+0

ありがとうございます!私はそのことから多くを学んだ – roy360

0

"static var ..."を定義できます。 varは関数が返ってもまだ生きています。