2010-12-03 38 views
2

今天我遇到了這段代碼,同時在C編程語言課程中輔導了一些學生。 練習要求實現兩個功能。第一個掃描來自用戶的輸入,第二個顯示之前掃描的內容。 我碰到的代碼如下:在gcc下的C代碼中的奇怪行爲4.4.3


#include <stdio.h> 

void myInput(int i,int n) 
{ 
    int cpt; 
    int tab[n]; 

    for (cpt=0; cpt<n; cpt++) 
    { 
    printf("Enter a number :"); 
    scanf("%d",&i); 
    tab[cpt]=i; 
    } 
} 



void myDisp (int n) 
{ 
    int tab[n];  
    int cpt; 

    for (cpt=0; cpt <n; cpt++) 
    { 
    printf("%d ", tab[cpt]); 
    } 
} 

int main() 
{ 
    int n; int i; 
    printf(" Entrer the numbers of elements you want: \n"); 
    scanf("%d \n",&n); 
    int tab[n]; 
    myInput(i,n);   
    myDisp(n); 
} 

儘管此代碼是充滿矛盾的,但它實際上是在GCC 4.4.3工作:它會顯示已輸入的數字! !!!!! 有誰知道這些代碼是如何工作的?

非常感謝

+0

供將來參考:請突出顯示您的代碼並按下Ctrl + K或點擊'0 1'按鈕等來設置您的代碼格式。謝謝。 – birryree 2010-12-03 16:53:07

+0

這是完全有效的C99,從我所能看到的。 – Electro 2010-12-03 16:57:03

+0

@Electro,@birryree:他可能正在研究`myDisp`中未初始化變量`tab`的使用。 – Thanatos 2010-12-03 16:59:07

回答

8

如果有效,它是通過純粹的運氣。 myDisp中打印的內容是未初始化的堆棧,其中可能包含或不包含在myInput中放入類似名稱變量的數據。 Related reading

下面是用什麼都不做的代碼來打破它一個簡單的方法:

void myInput(int i,int n) 
{ 
    // Add some variables to mess up the stack positioning. 
    int breaker; 
    int cpt; 
    int stomper; 
    int tab[n]; 
    int smasher; 

    for (cpt=0; cpt<n; cpt++) 
    { 
    printf("Enter a number :"); 
    scanf("%d",&i); 
    tab[cpt]=i; 
    } 

    // Trick the compiler into thinking these variables do something. 
    breaker = 1; 
    smasher = 3 * breaker; 
    stomper = smasher + breaker; 
    breaker = stomper * smasher; 
} 

另一種方式來打破這將是把一個函數調用(比如,以printf)的調用myInputmyDisp之間。

0

由於兩個陣列完全分開,所以它確實不適用。如果是這樣,那只是因爲他們最終在內存中的同一個位置。

1

它不起作用,至少不一致。就算我有GCC 4.4.4不是故事的4.4.3

$ ./a.out 
Entrer the numbers of elements you want: 
5 
2 
Enter a number :Enter a number :4 
Enter a number :1 
Enter a number :2 
Enter a number :3 
2 4 1 134514562 3 

寓意是當您訪問未初始化的內存,任何事情都有可能發生,包括外觀工作

0

可能是因爲tab本地的內存位置恰好(幾乎?)相同。

這聽起來不太奇怪:myInputmyDisp有幾乎相同的簽名(它們只有一個int參數不同);即使在最壞的情況下,在兩個函數中由tab所指的堆棧上的位置仍將被正確地對齊並且最多移位兩個inticptmyInput)。

0

它似乎程序訪問您聲明的每個數組int tab[n]相同的內存位置,但如上所述,它不應​​該工作。

但我認爲這裏發生的事情是這樣的:你在main()內分配tab [],比方說,在地址0x00000001下(僅作爲示例)。該數組有n個整數,但根本沒有數值。

然後你進入myInput(),再次聲明數組(相同的大小),在其他地址,如0x001F0000,然後設置值,逐一。

因此,當函數終止時,它釋放其變量的已分配內存,因此您的數組不再存在。

但是等等,這是C,所以當你釋放內存時,你只會告訴堆(或內存分配器,一般情況下)地址可以再次使用。你不會完全刪除內存中的值。

然後你調用myDisp()並再次聲明你的數組。看起來你剛纔請求的內存具有更高的優先級,然後再次給予你的程序。所以你的數組再次實例化並且在同一個地址上。

因此,即使你沒有填充數值,內存也會被讀取(因爲它始終在C中有效)並且值仍然存在。

呵呵,在main()裏面聲明的數組?沒有什麼事情發生。嘗試打印它的值,我敢打賭你不會有正確的值。

這是我的猜測。

編輯:只是爲了看到發生的事情:嘗試聲明另一個數組之後(不要重命名選項卡),說tab2,長度相同,並使用它來把你的值而不是選項卡,然後讓程序再次運行: )