2013-03-10 146 views
6

這也許是我遇到過的最奇怪的事情之一。我不用C編程太多,但從我知道的是真實的,再加上在線檢查不同的來源,變量宏名稱宏體只在while循環的範圍內定義。所以每次循環運行,我期待marcoName宏體獲得新的地址,併成爲完全新的變量。但是,這不是事實。循環內變量範圍

我發現,即使循環再次運行,兩個變量共享相同的地址,這導致我嚴重頭痛的鏈表,我需要檢查元素的唯一性。我不知道這是爲什麼。不應該宏名稱macroBody每次while循環運行時都會得到全新的地址?

我知道這是問題,因爲我打印的地址和他們是一樣的。

while(fgets(line, sizeof(line), fp) != NULL) // Get new line 
{ 
    char macroName[MAXLINE]; 
    char macroBody[MAXLINE]; 

    // ... more code 

    switch (command_type) 
    { 
     case hake_macro_definition: 
      // ... more code 

      printf("**********%p | %p\n", &macroName, &macroBody); 
      break; 

     // .... more cases 
    } 
} 

代碼是我的鏈接列表代碼的一部分。

struct macro { 
    struct macro *next; 
    struct macro *previous; 
    char *name; 
    char *body; 
};  

檢查元素是否已存在於鏈接列表中的函數。但由於*名稱具有相同的地址,因此我總是在if條件內結束。

static struct macro *macro_lookup(char *name) 
{ 
    struct macro *temp = macro_list_head; 

    while (temp != NULL) 
    { 
     if (are_strings_equal(name, temp->name)) 
     { 
      break; 
     }  

     temp = temp->next; 
    } 

    return temp; 
} 
+0

如果您的期望是獲得兩個變量的唯一地址,爲什麼不定義一個指針,爲循環的每次運行分配和釋放內存。另外,你對這個問題的評論很有意思。你提到你根據地址的唯一性做出決定,在這種情況下,這是一個棧變量/存儲器指針。 – Ganesh 2013-03-10 03:12:16

+0

是的,我可能會做這樣的事情。謝謝! – ThePedestrian 2013-03-10 03:24:31

回答

5

這些數組在棧中分配:

char macroName[MAXLINE]; 
char macroBody[MAXLINE]; 

編譯器已預分配給你,你的功能開始存在空間。換句話說,從計算機的角度來看,這些數組的位置與您在函數體頂部的循環體之外定義它們的位置相同。

C中的範圍僅指示標識符可見的位置。因此,編譯器(但不是計算機)強制執行在循環體之前或之後不能引用macroNamemacroBody的語義。但是從計算機的角度來看,這些數組的實際數據在函數啓動後就存在,並且只有在函數結束時纔會消失。

如果您要查看代碼的程序集轉儲,您可能會發現機器的幀指針減少了足夠大的數量,以使函數的所有局部變量具有空間,包括這些變量陣列。

+0

所以我只在函數結束時得到「新」變量,是否正確? – ThePedestrian 2013-03-10 03:15:47

+2

@ThePedestrian這樣的事情。你可以通過動態內存分配獲得「新」空間,即通過'malloc()'。順便說一下,如果你有興趣更多地瞭解這些東西的工作原理,這整個研究領域被稱爲*計算機組織*。 – chrisaycock 2013-03-10 03:18:00

+0

我現在實際參加了計算機組織課。你如何解釋事情很有意義。我從來沒有新的情況。我假設使用了「新」內存/寄存器,但爲什麼變量只能存在一次纔有意義。 – ThePedestrian 2013-03-10 03:20:08

3

我需要什麼,除了chrisaycock的回答說:你不應該使用指針外函數的局部變量,這些變量定義考慮這個例子:

int * f() 
{ 
    int local_var = 0; 
    return &local_var; 
} 
int g(int x) 
{ 
    return (x > 0) ? x : 0; 
} 
int main() 
{ 
    int * from_f = f(); // 
    *from_f = 100; //Undefined behavior 
    g(15); //some function call to change stack 
    printf("%d", *from_f); //Will print some random value 
    return 0; 
} 

一樣的,實際上,適用於塊。從技術上講,塊結束後可以清除塊本地變量。因此,在循環的每次迭代中,舊地址可能無效。這不會是真的,因爲C編譯器的確因爲性能原因將這些變量放到相同的地址,但是你不能依賴它。

你需要了解的是如何分配內存。如果你想實現一個列表,它是一個增長的結構。記憶從哪裏來?您不能從堆棧分配太多內存,並且一旦從函數返回,內存就會失效。所以,你需要從堆中分配它(使用malloc)。

+0

感謝您提到這一點。我遇到了另一個問題,它來自於你描述的場景。謝謝! – ThePedestrian 2013-03-10 20:03:33