一场比赛的区别

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

我有三个数组,所有数组从一开始就基本相同。它们都以50个条目开头,并且都是整数数组。但是,其中一个立即用大值填充,而另两个以通常的0,0,0,...开头。是什么使得该数组与其他数组脱颖而出?根据提供一个最小示例的建议,我在下面发布了一个示例。它可能可以进一步减少,但是我只保留了所有print语句,以说明这是一个Heisenbug的情况。的确,如果我删除更多行,则该问题可能只是无法出现,并且我想确保它出现以便可以消除。

  int main() {
   int assignments;
   int i; /*for loop index for both loops*/
   int days_late[50], scores[50], weights[50];
   scanf(" %d",&assignments);
   /*assigns assignment data from input to days_late, scores, weights*/
   for(i=0; i<assignments; i++){
     int index;
     printf(" Index scanned: %d",scanf(" %d",&index));
     printf(" Index is: %d",index);
     printf("\nScore just added is %d",scores[index]);
     printf("\nWeight just added is %d",weights[index]);
     printf("\nLateness just added is %d",days_late[index]);
     printf("\nIndex is %d",index);
     printf(" Variables scanned: %d",scanf(" %d%d%d",&scores[index],&weights[index],&days_late[index]));
     printf("\nScore just added is %d",scores[index]);
     printf("\nWeight just added is %d",weights[index]);
     printf("\nLateness just added is %d",days_late[index]);
   }
/*anything past this point is not neccessary, the error has already occurred*/
}

输出:

Index scanned: 1 Index is: 2
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0
Index is 2 Variables scanned: 0
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0 Index scanned: 0 Index is: 2
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0
Index is 2 Variables scanned: 0
Score just added is -1793035504
Weight just added is 0
Lateness just added is 0

严重,分数与体重/迟来有什么区别?从一开始,似乎只有其中一个被搞砸了。

编辑:我嵌套了scanf和printf来检查成功扫描了多少变量,并且返回的数字是我期望的。因此没有新信息。

这是从中读取输入的文件:

10 0 Y
2
2, 80, 40, 0
1, 100, 60, 0

前两行已正确处理,并且涉及它们的变量始终不在上面的代码块中。因此该文件也可能是

2, 80, 40, 0
1, 100, 60, 0
c c89
2个回答
5
投票

问题是您在逻辑上尝试将“小推车放到马前”。程序流程是顺序的。在尝试输出存储的值之前,您需要阅读并存储要查找的值。在您的代码中,您尝试在获得输入以填充值(或在声明过程中初始化值)之前输出uninitialized(例如indeterminate)值。如上所述,这导致Undefined Behavior

C11 Standard - 6.7.9 Initialization(p10)“如果具有自动存储期限的对象未显式初始化,则其值不确定。”C11 Standard - J.2 Undefined Behavior“具有自动存储持续时间的对象的值在被使用时不确定(6.2.4,6.7.9,6.8)。“

要使“马车先回车”,您需要考虑代码中需要按顺序进行的操作,以确保变量在尝试输出值之前已被输入正确填充。此外,如果您没有其他答案,请了解除非您检查返回内容来确定输入是成功还是失败,否则您将无法正确使用任何输入函数。

