首页 > 解决方案 > 找不同的游戏

问题描述

我有三个数组,所有这些都基本相同。它们都以 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

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

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

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

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

前两行被正确处理,并且涉及它们的变量无论如何都不在上面的代码块中。所以文件也可能是

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

标签: cc89

解决方案


问题是你在逻辑上试图把“本末倒置”。程序流程是顺序的。在尝试输出存储的值之前,您需要读取并存储您正在寻找的值。在您的代码中,您尝试在获得输入以填充值(或在声明期间初始化值)之前输出未初始化的(例如indeterminate)值。如上所述,这会导致Undefined Behavior

C11 标准 - 6.7.9 初始化(p10) “如果具有自动存储持续时间的对象未显式初始化,则其值是不确定的。” C11 标准 - J.2 未定义行为“具有自动存储持续时间的对象的值在不确定时使用(6.2.4、6.7.9、6.8)。”

为了让“马回到车前”,您需要考虑在您的代码中需要按顺序发生什么,以确保您的变量在尝试输出值之前正确填充输入。此外,如果您从答案中没有得到任何其他信息,请了解您无法正确使用任何输入函数,除非您检查返回以确定输入是成功还是失败。

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

使问题复杂化的是,您尝试让用户index在将存储值的数组中输入 (很好,但如果您正在循环获取输入,则没有必要)。此外,该index值必须在每个数组中的元素范围内,例如0 <= index < 50. 在使用它之前验证index范围内的落差取决于您 - 或者您将通过尝试写入和读取数组边界之外的值再次调用未定义行为。

为了消除整个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生成)有效条目之前重新提示用户,但在输入逻辑解决后留给您。有关示例,请参阅C 中 isalpha 函数未返回正确值的答案— 将所有输入标记为 AZ 字符。

示例使用/输出

$ ./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

这涵盖了我对您正在尝试的内容的理解。如果我误读了某些内容,请告诉我,我很乐意提供进一步的帮助。同样,如果您需要对上述任何内容进行进一步解释,请在下方发表评论。


输入文件格式发布后编辑

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

由于您正在阅读一行,因此您将需要使用面向行的输入功能,例如fgets()(或 POSIX getline())。注意面向行的函数读取并'\n'在它们填充的缓冲区中包含每行末尾sscanf

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

从第 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

再看一遍,如果您还有其他问题,请告诉我。


推荐阅读