gpt4 book ai didi

c - 循环条件问题 - 文件结尾

转载 作者:行者123 更新时间:2023-12-04 10:56:35 25 4
gpt4 key购买 nike

当前代码迭代:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_LINE_SIZE 60
#define MAX_LIST_SIZE 15
#define MAX_QUIZ_SIZE 10

typedef struct question {
char *question;
char **choices;
int n_choices;
char *correct_answer;
} QUESTION;

char *dupString(const char *s) {
// copies a string
// CHECK TO SEE IF DUP WORKS

char *dup = malloc(strlen(s) + 1);
if (strcpy(dup, s)) {
return dup;
} else {
printf("Error duplicating string");
return 0;
}
}

void free_question(QUESTION *q) {
// free memory
for(int i = 0; i < q->n_choices; i++) {
free(q->choices[i]);
}
free(q->choices);
free(q->question);
free(q->correct_answer);

// set pointers to null
for(int i = 0; i < q->n_choices; i++) {
q->choices[i] = NULL;
}
q->choices = NULL;
q->question = NULL;
q->correct_answer = NULL;
}

static int read_info(FILE *pData, char **ptr)
{
char line[MAX_LINE_SIZE];
if (fgets(line, sizeof(line), pData) == 0 ||
(*ptr = dupString(line)) == 0)
return EOF;
return 0;
}

static int read_number(FILE *pData, int *num, QUESTION *q)
{
char line[MAX_LINE_SIZE];
if (fgets(line, sizeof(line), pData) == 0 ||
(*num = atoi(line)) < 2 || q->n_choices > 9)
return EOF;
return 0;
}

static int read_choices(FILE *pData, QUESTION *q)
{
char line[MAX_LINE_SIZE];
for (int i = 0; i < q->n_choices; i++)
{
if (fgets(line, sizeof(line), pData) == 0 ||
(q->choices[i] = dupString(line)) == 0)
return EOF;
}
return 0;
}

int parseQuestion(FILE *pData, int qnum, QUESTION *q)
{
*q = (QUESTION){ NULL, NULL, 0, NULL };

if (read_info(pData, &q->question) == EOF ||
read_number(pData, &q->n_choices, q) == EOF ||
(q->choices = calloc(q->n_choices, sizeof(char *))) == 0 ||
read_choices(pData, q) == EOF ||
read_info(pData, &q->correct_answer) == EOF)
{

return EOF;
}

return 0;
}

struct question makeQuestion(FILE *pData, QUESTION *q) {

int qIndex, numChoices;
char question[MAX_LINE_SIZE], temp[MAX_LINE_SIZE], choices[MAX_LINE_SIZE], correctAns[MAX_LINE_SIZE];

// Eat first line = QUESTION
fgets(question, MAX_LINE_SIZE, pData);
q->question = dupString(question);


// Eat second line = NUMBER OF CHOICES
fgets(temp, MAX_LINE_SIZE, pData);
numChoices = atoi(temp);
q->n_choices = numChoices;

// Allocate memory
q->choices = calloc(q->n_choices, sizeof(char*));

// Eat nth lines = CHOICES
for (qIndex=0; qIndex<=numChoices-1; qIndex++) {
fgets(choices, MAX_LINE_SIZE, pData);
q->choices[qIndex] = dupString(choices);
}

// Eat nth + 1 line = CORRECT ANSWER
fgets(correctAns, MAX_LINE_SIZE, pData);
q->correct_answer = dupString(correctAns);

return *q;
}

int ask(QUESTION *q) {
// Return 1 for correct guess, 0 for incorrect guess.

int choice;

printf("\n%s\n", q->question);

for (int i = 0; i <= q->n_choices-1; i++) {
printf("%d : %s", i+1, q->choices[i]);
}

do {
printf("Select an answer [1-%d]: ", q->n_choices);
scanf("%d", &choice);

if (choice == 0) {
return 2;
}

/* Check guess */
int ret;
size_t size = sizeof(q->correct_answer);
ret = memcmp(q->choices[choice-1], q->correct_answer, size);

if (ret == 0) {
return 1;
}
} while (choice < 1 || choice > q->n_choices);

return 0;
}


int main() {

int num = 0; // question being asked
int score = 0; // incorrect guesses
char temp[MAX_LINE_SIZE]; // temp for loop condition

FILE* pData;

char *filename = "tickle.txt";
char c;

if ((pData = fopen(filename, "r"))) {

printf("Welcome to the 2014 Quiz-festival!\n\n");
printf("Are you ready to begin? [Y/y]: ");
c = getchar();

if (c == 'Y' || c == 'y') {

QUESTION q;
while (parseQuestion(pData, ++num, &q) == 0) {
makeQuestion(pData, &q);

if (ask(&q) == 1) {
++score;
printf("Correct!\n");
} else {
printf("Oops, bad luck!\n");
}
free_choices(&q);
}

} else {
printf("Come back again.\n");
return 0;
}

} else {
printf("File failed to open.");
return 0;
}

fclose(pData);
return 0;
}
它似乎有效,但是,它从第二个测验开始。现在我完全糊涂了。
示例数据文件:

