繁体   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