找不同的游戏
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, weight
和 days_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]));
已解决问题。大卫的回答也很有见地,但只解释了第一个分数输出的巨大价值。我仍然建议人们支持他的回答,因为它包含对其他问题的有用建议。
我有三个数组,一开始基本上都是一样的。它们都以 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, weight
和 days_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]));
已解决问题。大卫的回答也很有见地,但只解释了第一个分数输出的巨大价值。我仍然建议人们支持他的回答,因为它包含对其他问题的有用建议。