【问题标题】:Why the result of this program is always zero? [duplicate]为什么这个程序的结果总是为零? [复制]
【发布时间】:2020-10-02 11:52:22
【问题描述】:

我正在尝试编写一个简单的程序,它接收最多 30 名学生的分数、姓名和 ID,并打印他们的平均分数。我想知道为什么程序的结果总是为零。
如果有人能给我提示,我将不胜感激。
代码如下:

#include <stdio.h>

struct student{
    char name[30];
    int mark;
    int ID;

} s[30];

int main() {
    int n, i=0, sum=0;
    float average;
    /* printf("enter the number of students: "); */
    scanf("%d", &n);
    /* printf("enter their information: "); */

    for(i=0; i<n; i++)
        scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);

    for(i=0; i<n; i++)
         sum+=s[i].mark;
    
    average=sum/(float)n ;
    printf("%.2f", average);
}

【问题讨论】:

  • 你明白 C 不关心你的缩进,是吗?
  • 这几乎就像让缩进成为一件重要的事情是一个愚蠢的想法,肯定没有任何语言会使用:)
  • 不管怎样,您是否尝试验证各个 s[i].mark 值是什么?
  • 你能展示一下你输入值的方式

标签: c


【解决方案1】:

格式说明符%s 表示要读取一个字符串,它正在这样做……包括您的逗号和后续字符。这是“贪婪”。

那么%d 就没有什么可以吸收的了,所以所有的整数都保持为零。

我建议你一次读一行,然后解析这些行。

另外,在this similar question上也有一些建议。


当遇到这样的问题时,您应该尝试通过检查调试器中的变量值来缩小范围,或者甚至只是使用printf,如下所示:

    printf("%s|%d|%d\n", s[i].name, s[i].mark, s[i].ID);

当我把它放在你的第一个循环中,并将以下输入传递给程序时:

2
A,2,3
B,4,5

the output is this:

A,2,3|0|0
B,4,5|0|0
0.00

...这清楚地表明解析是问题。

【讨论】:

    【解决方案2】:

    问题出在这一行:

    scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);
    

    它不会像你想象的那样工作。为了测试它,我修改了你的程序。

    int main() {
        int n = 10, i=0, sum=0;
        int scanfResult;
        float average;
        /* printf("enter the number of students: "); */
        //scanf("%d", &n);
        /* printf("enter their information: "); */
        for(i=0; i<n; i++)
        {
            scanfResult = scanf("%s,%d,%d",s[i].name,&s[i].mark,&s[i].ID);
            printf("scanf has scanned %d items\n", scanfResult);
            if(scanfResult != 3) 
            {
                printf("you need to find another way of entering the data\n");
                exit(1);
            }
        }
        for(i=0; i<n; i++)
             sum+=s[i].mark; 
        average=sum/(float)n ;
        printf("%.2f", average);
    }
    

    https://godbolt.org/z/PredEd

    你需要做什么?您需要使用fgets 阅读鲸鱼行并编写解析器,该解析器将分割此字符串

    始终检查扫描结果

    【讨论】:

    • 我已经说过了!
    【解决方案3】:

    如果您尝试输入带有空格的名称,例如

    Joe Smith,90,1234
    

    那么问题是%s 转换说明符在第一个空白字符处停止读取,因此它读取"Joe" 并将"Smith" 留在输入流中,这会破坏接下来的两次读取。或者,如果您没有任何空格,%s 会将整个输入行读入name(无论是否合适,都可能导致缓冲区溢出)。

    您应该使用%[ 转换说明符而不是%s 并明确调整其大小以避免出现缓冲区溢出的风险。您还应该检查 scanf 的返回值,以确保您正确阅读了所有 3 项:

    /**
     * loop until we have three good inputs;
     * %29[^,] reads up to 29 characters or to the next comma;
     * An array of size 30 can store a string of up to
     * 29 characters plus the string terminator;
     * Added leading blank in the format string to consume
     * any leading whitespace. 
     */
    while ( scanf( " 29%[^,],%d,%d", s[i].name, &s[i].mark, &s[i].ID) != 3 )
    {
       fprintf(stderr, "Bad input, try again\n" );
       /**
        * clear out the input stream before trying again
        */
       while ( getchar() != '\n' )
         ; // empty loop body
    }
    

    【讨论】:

      【解决方案4】:

      你的问题是,中的scanf("%s,%d,%d",s[i].name,&amp;s[i].mark,&amp;s[i].ID);

      我将代码更改如下:

      scanf("%s%d%d",s[i].name,&s[i].mark,&s[i].ID);
      

      然后输入和输出为: 输入:

      2
      moh 1 2
      test 2 3
      

      输出:

      1.50
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多