2017-03-16 9 views
2
#include <stdio.h> 
typedef struct { 
    int data; 
    char * string; 
}Node; 

Node * init(){ 
    Node node; 
    node.data = 5; 
    node.string = "hello"; 
    Node * point = &node; 
    return point; 
} 
int main() { 
    Node * test = init(); 
    printf("%d\n", test->data); 
    printf("%d", test->data); 
} 

なぜ最後の2つのprintf文で異なる結果が生じるのですか?私はテストポインターをどのように割り当てているかとは関係がありますが、それを修正する方法はわかりません。C言語:なぜこれらの2つのprintf文で異なるものが出力されるのですか?

答えて

3

あなたの場合、nodeは、関数init()のローカル変数ですが、あなたはこれのアドレスを返します。したがって、関数が返されると、もうnodeという存在は存在しません。

戻り値の戻り値は、戻り値がundefined behaviorとなる無効なメモリにアクセスした後に戻されます。

しかし、構造体変数自体をポインタではなく返すことができ、呼び出し元の戻り値を別の変数で収集することができます。

+0

これを修正するには、コードを変更する必要がありますか? – Madnobleman

+0

@weijazhou答えの最後の段落をもう一度読んで、ただ更新してください。 :) –

0

ノードは関数init()のローカル変数として定義されているため、関数が返ってからメモリは解放されます。

ノードをグローバル変数として定義するか(グローバル変数が気に入らない:-))、mallocを呼び出してメモリを割り当てる必要があります。

node = malloc(sizeof(Node)); 

ノードが不要になったら、メモリを解放してください。

0

更新のinit()構造体を返すために:

Node init(){ 
    Node node; 
    node.data = 5; 
    node.string = "hello"; 
    return node; 
} 

次のようにアクセス:

Node testNode = init(); 
printf("%d\n", testNode.data); 
printf("%d", testNode.data); 

それとも、このようにポインタを使用する場合:

Node testNode = init(); 
Node* pointerToNode = &testNode; 
printf("%d\n", pointerToNode->data); 
printf("%d", pointerToNode->data); 

その理由は@Souravがデータ​​がもはや有効ではないと回答したためです。

希望すると便利です。

1

はい、コードには、関数のローカルオブジェクトへのポインタを返すための未定義の動作があります。しかし、それはあなたのアプローチが誤って始まったようです。あなたのinit関数は適切な初期値を持つ構造体を初期化することになっているので、これを行うためのポインタを返す必要はありません。別の答えが提案のように、値によって

  1. 戻る:あなたは3つのオプションがあります。

  2. 関数の初期化のための構造体のアドレスを渡します。あなたが成功したか失敗したかを知らせることができるようにこれは、戻り値を解放:

    bool init(Node *node) { // must include stdbool.h 
        if(!node) 
         return false; 
    
        node->data = 5; 
        node->string = "hello"; 
        return true; 
    } 
    
    //... 
    
    Node test; 
    if(!init(&test)) { 
        //failed to initialize, handle the error 
    } 
    
  3. は完全に機能を見送ると、ノードの初期値を示していたマクロを供給:

    #define NODE_INIT_VAL { \ 
        .data = 5, .string = "hello", \ 
    } 
    

    これは、あなたがすることができます単にNode test = NODE_INIT_VAL;と書いてください。静的な保存期間を持つオブジェクトをどのように初期化したいかもわかります。

関連する問題