簡體   English   中英

如果我在 scanf 函數中使用帶有字符串的“&”會發生什么?

[英]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指向的位置。 大多數編譯器會分析printfscanfprintf的格式字符串,因此會發出錯誤消息。

請注意, 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.

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