2016-03-11 45 views
2

在C中,如果scanf()中的參數不存在&,則不會生成編譯錯誤;相反,顯示的結果是錯誤的(即發生語義錯誤)。缺少C中的訪問說明符並不會導致編譯錯誤

考慮下面的代碼:

char str[30]; 
int a; 
printf("Enter the value"); 
scanf("%s %d", str, a);  // This is the statement in question. 
printf("You entered %s %d", str, a); 

在這裏,我知道str是一個字符數組,因此將有一個基本地址,因而不會產生編譯錯誤。但爲什麼a參數&的缺席不會導致編譯錯誤?

另外str給出正確的輸出,但整數總是產生值-28770作爲輸出。爲什麼是這樣?

+0

你在輸入什麼?你期望的結果是什麼? –

+0

「始終將-28770作爲輸出的整數」 - 未初始化的局部變量「a」。包含在聲明前的那個內存位置(堆棧或寄存器)。每次運行可能相同,每次可能會有所不同;這就是爲什麼它是「未定義的行爲」。 - 你的編譯器沒有警告過你嗎? – JimmyB

+0

好的。編譯器沒有給出任何警告。謝謝回答。 – Gon

回答

2
int scanf(const char *format, ...); 

這是scanf的原型。第一個參數是char *,其他參數是可變長度。所以不會產生錯誤。

+0

詳細說明:'scanf()'中的可變參數沒有聲明類型,因此,對於編譯器來說,它可以是任何東西。 – JimmyB

1

由於Umamahesh P寫道,您不會收到編譯錯誤,因爲scanf是一個變量參數函數。至於運行程序時會發生什麼,這是C標準所稱的「未定義行爲」。任何事情都可能發生。您需要查看機器指令和內存地址級別發生了什麼,以查看scanf對您提供的整數值的確切含義,而不是指針。

+0

不會'scanf(...,a)'嘗試將值輸入寫入內存中的隨機位置,可能會導致分段錯誤? – JimmyB

+0

@HannoBinder可能發生 - 但行爲是_undefined_,意思是任何事情都可能發生。 – davmac

+1

@HannoBinder:正如davmac寫道的那樣,可能會發生,但不能保證。我看到的另一個行爲是參數在寄存器中傳遞,並且32位整數和64位指針在不同的寄存器中傳遞,所以scanf會得到一個指向某個東西的指針,恰好在正確的寄存器中。 –

4

scanf具有原型:

int scanf(const char *fmt, ...); 

...意味着任何數量的參數任何類型可以fmt之後指定。因此,調用者(而不是編譯器)負責確保提供的參數與函數期望的內容匹配。

0

您可以獲得編譯器警告,具體取決於您使用的編譯器和您指定的選項。

此外,即使它試圖顯示這些警告,如果使用vscanf()或者如果使用動態字符串作爲格式參數,編譯器將完全無法執行此操作。

例如,這是我開始使用MinGW的-64 GCC 4.5.4輸出:

gcc -Wall -o small.exe small.c 

small.c:7:3: warning: format '%d' expects type 'int *', but argument 3 has type 'int' 
small.c:7:8: warning: 'a' is used uninitialized in this function 

只需添加-Werror選項來打開這些警告變爲錯誤。

相關問題