[英]What happens if I use "&" with string in scanf function?
我剛剛在博客中看到了一些代碼。 它使用
scanf("%s",&T);
但正如我們所知,我們不應該在字符串中使用&符號,因為它會自動分配該字符串的第一個地址。 我確實運行了該代碼,令人驚訝的是它正在運行,所以我想知道當我在字符串中使用&
時會發生什么?
#include <stdio.h>
int main()
{
char T[2];
scanf("%s", &T);
printf("You entered %s\n", T);
}
從技術上講,這是一種類型不匹配,導致未定義行為。 對於掃描string ,預期參數是指向字符數組初始元素的指針。
當你有一個char[somevalue]
類型的數組t
時,當你說
scanf("%s",t);
t
衰減到指向第一個元素的指針,所以沒問題。
另一方面,當你說&t
,它是char (*)[somevalue]
- 指向數組的指針,整個數組,而不是指向數組初始元素的指針。
現在,由於數組的地址和數組的第一個元素的地址相同(內存位置),因此,將掃描值寫入提供的地址可能不會導致任何問題並按預期工作 - 但這兩者都不是定義或推薦。
代碼片段的相關部分是:
char T[2];
scanf("%s", &T);
&T
是一個指向兩個字符數組的指針( char (*)[2]
)。 這不是scanf
需要用於%s
說明符的類型:它需要一個指向字符( char *
)的指針。 所以程序的行為是未定義的。
如您所知,編寫此程序的正確方法是
char T[2];
scanf("%s", T);
由於T
是一個數組,當它在大多數上下文中使用時,它會“衰減”到指向第一個字符的指針: T
等價於&(T[0])
,其類型為char *
。 當您獲取數組的地址 ( &T
) 或其大小 ( sizeof(T)
) 時,不會發生這種衰減。
實際上,幾乎所有平台都對指向同一地址的所有指針使用相同的表示。 所以編譯器為T
和&T
生成完全相同的代碼。 有一些罕見的平台可能會生成不同的代碼(我聽說過它們,但我無法命名)。 一些平台對“字節指針”和“字指針”使用不同的編碼,因為它們的處理器本機尋址的是字,而不是字節。 在此類平台上,指向同一地址的int *
和char *
具有不同的編碼。 這些類型之間的轉換會轉換值,但在諸如可變參數列表之類的東西中誤用會導致錯誤的地址。 但是,我希望這樣的平台對字符數組使用字節地址。 還有一些罕見的平台,其中指針不僅編碼數據的地址,還編碼一些類型或大小信息。 然而,在這樣的平台上,類型和大小信息必須是等效的:它是一個 2 字節的塊,從T
的地址開始,可逐字節尋址。 所以這個特定的錯誤不太可能產生任何實際影響。
請注意,如果您首先使用指針而不是數組,情況將完全不同:
char *T; // known to point to an array of two characters
scanf("%s", &T); // bad
這里&T
是指向內存中包含字符數組地址的位置的指針。 所以scanf
會將它讀取的字符寫在指針T
存儲在內存中的位置,而不是T
指向的位置。 大多數編譯器會分析printf
和scanf
等printf
的格式字符串,因此會發出錯誤消息。
請注意, char T[2]
只有兩個字符的空間,這包括字符串末尾的空字節。 所以scanf("%s", T)
只能讀取單個字符。 如果此時輸入包含多個非空白字符,程序將溢出緩沖區。 要讀取單個字符並使其成為單字符字符串,請使用
char T[2];
scanf("%c", T);
T[1] = 0;
與scanf("%s", T)
,它讀取任何字符,甚至是空格。 要讀取具有長度限制的字符串,請向%s
規范添加限制。 你永遠不應該在scanf
使用無限的%s
,因為這將讀取盡可能多的輸入,不管有多少空間可以在內存中存儲這個輸入。
char T[2];
scanf("%1s", T); // one less than the array size
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.