我目前正在开发一个可从文本文件配置的测验程序。当我尝试使程序只打印0到3阵列时出现问题。抱歉,如果我的问题是noob-ish问题。我是C的新手。我的代码出了什么问题?
更新:
在将array [i ++]更改为array [j ++]之后,代码可以正常工作。对于第一个循环,它工作正常。但是下一个循环,存储在数组中的数据似乎搞砸了。我编辑了testingc.txt内容,只是为了测试Paul Ogilvie建议的新随机内容。
第一次输出:
This is the first question
A.Really
B.No
C.Yes
在我输入C作为答案后,它打印正确!和标记。但是对于下一个循环,它给出了这个输出:
Which one of this is an OS
s 10
B.Microsoft Word
代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
//Variables
int i, linepick, line = 1, found = 0, marks = 0, j = 0;
char chars[1000], answer[1000], questionfile[] = "C:\\Users\\cbtcode\\Desktop\\testingc.txt";
FILE *file;
file = fopen(questionfile, "r");
if (file == NULL) {
printf("Can't find question file.\n");
}
else {
while (fgets(chars, 1000, file))
{
linepick = rand() % 20 + 1;
for (i = 0; i < linepick; i++)
{
if (fgets(chars, 1000, file) == NULL)
{
break;
}
else
{
found = 1;
char *p;
char *array[1000];
p = strtok(chars, ";");
while (p != NULL)
{
array[j++] = p;
p = strtok(NULL, ";");
}
if (array != NULL)
{
printf("%s\n", array[0]);
printf("%s\n", array[1]);
printf("%s\n", array[2]);
printf("%s\n", array[3]);
scanf("%s", answer);
if (strcmp(answer, array[4]) == 0) {
printf("Correct!\n");
marks = marks + 10;
printf("Your Marks: %d%%\n\n", marks);
}
else {
printf("Wrong!\n");
marks = marks - 10;
printf("Your Marks: %d%%\n\n", marks);
}
}
else
{
printf("ERROR: Can't find the question!");
}
}
}
line++;
}
if (found == 0)
{
printf("ERROR: Line number %d was not found.", linepick);
}
}
我的testingc.txt内容:
This is the first question;A.Really;B.No;C.Yes;C;
This is the first question;A.Really;B.No;C.Yes;C;
Which one of these is an OS;A.Windows 10;B.Microsoft Word;C.Notepad;C;
答案 0 :(得分:0)
问题出现在下面的代码中:
while (p != NULL)
{
array[i++] = p;
p = strtok(NULL, ";");
}
printf("%s\n", array[0]);
printf("%s\n", array[1]);
printf("%s\n", array[2]);
printf("%s\n", array[3]);
scanf("%s", answer);
if (strcmp(answer, array[4]) == 0) {
printf("Correct!\n");
marks = marks + 10;
printf("Your Marks: %d%%\n", marks);
}
你怎么知道在循环中分配了数组[1],数组[2],数组[3],数组[4]等。 您在访问它们之前没有检查。如果未分配它们,则它们将具有垃圾值,因为您尚未初始化数组。
另外,你正在做array[i++] = p;
。
可能是你需要使用不同的计数器j。
根据OP的要求进行编辑:
试试这段代码:
if (linepick == line)
{
found = 1;
char *p = NULL;
char *array[1000] = {NULL};
int j = -1, k = 0;
p = strtok(chars, ";");
while (p != NULL)
{
j += 1:
array[j] = p;
p = strtok(NULL, ";");
}
if ( j >= 0 ) {
for (k=0; k < j && k < 4; k++) {
printf("%s\n", array[k]);
scanf("%s", answer);
if (j >= 4 && array[4] && (strcmp(answer, array[4]) == 0)) {
printf("Correct!\n");
marks = marks + 10;
printf("Your Marks: %d%%\n", marks);
}
else {
printf("Wrong!\n");
marks = marks - 10;
printf("Your Marks: %d%%\n", marks);
}
}
else {
printf("Wrong!\n");
marks = marks - 10;
printf("Your Marks: %d%%\n", marks);
}
}
答案 1 :(得分:0)
循环for (i = 0; i < 20; i++)
重新排列chars
20倍。
第二次,数组中不再存在;
,因为它们已被'\0'
替换为strtok
。
因此strtok
会返回chars
,array[i++] = p;
会将p
存储在数组末尾之外。
这是未定义的行为。任何事情都可能发生:例如,由于您多次重复此操作,您可能会覆盖堆栈上的关键数据,从而导致您发现崩溃。
<强>更新强>:
编辑问题中发布的代码是有问题的,它会使评论和答案不一致。如果在解决所提供的答案中的初始问题后遇到更多问题,请考虑提出新问题。
更新的代码中仍然存在问题:
在解析循环之前,不要初始化j
。第一行将正确存储到数组中,如果它不包含;
array
中的条目,而后续行将被解析为越界位置。
您的正确解析测试不正确:array
永远不是NULL
,它是自动存储中的数组,而不是指针。您应该检查是否已使用if (j == 5)
解析了5个字段。
您尝试对问题进行随机播放并不能很好地工作,您应该在每次尝试之前回放流并使用数组来避免多次询问同一个问题。当前的实现很困惑,总是会跳过第一行。
这是一个简化版本:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
int i, n, total_lines, marks = 0;
char chars[1000], answer[10];
char questionfile[] = "C:\\Users\\cbtcode\\Desktop\\testingc.txt";
FILE *file;
file = fopen(questionfile, "r");
if (file == NULL) {
printf("Cannot open question file.\n");
return 1;
}
// first determine the number of questions:
for (total_lines = 0; fgets(chars, sizeof(chars), file) != NULL;) {
strtok(chars, ";"); // question
strtok(NULL, ";"); // A choice
strtok(NULL, ";"); // B choice
strtok(NULL, ";"); // C choice
if (strtok(NULL, ";")) { // correct choice.
total_lines++;
}
}
if (total_lines == 0) {
printf("No valid questions in the file.\n");
return 1;
}
// ask at most total_lines unique questions
int asked[total_lines];
for (i = 0; i < total_lines; i++)
asked[i] = 0;
for (n = 0; n < total_lines; n++) {
int skip = rand() % (total_lines - n);
rewind(file);
for (i = 0; fgets(chars, 1000, file) != NULL;) {
char *array[5];
array[0] = strtok(chars, ";"); // question
array[1] = strtok(NULL, ";"); // A choice
array[2] = strtok(NULL, ";"); // B choice
array[3] = strtok(NULL, ";"); // C choice
array[4] = strtok(NULL, ";"); // correct choice.
if (array[4] == NULL) // invalid line
continue;
if (asked[i++]) // question asked already
continue;
if (skip-- > 0) // skip this question
continue;
asked[i] = 1;
printf("%s\n", array[0]);
printf("%s\n", array[1]);
printf("%s\n", array[2]);
printf("%s\n", array[3]);
if (scanf("%9s", answer) != 1) {
printf("premature end of file\n");
return 1;
}
if (strcmp(answer, array[4]) == 0) {
printf("Correct!\n");
marks = marks + 10;
printf("Your Marks: %d%%\n\n", marks);
} else {
printf("Wrong!\n");
marks = marks - 10;
printf("Your Marks: %d%%\n\n", marks);
}
}
}
fclose(file);
printf("Your final score: %d%%\n\n", marks);
return 0;
}
答案 2 :(得分:0)
要做出很多评论,但原因是你的
array[i++] = p;
因为i
也是你的循环计数器所以它可以有任何值,最多20个。然后,如果你想打印元素0..3这些可能是空指针,所以你访问不属于你的内存:访问违规。
使用新变量,例如int j
索引数组。
- 编辑 -
好的,所以你修复了这个错误。下一个错误是你读了一个问题,然后循环20次直到linepick == line
但是...问题没有改变,所以你总是显示相同的问题。您可能想要阅读与随机选择的linepick
匹配的问题,因此您必须大致阅读linepick
行:
linepick = rand() % 20;
for (i = 0; i < linepick; i++)
{
if (fgets(chars, 1000, file)==NULL) break; // no such question
...