c - 我的 SIMPLE C 程序有什么问题?

标签 c char int printf

我正在用 C 编写一个 super 简单的基于命令行的程序。这只是一个小测试,代码非常简单。所以它的目的是询问用户的姓名、数学成绩、英语成绩、计算成绩。然后计算出他们的平均成绩,并告诉他们输入的名字。是的,我知道这是一个非常简单的程序,但我还是做错了。

问题是,我的代码的一部分将首先运行,告诉用户输入他们的名字,然后一旦他们这样做并按下回车键,我的代码的其余部分将立即运行,然后停止工作。很奇怪,我就是不明白哪里出了问题。

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char chr;
    char firstname;
    int mathsmark, englishmark, computingmark, averagemark;

    printf("What is your name?\n");
    scanf("%c", &firstname);
    printf("\n");

    printf("What is your maths mark?\n");
    scanf("%d", &mathsmark);
    printf("\n");

    printf("What is your english mark?\n");
    scanf("%d", &englishmark);
    printf("\n");

    printf("What is your computing mark?\n");
    scanf("%d", &computingmark);
    printf("\n");

    printf("Your name is: %c", firstname);
    printf("\n");

    averagemark = (mathsmark + englishmark + computingmark) / 3;
    printf("%d", averagemark);
    printf("\n");

    chr = '\0';

    while (chr != '\n') {

        chr = getchar ();
    }

    return 0;
}

最佳答案

一个主要问题是您已将 firstname 声明为单个字符长,并且当您尝试从控制台读取名称时,您使用的是 %c 转换说明符,它从输入流中读取下一个单个字符并将其存储到 firstname。名称的其余部分留在输入流中,以破坏剩余的 scanf 调用。

例如,如果您键入“Jacob”作为名字,那么第一个 scanf 调用会将 J 分配给 firstname,留下 "acob\n" 在输入流中。

下一个 scanf 调用尝试将 "acob\n" 转换为整数值并将其保存到 mathsmark,但失败了 ("acob\n" 不是有效的整数字符串)。接下来的两个 scanf 调用也会发生同样的事情。

最后一个循环

while (chr != '\n')
{
   chr = getchar();
}

最终消耗了 "acob\n" 的剩余部分,其中包含换行符(因为您在键入名称后按了 Enter),导致循环和程序退出。

你如何解决这个问题?

首先,您需要将firstname 声明为char数组:

char firstname[SOME_SIZE] = {0};

其中 SOME_SIZE 足够大以处理您的所有情况。您需要将 scanf 调用更改为

scanf("%s", firstname);

这告诉 scanf 从输入流中读取字符直到下一个空白字符,并将结果存储到 firstname 数组中。请注意,您不需要在此处使用 & 运算符;在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,表达式的值将是数组中第一个元素的地址。

请注意,scanf 不是很安全,也不是很健壮。如果您输入的字符多于缓冲区的容量,scanf 会很乐意将这些额外的字符存储到数组后面的内存中,这可能会破坏一些重要的东西。您可以通过在转换说明符中使用显式字段宽度来防止这种情况,例如

scanf(*%29s", firstname);

但总的来说这很痛苦。

scanf 也不太擅长检测错误输入。如果您输入“12er”作为您的标记之一,scanf 将转换并分配 “12”,将 “er” 留在流弄脏了下一个阅读。

scanf 返回成功赋值的次数,因此防止错误输入的一种方法是检查返回值,如下所示:

if (scanf("%d", &mathmarks) != 1)
{
  printf("Bad input detected for math marks\n");
}

不幸的是,scanf 不会从流中删除坏字符;你必须自己使用 getchar 或类似的方法来完成。

关于c - 我的 SIMPLE C 程序有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12803254/

相关文章:

c - trie 中未初始化的值

C 程序和宏

c - 如何检查 char* 变量是否指向空字符串?

c - 使用 char* 和 unsigned char* 打印整数的内存表示形式

c - 为什么变量 == 105 而不是 100?

c - 为什么我会检测到堆栈粉碎?

java - 如何将字符串的字符与数组的索引相匹配

C++ 将数字转换为单词

java - 为什么java在表达式中不自动将int转换为double?

arrays - 获得数组 int 的排列所需的最少移动次数?