将scanf语句更改为
我有三个数组,所有数组从一开始就基本相同。它们都以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
问题是您在逻辑上尝试将“小推车放到马前”。程序流程是顺序的。在尝试输出存储的值之前,您需要阅读并存储要查找的值。在您的代码中,您尝试在获得输入以填充值(或在声明过程中初始化值)之前输出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, 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的答案。示例使用/输出
$ ./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的答案也很有见地,但仅说明了第一得分输出的巨大价值。我仍然建议人们赞成他的答案,因为它包含有关其他问题的有用建议。
将scanf语句更改为