簡體   English   中英

我不了解指針,地址和范圍

[英]I don't understand pointers, addresses and scopes

以下是我編寫的代碼段,目前正在打印中掙扎。

在我的主要方法中,我使用有效輸入兩次調用函數insertPoint ,例如: insertPoint(42); insertPoint(56); insertPoint(42); insertPoint(56); 並獲得以下輸出:

A.1 42
B.3 2686700

但是在B.3,我希望它也返回值42,但不會。 我假設2686700指向內存中的某個地址。

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

struct point {
    int value;
    struct point* next;
};

struct point *root;

int insertPoint(int value) {            
    // Graph is empty, set new root 
    if(root == 0){
        struct point newRoot;
        newRoot.value = value;

        root = &newRoot;
        (*root).value = value;
        printf("A.1 %d \n", (*root).value); // "A.1 42"
        return value;
        }
    printf("B.3 %d \n", (*root).value); // "B.3 2686700"

    /* rest of code here; irrelevant since related variables are not changed */
}

有人知道為什么會這樣嗎? 任何建設性的評論/答案表示贊賞。

如果下降者會向我提供反饋,我也將不勝感激,為什么他們認為我的問題不合適。

如果采用if (root == 0)分支,則root將指向struct point newRoot; 這是在if分支主體內部的堆棧上分配的。 newRoot結構在離開分支的主體和函數的主體之后(在您的情況下,在return value;之后)超出范圍return value; 聲明。 但是,全局指針變量root將繼續指向內存中的該位置(堆棧上)。 該位置上的堆棧存儲器的內容很可能會被其他一些代碼覆蓋,因此從該位置讀取point (成員)值(例如,通過root指針)將導致不確定的行為,這就是為什么要得到這種結果的原因。

您可能打算動態分配新的根,例如:

if(root == 0) {
    root = (point *) malloc(sizeof(point));
    root->value = value;
    root->next = NULL;
    printf("A.1 %d \n", root->value); // "A.1 42"
    return value;
}

別忘了設置next指針,因為默認情況下它不會為NULL (除非也許不是malloc而是使用calloc來對返回的內存進行零初始化,從而在大多數平台上有效地使next的值等於NULL )。 另外,不要忘記釋放動態分配的任何內存:使用malloccallocrealloc分配的任何內存都必須稍后使用free

您的代碼具有未定義的行為,因為它允許在范圍之外使用指向局部變量的指針。

它發生在這里:

struct point newRoot;
...
root = &newRoot;

問題在於,一旦函數到達}關閉if語句, root就會失效。 對其的任何取消引用都是未定義的行為。 因此,當您這樣做時

printf("B.3 %d \n", (*root).value); 

您訪問無效指針指向的內存。

幸運的是,解決此問題的方法很簡單:使用malloc而不是newRoot為鏈表元素分配內存:

if(root == 0){
    root = malloc(sizeof(struct point));
    root->value = value;
    printf("A.1 %d \n", (*root).value); // "A.1 42"
    return value;
}

當然,在退出程序之前,您需要使用malloc free分配的malloc ,以避免內存泄漏。

您創建struct point newRoot; 在函數內部的堆棧上。 由於它在堆棧上,因此在退出此函數時將其銷毀。 此后,任何使用其指針( *root )的操作都應給出未定義的結果。

您必須了解,堆棧超出范圍時,堆棧中的內容會消失

所以

root = &newRoot;

這里newRoot在堆棧中。 函數結束newRoot結束-指針無效

使用malloc創建newRoot對象,這樣我可以使函數調用的壽命更長

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM