scanf() 在读取第三个取消引用的整数时使我的程序崩溃。我该如何解决这个问题?

问题描述 投票:0回答:2

好的,这是相关代码:

int main(int argc, char *argv[]) {
    int *v1, *v2, *v3;
    printf("Enter three integers: ");
    scanf("%d %d %d", v1, v2, v3);
    printf("We made it this far?\n");
    /* Other stuff after */
    return 0;
}

当使用任意三个整数的输入时,它将成功地将这些值分配给

*v1
*v2
,但是当尝试将第三个整数分配给
v3
时,程序将超时。当我给出三个以上的整数时也会发生这种情况。我对程序进行了分段,并逐一扫描整数,在这个过程中:K */

int main(int argc, char *argv[]) {
    int *v1;
    int *v2;
    int *v3;
    printf("Enter three integers: ");
    scanf("%d ", v1);
    printf("%d\n", *v1);
    scanf("%d ", v2);
    printf("%d\n", *v2);
    scanf("%d\n", v3);
    printf("%d\n", *v3);
    printf("We made it this far?\n");
    return 0;
}

我真的看不出问题是什么。格式说明符看起来很好,问题在于无论变量名称、输入或其他任何内容。我在 VSCode 上运行,我们一次也没有进入调试打印“我们已经做到这一步了吗?”任何帮助将不胜感激!

c variables crash scanf undefined-behavior
2个回答
2
投票

您的代码具有未定义的行为:在

scanf("%d %d %d", v1, v2, v3);
中,您传递了3个未初始化的指针作为转换后的整数的目标。
scanf()
将读取标准输入并将数字转换为整数(以 10 为基数)并存储转换后的值,就像通过
*v1 = value
一样。仅当已使用有效
*v1
变量的地址初始化
v1
时,写入
int
才有意义。

您的代码仅因第三个变量而崩溃的原因纯粹是偶然:似乎

v1
v2
的初始值恰好是有效地址,并且
scanf
将从
stdin
读取的值存储到这些地址而不会崩溃存在分段错误。然而,“有效地址”并没有说明这些指针指向什么,它可以位于可写内存中的任何位置,包括保存有价值信息的位置,这些信息的修改将在以后导致可怕的后果,即使在程序完成之后也是如此。未定义的行为可能不会立即产生明显的后果,这使得调试更加困难。 C 程序员应该使用一切可用的帮助来尝试避免未定义的行为。在这种情况下,当您将未初始化变量的值传递给

scanf()

时,使用高级警告进行编译(例如:gcc -Wall -Wextra -Werror)会发现问题。

这是修改后的版本:

#include <stdio.h> int main(int argc, char *argv[]) { int i1, i2, i3; int *v1 = &i1, *v2 = &i2, *v3 = &i3; printf("Enter three integers: "); int n = scanf("%d %d %d", v1, v2, v3); if (n == 3) { printf("We made it this far?\n"); /* Other stuff after */ printf("%d %d %d\n", i1, i2, i3); } else { printf("scanf returned %d\n", n); } return 0; }

请注意,惯用做法是直接将目标变量的地址传递给 
scanf()

,而不是使用指针变量。您可以删除

v1
、v2
and
v3` 的定义并编写:
    int n = scanf("%d %d %d", &i1, &i2, &i3);

始终检查 
scanf()

的返回值以检测无效或丢失的输入也很重要。如果

scanf()
无法根据格式字符串转换值,它会停止读取输入流,并将有问题的字节保留在流缓冲区中,保留尚未转换的目标变量未修改(在本例中仍未初始化),并返回执行和存储的成功转换的数量,或者如果根本没有可用的输入,则返回
EOF
在具有自动存储功能的函数的本地范围内定义的未初始化变量(与 

static

存储相反),当函数进入其定义范围时,具有堆栈内存或寄存器具有的任何初始值。这些字节可能在一次运行到另一次运行、一次调用到另一台计算机、一台机器到另一台机器上有所不同......如果它们形成有效的地址,这纯粹是偶然(并且缺乏运气)。

    


1
投票

#include <stdio.h> int main (int argc, char *argv[]) { int v1; int v2; int v3; int *p1 = &v1; int *p2 = &v2; int *p3 = &v3; printf ("Enter three integers: "); scanf ("%d", &v1); printf ("%d\n", *p1); scanf ("%d", &v2); printf ("%d\n", *p2); scanf ("%d", &v3); printf ("%d\n", *p3); printf ("We made it this far?\n"); return 0; }

© www.soinside.com 2019 - 2024. All rights reserved.