簡體   English   中英

為什么在 C 中使用 int 格式將輸入轉換為 char 會改變另一個 char 變量的值?

[英]Why in C does taking input using int format to a char change the value of another char variable?

我使用 scanf() 將“%d”格式的輸入輸入到一個字符中,因為我不想要超過 8 位。 但是這樣做會改變另一個 char 變量的值。

代碼:

#include <stdio.h>
int main() {
        char a;
        char b;
        printf("Enter a: ");
        scanf("%c", &a);
        printf("a = %c\n", a);
        printf("Enter b: ");
        scanf("%d", &b);
        printf("\na = %d\n", a);
        printf("b = %d\n", b);
}

Output:

Enter a: c
a = c
Enter b: 56

a = 0
b = 56

截屏

scanf 從標准輸入讀取數據並根據參數格式將它們存儲到附加的 arguments 指向的位置。

scanf("%d", &b);

使用 %d,您將 integer 存儲到無法保存 integer 的 char 變量中。 變量現在增長到它上面的堆棧中的另一個變量。

如果您使用標志“-fstack-protector-all”進行編譯,您應該會在執行時得到 *** 檢測到堆棧粉碎 *** 錯誤。

重復使用scanf() function 時會出現此問題。 由於scanf()不會自動跳過 stream 中的空格,因此必須在 %c 轉換說明符前面留一個空格。

我在ISO C11 (-std=c11)模式下使用 GCC 編譯器來調查這個問題。

#include <stdio.h>
#include <stdlib.h>

/**
 * @brief   Main Program
 * @return  Returns 0 if the program is successful.
 */
int main( void )
{
    char a;
    char b;

    printf( "Enter the value of a: " );
    scanf( "%c", &a );

    printf( "Enter the value of b: " );
    scanf( " %c", &b );
    /// A space has been added in front of the %c conversion identifier of the scanf() function.

    printf( "The value of variable a: %d\n", a );
    printf( "The value of variable b: %d\n", b );

    return EXIT_SUCCESS;
}

Screenshot 1:測試應用程序

@JBahn77 謝謝。 我剛剛注意到第二個scanf() function 使用%d轉換令牌。 我同意你指出的副作用。 當編譯器一個接一個地加載 memory 中的變量時,就會發生這種情況。 例如,當在變量 b 中輸入足夠大的數字時,我檢查了變量 a 的變化。 我將代碼更改如下。

#include <stdio.h>
#include <stdlib.h>

/**
 * @brief   Main Program
 * @return  Returns 0 if the program is successful.
 */
int main( void )
{
    char a;
    char b;

    printf( "Address of variable a: %p\n", &a );
    printf( "Address of variable b: %p\n", &b );

    printf( "Enter the value of a: " );
    scanf( "%c", &a );

    printf( "Enter the value of b: " );
    scanf( " %d", &b );

    printf( "The value of variable a: %d\n", a );
    printf( "The value of variable b: %d\n", b );

    return EXIT_SUCCESS;
}

然后,當我測試代碼時,我意識到了這種副作用的后果。

Screenshot 1測試編輯后的代碼

測試代碼如下圖所示。

Screenshot 2結果解讀

scanf格式字符串中的格式化指令不僅指示如何匹配輸入,還指示要存儲結果值的相應變量的類型。 如果你傳遞一個指向 object 的指針,它的類型與相應指令所期望的不同,那么你將獲得未定義的行為。

即使對於簡單的符號不匹配也是如此,但在您的情況下,您的大小不匹配。 對於沒有大小修飾符的%d指令, scanf期望將掃描的 integer 值寫入 [ signed ] int類型的 object 中。 如果您傳遞的指針改為指向char ,並且在大多數實現中,如果int大於char ,那么產生的未定義行為特別有可能以不需要的方式表現出來,例如通過在其他變量的值。

如果要將數字掃描為char大小的 integer,那么您應該

  1. 將變量聲明為有signed charunsigned char ,而不是默認char ,並且
  2. 為所選數據類型使用正確的轉換說明符和大小修飾符

例如,

unsigned char b;

scanf("%hhu", &b);

%u是無符號 integer 的格式指令,並且hh修飾符指示scanf目標變量是char / signed char / unsigned char的大小。

如果你想要一個簽名的 integer 那么它會是相似的,但是使用%d格式化指令:

signed char b;

scanf("%hhd", &b);

作為一種風格,不要將默認char用於數字數據,即使您確信需要支持的值范圍是有signed charunsigned char范圍交集的子集。 特別是如果您打算將它與格式化的 I/O 函數一起使用,因為%hhd%hhu是否是默認char的正確指令是特定於實現的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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