Question 1

3 (number of answers)

Answer 1a

Answer 1b

Answer 1c

Answer 1a (this is the correct answer)

Question 2

2

Answer 2a

Answer 2b

Answer 2b (this is the correct answer)


程序从问题 2 开始。内存有问题吗?我似乎无法绕过它。

最佳答案

parseQuestion()函数是检测 EOF 的函数,它应该返回一个值,指示是否有问题要处理(如果没有,则假设为 EOF)。

鉴于这种情况,我可能会重写它的界面:

QUESTION question;
while (parseQuestion(pData, ++num, &question) == 0)
{
…process a known-to-be-valid question…
}

我会让它做提示,传递文件指针、问题编号和指向它会填充的问题结构的指针。它会在成功时返回 0,在失败时返回一些其他值(可能是 EOF)。

这或多或少是在 C 中处理此类问题的标准方法。退一步,这就是您检查 fgets() 的方式。作品:
char line[4096];
while (fgets(line, sizeof(line), fp) != 0)
{
…process line…
}

你可能会重写 parseQuestion()像这样:
int parseQuestion(FILE *pData, int qnum, QUESTION *q)
{
char line[MAX_LINE_SIZE];

*q = (QUESTION){ NULL, NULL, 0, NULL };

printf("******** Question: %d ********\n", num);

if (fgets(line, sizeof(line), pData) == 0 ||
(q->question = dupString(line)) == 0)
return EOF;

if (fgets(line, sizeof(line), pData) == 0)
{
free_choices(q);
return EOF;
}
q->n_choices = atoi(line);
if (q->n_choices < 2 || q->n_choices > 9)
{
fprintf(stderr, "Invalid number of choices %d (should be 2..9)\n",
q->n_choices);
free_choices(q);
return EOF;
}

q->choices = calloc(q->n_choices, sizeof(char *));
if (q->choices == 0)
{
fprintf(stderr, "Memory allocation failed)\n");
free_choices(q);
return EOF;
}

for (int i = 0; i < q->n_choices; i++)
{
if (fgets(line, sizeof(line), pData) == 0 ||
(q->choices[i] = dupString(line)) == 0)
{
free_choices(q);
return EOF;
}
}

if (fgets(line, sizeof(line), pData) == 0 ||
(q->correct_answer = dupString(line)) == 0)
{
free_choices(q);
return EOF;
}

return 0;
}

但是,在错误处理中,该代码中有很多重复;您可能更愿意尝试摆脱其中的一些。您可以调用 free_choices()前第一 return EOF; ,但这无关紧要(但是当您处理错误时,边际性能开销并不重要)。使用 calloc()分配指针数组很重要;这意味着您可以安全地调用 free_choices()当数组被部分填充时。这样的观察导致:
static int read_info(FILE *pData, char **ptr)
{
char line[MAX_LINE_SIZE];
if (fgets(line, sizeof(line), pData) == 0 ||
(*ptr = dupString(line)) == 0)
return EOF;
return 0;
}

static int read_number(FILE *pData, int *num)
{
char line[MAX_LINE_SIZE];
if (fgets(line, sizeof(line), pData) == 0 ||
(*num = atoi(line)) < 2 || q->n_choices > 9)
return EOF;
return 0;
}

static int read_choices(FILE *pdata, QUESTION *q)
{
for (int i = 0; i < q->n_choices; i++)
{
if (fgets(line, sizeof(line), pData) == 0 ||
(q->choices[i] = dupString(choices)) == 0)
return EOF;
}
return 0;
}

int parseQuestion(FILE *pData, int qnum, QUESTION *q)
{
printf("******** Question: %d ********\n", num);
*q = (QUESTION){ NULL, NULL, 0, NULL };

if (read_info(pData, &q->question) == EOF ||
read_number(pData, &q->n_choices) == EOF ||
(q->choices = calloc(q->n_choices, sizeof(char *))) == 0 ||
read_choices(pData, q) == EOF ||
read_info(pData, &q->correct_answer) == EOF)
{
free_choices(q);
return EOF;
}

return 0;
}

你可以有 read_choices()调用 read_info()迭代而不是实现 read_info()read_choices() .任何代码通常都有改进的余地。

关于c - 循环条件问题 - 文件结尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23861274/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com