找不同的游戏

A game of spot the difference

我有三个数组,一开始基本上都是一样的。它们都以 50 个条目开头,并且都是整数数组。然而,其中一个立即填充了大值,而另外两个以通常的 0,0,0 开始,... 是什么让这个数组与众不同?根据提供最小示例的建议,我在下面发布了一个示例。它可能会进一步减少,但我保留了所有打印语句只是为了说明这是一个 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

说真的,分数和weight/lateness有什么区别?只有其中一个似乎从一开始就搞砸了。

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

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

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

前两行处理正确,涉及到的变量反正不在上面的代码块中。所以文件也可能是

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

问题是您在逻辑上尝试放置 "cart before the horse"。程序流程是顺序的。在尝试输出存储的值之前,您需要读取并存储要查找的值。在您的代码中,您尝试在获得输入以填充值(或在声明期间初始化值)之前输出 uninitialized(例如 indeterminate)值.如上所述,这会导致 Undefined Behavior:

C11 Standard - 6.7.9 Initialization(p10) "If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate." and C11 Standard - J.2 Undefined Behavior "The value of an object with automatic storage duration is used while it is indeterminate (6.2.4, 6.7.9, 6.8)."

要获得 "horse back before the cart",您需要考虑在您的代码中需要按顺序发生什么,以确保您的变量在您尝试之前正确填充了输入输出值。此外,如果您没有从答案中得出任何其他结论,请了解您无法正确使用任何输入功能,除非您 选中 return 以判断输入成功还是失败。

查看您的代码,您似乎想提示用户输入 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 的回答。

例子Use/Output

$ ./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 是相当合理的简单。

由于您正在阅读一次一行,因此您需要使用面向行的输入函数,例如作为 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;
}

例子Use/Output

使用 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]));

已解决问题。大卫的回答也很有见地,但只解释了第一个分数输出的巨大价值。我仍然建议人们支持他的回答,因为它包含对其他问题的有用建议。