[查看您的代码,似乎要提示用户输入assignments的数量,然后循环获取score, weightdays_late的数组元素的输入,然后显示输入的内容以确认输入。

使问题复杂化,您尝试让用户在要存储值的数组内输入index(很好,但是如果您循环获取输入,则不需要)。此外,index值必须在每个数组中的元素范围内,例如0 <= index < 50。在您使用index之前,您需要先验证它是否在该范围内-否则,您将尝试通过尝试在数组范围之外写入和读取值来再次调用Undefined Behavior

要消除整个index问题,由于正在循环,只需读取与循环变量相对应的赋值即可。 (例如,您可以在循环中使用scores[index]代替scores[i]),这种循环方式可控制提示和填充索引。

将它们放在一起并验证每个输入(如果输入无效,则直接退出,您可以执行以下操作:

#include <stdio.h>

int main (void) {

    int assignments,
        i,                      /* for loop index for both loops */
        days_late[50] = {0},    /* initialize arrays all zero */
        scores[50] = {0}, 
        weights[50] = {0};

    fputs ("\nEnter No. assignments: ", stdout);    /* prompt for no. assignments */
    /* VALIDATE EVERY INPUT - both the conversion and that the value is within range */
    if (scanf("%d", &assignments) != 1 || assignments < 0 || assignments > 49) {
        fputs ("error: invalid integer input or input out of range.\n", stderr);
        return 1;
    }

    /* loop assignments times */
    for (i = 0; i < assignments; i++) {
        /* display assignment no. prompt for score, weight, days_late */
        printf ("\nassignment[%2d]\nenter score, weight, days_late: ", i + 1);
        if (scanf ("%d%d%d",    /* read and VALIDATE each value */
                    &scores[i], &weights[i], &days_late[i]) != 3) {
            fputs ("error: invalid integer input - scores, weights, days_late.\n", 
                    stderr);
            return 1;
        }
        /* output values read */
        printf ("\nScore just added is %d\n"
                "Weight just added is %d\n"
                "Lateness just added is %d\n",
                scores[i], weights[i], days_late[i]);
    }
    return 0;
}

注意,您可以更轻松地处理错误检查,以便再次提示用户,直到输入有效条目(或生成EOF)为止,但在解决输入逻辑后留给您。有关示例,请参见isalpha function in C not returning the correct value — flags all inputs as A-Z characters的答案。

示例使用/输出

$ ./bin/scoreswtsdays_late

Enter No. assignments: 2

assignment[ 1]
enter score, weight, days_late: 88 1 0

Score just added is 88
Weight just added is 1
Lateness just added is 0

assignment[ 2]
enter score, weight, days_late: 91 1 2

Score just added is 91
Weight just added is 1
Lateness just added is 2

这涵盖了我对您正在尝试的理解。如果我有看错的东西,请告诉我,我很乐意提供进一步的帮助。同样,如果您需要以上任何内容的进一步说明,请在下面添加评论。


发布输入文件格式后进行编辑

虽然我们仍然不清楚第一行的含义,但鉴于您的剩余描述,请从第2行读取assignments,然后循环assignments次以读取index, scores, weights, days_late非常简单。

由于正在读取line-at-a-time

,因此您将需要使用line-at-a-time输入功能,例如fgets()(或POSIX getline())。请注意,面向行的函数读取并在它们填充的缓冲区的每行末尾包含'\n'(尽管这里使用sscanf进行解析,不需要特殊的容纳))

要处理您的输入文件,只需阅读前两行,以获取读取文件其余部分所需的信息。不要忘记验证从第2行读取的assignments值是否在数组范围内。

从第3行开始,只需读取该行,然后使用sscanf解析该行中的值,以验证每行发生的预期转化次数。使用格式字符串

"%d, %d, %d, %d"可以轻松地从行中解析值。

将各个部分放在一起,您可以做:

#include <stdio.h>

#define MAXC 1024       /* if you need a constant, #define one (or more) */

int main (void) {

    char buf[MAXC];             /* character array used as buffer for input */
    int assignments,
        i = 0,                  /* loop counter */
        days_late[50] = {0},    /* initialize arrays all zero */
        scores[50] = {0}, 
        weights[50] = {0};

    if (!fgets (buf, MAXC, stdin)) {    /* read/validate line 1 */
        fputs ("error: insufficient input - line 1\n", stderr);
        return 1;
    }
    /* parsing the 3 values left to you until description given */
    printf ("line 1: %s", buf);       /* simply output line 1 */

    if (!fgets (buf, MAXC, stdin)) {    /* read/validate line 2 */
        fputs ("error: insufficient input - line 1\n", stderr);
        return 1;
    }
    /* parse assignments from buf, validate in range */
    if (sscanf (buf, "%d", &assignments) != 1 || assignments < 0 || assignments > 49) {
        fputs ("error: invalid assignments values line - 2\n", stderr);
        return 1;
    }

    while (i < assignments && fgets (buf, MAXC, stdin)) {
        int index, score, weight, dayslate; /* temporary value to read into */
        /* parse values from line, VALIDATE 4 conversion took place */
        if (sscanf (buf, "%d, %d, %d, %d", &index, &score, &weight, &dayslate) != 4 ||
                    index < 0 || index > 49) {
            fputs ("error: invalid line format, lines 3+, or index out of range\n", 
                    stderr);
            return 1;
        }
        scores[index] = score;          /* assign values to array[index] */
        weights[index] = weight;
        days_late[index] = dayslate;

        /* output values read */
        printf ("\nassignment[%2d]:\n"
                "  Score just added is   : %d\n"
                "  Weight just added is  : %d\n"
                "  Lateness just added is: %d\n",
                index, scores[index], weights[index], days_late[index]);
        i++;    /* increment counter */
    }
    return 0;
}

示例使用/输出

将输入文件放置在dat/scoreswtsdays.txt中,同时将数据文件重定向为输入时运行程序将导致以下结果:

$ ./bin/scoreswtsdays_late_file < dat/scoreswtsdays.txt
line 1: 10 0 Y

assignment[ 2]:
  Score just added is   : 80
  Weight just added is  : 40
  Lateness just added is: 0

assignment[ 1]:
  Score just added is   : 100
  Weight just added is  : 60
  Lateness just added is: 0

再次查看情况,如果还有其他问题,请通知我。

将scanf语句更改为

printf(" Variables scanned: %d",scanf("%*c%d%*c%d%*c%d",&scores[index],&weights[index],&days_late[index]));

已解决问题。 David的答案也很有见地,但仅说明了第一得分输出的巨大价值。我仍然建议人们赞成他的答案,因为它包含有关其他问题的有用建议。


0
投票

将scanf语句更改为

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