简体   繁体   English

为什么在 C 中使用 int 格式将输入转换为 char 会改变另一个 char 变量的值?

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

I took input in "%d" format into a character using scanf() because I didn't want more than 8 bits.我使用 scanf() 将“%d”格式的输入输入到一个字符中,因为我不想要超过 8 位。 But doing so changed the value of another char variable.但是这样做会改变另一个 char 变量的值。

Code:代码:

#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: Output:

Enter a: c
a = c
Enter b: 56

a = 0
b = 56

Screenshot截屏

scanf reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments. scanf 从标准输入读取数据并根据参数格式将它们存储到附加的 arguments 指向的位置。

scanf("%d", &b);

With %d you are storing an integer into the char variable that can not hold an integer.使用 %d,您将 integer 存储到无法保存 integer 的 char 变量中。 the Variable now grows into the other variable in stack above it.变量现在增长到它上面的堆栈中的另一个变量。

if you compile with the flag "-fstack-protector-all" you should get the *** stack smashing detected *** error on execution.如果您使用标志“-fstack-protector-all”进行编译,您应该会在执行时得到 *** 检测到堆栈粉碎 *** 错误。

This problem occurs when the scanf() function is used repeatedly.重复使用scanf() function 时会出现此问题。 Since scanf() doesn't automatically skip whitespace in the stream, a space must be left in front of the %c conversion specifier.由于scanf()不会自动跳过 stream 中的空格,因此必须在 %c 转换说明符前面留一个空格。

I used the GCC compiler in ISO C11 (-std=c11) mode to investigate this issue.我在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: Testing The Application Screenshot 1:测试应用程序

@JBahn77 thanks. @JBahn77 谢谢。 I just noticed that the second scanf() function uses the %d conversion token.我刚刚注意到第二个scanf() function 使用%d转换令牌。 I agree with the side effect you indicated.我同意你指出的副作用。 This happens when the compiler loads variables in memory one after the other.当编译器一个接一个地加载 memory 中的变量时,就会发生这种情况。 For example, I examined the change in variable a when a sufficiently large number is typed in variable b.例如,当在变量 b 中输入足够大的数字时,我检查了变量 a 的变化。 I changed the code as follows.我将代码更改如下。

#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;
}

Then, when I tested the code, I realized the consequences of this side effect.然后,当我测试代码时,我意识到了这种副作用的后果。

Screenshot 1 : Testing The Edited Code Screenshot 1测试编辑后的代码

The tested code is interpreted in the image below.测试代码如下图所示。

Screenshot 2 : Interpretation On Results Screenshot 2结果解读

The formatting directives in a scanf format string indicate not just how to match the input, but also the type of the corresponding variable in which the resulting value is to be stored. scanf格式字符串中的格式化指令不仅指示如何匹配输入,还指示要存储结果值的相应变量的类型。 If you pass a pointer to an object of a different type than the corresponding directive expects then you reap undefined behavior.如果你传递一个指向 object 的指针,它的类型与相应指令所期望的不同,那么你将获得未定义的行为。

That's true even for a simple signedness mismatch, but in your case you have a size mismatch.即使对于简单的符号不匹配也是如此,但在您的情况下,您的大小不匹配。 For a %d directive without a size modifier, scanf expects to write the scanned integer value in an object of type [ signed ] int .对于没有大小修饰符的%d指令, scanf期望将扫描的 integer 值写入 [ signed ] int类型的 object 中。 If the pointer you pass instead points to a char , and if, as is the case in most implementations, int is larger than char , then it is particularly likely that the resulting undefined behavior manifests in unwanted ways, such as by producing changes in the values of other variables.如果您传递的指针改为指向char ,并且在大多数实现中,如果int大于char ,那么产生的未定义行为特别有可能以不需要的方式表现出来,例如通过在其他变量的值。

If you want to scan a number as a char -sized integer, then you should如果要将数字扫描为char大小的 integer,那么您应该

  1. Declare the variable as either signed char or unsigned char , not default char , and将变量声明为有signed charunsigned char ,而不是默认char ,并且
  2. Use the correct conversion specifier and size modifier for the chosen data type.为所选数据类型使用正确的转换说明符和大小修饰符

For example,例如,

unsigned char b;

scanf("%hhu", &b);

%u is the format directive for an unsigned integer, and the hh modifier instructs scanf that the destination variable is the size of a char / signed char / unsigned char . %u是无符号 integer 的格式指令,并且hh修饰符指示scanf目标变量是char / signed char / unsigned char的大小。

If you want a signed integer then it would be similar, but with the %d formatting directive:如果你想要一个签名的 integer 那么它会是相似的,但是使用%d格式化指令:

signed char b;

scanf("%hhd", &b);

As a matter of style, do not use default char for numeric data, even if you are confident that the range of values you need to support is a subset of the intersection of the ranges of signed char and unsigned char .作为一种风格,不要将默认char用于数字数据,即使您确信需要支持的值范围是有signed charunsigned char范围交集的子集。 Especially so if you plan to use it with formatted I/O functions, because it is implementation-specific whether %hhd or %hhu is the correct directive for a default char .特别是如果您打算将它与格式化的 I/O 函数一起使用,因为%hhd%hhu是否是默认char的正确指令是特定于实现的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM