关于多项选择题程序的问题
Problems regarding an multiple choice question program
我创建了一个程序来生成多项选择考试的结果。该程序应该显示错误总数、空白答案和错误回答问题的数量。对于以下输入:
6
1..223
(这里.
表示空白答案)
123124
输出应该是:
Your result:
Mistakes: 3
Blanks: 2
Your mistakes are following:
4 5 6
Your blanks are following:
2 3
但代码显示未定义的行为。它似乎经历了无限循环。期待尽快解决我的问题。提前致谢。
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char data;
struct node* next;
}node;
void printNode(node* head)
{
node* local = head;
int i = 0;
if(local -> data == 0)
{
printf("0");
return;
}
while(local != NULL)
{
if(i == 3)
{
i = 0;
printf("\n");
}
printf("%d\t", local -> data);
local = local -> next;
++i;
}
}
void freeNode(node** head)
{
node* temp = (*head);
while((*head) != NULL)
{
(*head) = (*head) -> next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB, flagM, blnk, mstk;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if(n == 0)
return 0;
node* headM = (node*)malloc(sizeof(node));
node* nodeM;
node* headB = (node*)malloc(sizeof(node));
node* nodeB;
printf("Enter your given answers: ");
fflush(stdin);
for(i = 0; i < n; ++i)
{
scanf("%c", &ques[i]);
}
fflush(stdin);
ques[n] = '[=10=]';
printf("Enter the solution: ");
for(i = 0; i < n; ++i)
{
scanf("%c", &ans[i]);
}
ans[n] = '[=10=]';
for(i = 0; i < n; ++i)
{
if(ques[i] == '.')
{
++blnk;
if(flagB == 0)
{
headB -> data = i + 1;
headB -> next = NULL;
nodeB = headB;
continue;
}
nodeB -> next = (node*)malloc(sizeof(node));
nodeB = nodeB -> next;
nodeB -> data = i + 1;
nodeB-> next = NULL;
flagB = 1;
}
else if(ques[i] != ans[i])
{
++mstk;
if(flagM == 0)
{
headM -> data = i + 1;
headM -> next = NULL;
nodeM = headM;
continue;
}
nodeM -> next = (node*)malloc(sizeof(node));
nodeM = nodeM -> next;
nodeM -> data = i;
nodeM-> next = NULL;
flagM = 1;
}
}
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are follwing:\n");
printNode(headM);
printf("\nYour blanks are follwing:\n");
printNode(headB);
freeNode(&headM);
freeNode(&headM);
return 0;
}
我对这段代码做了一些修改,检查一下。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node node;
struct Node
{
int data;
struct Node * next;
};
void printNode(node *head)
{
node *local = head;
while (local != NULL)
{
printf("%d ", local->data);
local = local->next;
}
}
void freeNode(node **head)
{
node *temp = (*head);
while ((*head) != NULL)
{
(*head) = (*head)->next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB = 0, flagM = 0, blnk = 0, mstk = 0;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if (n == 0)
return 0;
node *headM = (node*) malloc(sizeof(node));
headM->data = 0;
node *nodeM = headM;
node *headB = (node*) malloc(sizeof(node));
headB->next = 0;
node *nodeB = headB;
printf("Enter your given answers: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ques[i]);
}
ques[n] = '[=10=]';
fflush(stdin);
printf("Enter the solution: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ans[i]);
}
ans[n] = '[=10=]';
fflush(stdin);
for (i = 0; i < n; ++i)
{
if (ques[i] == '.')
{ ++blnk;
if (flagB == 0)
{
nodeB->data = i + 1;
nodeB->next = NULL;
flagB = 1;
continue;
}
nodeB->next = (node*) malloc(sizeof(node));
nodeB = nodeB->next;
nodeB->data = i + 1;
nodeB->next = NULL;
}
else if (ques[i] != ans[i])
{ ++mstk;
if (flagM == 0)
{
nodeM->data = i + 1;
nodeM->next = NULL;
flagM = 1;
continue;
}
nodeM->next = (node*) malloc(sizeof(node));
nodeM = nodeM->next;
nodeM->data = i + 1;
nodeM->next = NULL;
//flagM = 1; //You made a mistake here
}
}
nodeM = headM;
nodeB = headB;
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are following question numbers:\n");
if (mstk != 0)
printNode(headM);
else
printf("No Mistakes\n");
printf("\nYour blanks are following question numbers:\n");
if (blnk != 0)
printNode(headB);
else
printf("No Blanks\n");
freeNode(&headM);
freeNode(&headM);
return 0;
}
这里有一些额外的想法。使您的代码非常复杂且难以调试并保持逻辑清晰的原因是您将 linked-list Add 函数混合在空白和错误的逻辑中,并使用特殊条件来处理添加第一个节点和后续节点。这使事情难以测试和调试。如果您需要向 linked-list 添加节点,则编写一个 add()
函数,您可以在将其用于代码之前对其进行彻底测试和调试。
您的 VLA ques
和 ans
太短,无法容纳 n
个字符的字符串,它们至少必须有 n + 1
个字符长才能为nul-termining 标记字符串结尾的字符。理想情况下,您将使它们至少长 2 个字符以同时容纳 '\n'
这将允许您使用 fgets()
进行输入而不是一次循环 scanf()
一个字符 - 这真是疯了。
您不需要将指针的地址传递给 freeNode()
只需传递一个指针即可。当然 freeNode()
将收到指针的副本——但它将包含原始地址——并且由于您不必对该指针进行任何更改以返回给调用者,因此无需传递指针的地址(完成后就没有任何列表需要担心了...)
所以将这些部分放在一起,添加一个 add()
函数以添加到您的链表(请参阅 Linus on Understanding Pointers 了解为什么使用 pointer-to-pointer 迭代到末尾),以及添加一个简单的 empty_stdin()
函数以删除 stdin
中剩余的 '\n'
,以便在稍后调用 fgets()
之前使用 scanf()
读取 n
13=] 和 ans
,你可以这样做:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple function to empty stdin to end-of-line */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
typedef struct node
{
int data;
struct node *next;
} node;
node *add(node **head, int v)
{
node **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*newn = malloc (sizeof *newn); /* allocate new node */
if (!newn) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
newn->data = v; /* initialize members values */
newn->next = NULL;
while (pn) { /* iterate to end of list */
ppn = &pn->next;
pn = pn->next;
}
return *ppn = newn; /* add & return new node */
}
void printNode (node *head)
{
for (; head; head = head->next)
printf (" %d", head->data);
putchar ('\n');
}
void freeNode(node *head)
{
while (head != NULL)
{
node *victim = head;
head = head->next;
free(victim);
}
}
int main()
{
int n, i, blnk, mstk;
blnk = mstk = 0;
node *headM = NULL; /* declare pointers and initialize NULL */
node *headB = NULL;
printf ("Enter the number of questions: ");
/* you must VALIDATE every user-input */
if (scanf ("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
empty_stdin(); /* remove '\n' (and any other chars from user) */
/* before calling fgets() below */
if (n == 0) /* check 0 BEFORE VLA declaration */
return 0;
char ques[2*n], ans[2*n]; /* declare question/answer VLAs, don't skimp */
printf("Enter your given answers: ");
if (!fgets(ques, sizeof ques, stdin)) /* read ques from stdin */
return 1;
ques[strcspn(ques, "\r\n")] = 0; /* trim '\n' from end of ques */
printf("Enter the solution: ");
if (!fgets(ans, sizeof ans, stdin)) /* read ans from stdin */
return 1;
ans[strcspn(ans, "\r\n")] = 0; /* ditto for ans */
for(i = 0; i < n; ++i) /* loop n times */
{
if(ques[i] == '.') /* if blank */
{
add (&headB, i + 1); /* add to list headB */
++blnk; /* increment counter */
}
else if(ques[i] != ans[i]) /* if mistake */
{
add (&headM, i + 1); /* add to list headM */
++mstk; /* increment counter */
}
}
printf ("Your result:\n\tMistakes: %d\n\tBlanks: %d\n"
"Your mistakes are following:\n", mstk, blnk);
printNode(headM);
printf("\nYour blanks are following:\n");
printNode(headB);
freeNode(headM); /* no need to pass the address of the pointer to free */
freeNode(headB); /* there won't be a list left when freeNode is done */
return 0;
}
内容很多,慢慢看吧
例子Use/Output
$ ./bin/llquestions
Enter the number of questions: 6
Enter your given answers: 1..223
Enter the solution: 123124
Your result:
Mistakes: 2
Blanks: 2
Your mistakes are following:
4 6
Your blanks are following:
2 3
(注意:1..223
和123124
中的,5
不是错误,2
在正确的位置在最后)
检查一下,如果您还有其他问题,请告诉我。
我创建了一个程序来生成多项选择考试的结果。该程序应该显示错误总数、空白答案和错误回答问题的数量。对于以下输入:
6
1..223
(这里.
表示空白答案)
123124
输出应该是:
Your result:
Mistakes: 3
Blanks: 2
Your mistakes are following:
4 5 6
Your blanks are following:
2 3
但代码显示未定义的行为。它似乎经历了无限循环。期待尽快解决我的问题。提前致谢。
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char data;
struct node* next;
}node;
void printNode(node* head)
{
node* local = head;
int i = 0;
if(local -> data == 0)
{
printf("0");
return;
}
while(local != NULL)
{
if(i == 3)
{
i = 0;
printf("\n");
}
printf("%d\t", local -> data);
local = local -> next;
++i;
}
}
void freeNode(node** head)
{
node* temp = (*head);
while((*head) != NULL)
{
(*head) = (*head) -> next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB, flagM, blnk, mstk;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if(n == 0)
return 0;
node* headM = (node*)malloc(sizeof(node));
node* nodeM;
node* headB = (node*)malloc(sizeof(node));
node* nodeB;
printf("Enter your given answers: ");
fflush(stdin);
for(i = 0; i < n; ++i)
{
scanf("%c", &ques[i]);
}
fflush(stdin);
ques[n] = '[=10=]';
printf("Enter the solution: ");
for(i = 0; i < n; ++i)
{
scanf("%c", &ans[i]);
}
ans[n] = '[=10=]';
for(i = 0; i < n; ++i)
{
if(ques[i] == '.')
{
++blnk;
if(flagB == 0)
{
headB -> data = i + 1;
headB -> next = NULL;
nodeB = headB;
continue;
}
nodeB -> next = (node*)malloc(sizeof(node));
nodeB = nodeB -> next;
nodeB -> data = i + 1;
nodeB-> next = NULL;
flagB = 1;
}
else if(ques[i] != ans[i])
{
++mstk;
if(flagM == 0)
{
headM -> data = i + 1;
headM -> next = NULL;
nodeM = headM;
continue;
}
nodeM -> next = (node*)malloc(sizeof(node));
nodeM = nodeM -> next;
nodeM -> data = i;
nodeM-> next = NULL;
flagM = 1;
}
}
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are follwing:\n");
printNode(headM);
printf("\nYour blanks are follwing:\n");
printNode(headB);
freeNode(&headM);
freeNode(&headM);
return 0;
}
我对这段代码做了一些修改,检查一下。
#include <stdio.h>
#include <stdlib.h>
typedef struct Node node;
struct Node
{
int data;
struct Node * next;
};
void printNode(node *head)
{
node *local = head;
while (local != NULL)
{
printf("%d ", local->data);
local = local->next;
}
}
void freeNode(node **head)
{
node *temp = (*head);
while ((*head) != NULL)
{
(*head) = (*head)->next;
free(temp);
temp = (*head);
}
}
int main()
{
int n, i, flagB = 0, flagM = 0, blnk = 0, mstk = 0;
blnk = mstk = flagB = flagM = 0;
printf("Enter the number of questions: ");
scanf("%d", &n);
char ques[n], ans[n];
if (n == 0)
return 0;
node *headM = (node*) malloc(sizeof(node));
headM->data = 0;
node *nodeM = headM;
node *headB = (node*) malloc(sizeof(node));
headB->next = 0;
node *nodeB = headB;
printf("Enter your given answers: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ques[i]);
}
ques[n] = '[=10=]';
fflush(stdin);
printf("Enter the solution: ");
for (i = 0; i < n; ++i)
{
scanf("%s", &ans[i]);
}
ans[n] = '[=10=]';
fflush(stdin);
for (i = 0; i < n; ++i)
{
if (ques[i] == '.')
{ ++blnk;
if (flagB == 0)
{
nodeB->data = i + 1;
nodeB->next = NULL;
flagB = 1;
continue;
}
nodeB->next = (node*) malloc(sizeof(node));
nodeB = nodeB->next;
nodeB->data = i + 1;
nodeB->next = NULL;
}
else if (ques[i] != ans[i])
{ ++mstk;
if (flagM == 0)
{
nodeM->data = i + 1;
nodeM->next = NULL;
flagM = 1;
continue;
}
nodeM->next = (node*) malloc(sizeof(node));
nodeM = nodeM->next;
nodeM->data = i + 1;
nodeM->next = NULL;
//flagM = 1; //You made a mistake here
}
}
nodeM = headM;
nodeB = headB;
printf("Your result:\n\tMistakes: %d\n\tBlanks: %d\n", mstk, blnk);
printf("Your mistakes are following question numbers:\n");
if (mstk != 0)
printNode(headM);
else
printf("No Mistakes\n");
printf("\nYour blanks are following question numbers:\n");
if (blnk != 0)
printNode(headB);
else
printf("No Blanks\n");
freeNode(&headM);
freeNode(&headM);
return 0;
}
这里有一些额外的想法。使您的代码非常复杂且难以调试并保持逻辑清晰的原因是您将 linked-list Add 函数混合在空白和错误的逻辑中,并使用特殊条件来处理添加第一个节点和后续节点。这使事情难以测试和调试。如果您需要向 linked-list 添加节点,则编写一个 add()
函数,您可以在将其用于代码之前对其进行彻底测试和调试。
您的 VLA ques
和 ans
太短,无法容纳 n
个字符的字符串,它们至少必须有 n + 1
个字符长才能为nul-termining 标记字符串结尾的字符。理想情况下,您将使它们至少长 2 个字符以同时容纳 '\n'
这将允许您使用 fgets()
进行输入而不是一次循环 scanf()
一个字符 - 这真是疯了。
您不需要将指针的地址传递给 freeNode()
只需传递一个指针即可。当然 freeNode()
将收到指针的副本——但它将包含原始地址——并且由于您不必对该指针进行任何更改以返回给调用者,因此无需传递指针的地址(完成后就没有任何列表需要担心了...)
所以将这些部分放在一起,添加一个 add()
函数以添加到您的链表(请参阅 Linus on Understanding Pointers 了解为什么使用 pointer-to-pointer 迭代到末尾),以及添加一个简单的 empty_stdin()
函数以删除 stdin
中剩余的 '\n'
,以便在稍后调用 fgets()
之前使用 scanf()
读取 n
13=] 和 ans
,你可以这样做:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple function to empty stdin to end-of-line */
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
typedef struct node
{
int data;
struct node *next;
} node;
node *add(node **head, int v)
{
node **ppn = head, /* pointer to pointer to head */
*pn = *head, /* pointer to head */
*newn = malloc (sizeof *newn); /* allocate new node */
if (!newn) { /* validate allocation */
perror ("malloc-node");
return NULL;
}
newn->data = v; /* initialize members values */
newn->next = NULL;
while (pn) { /* iterate to end of list */
ppn = &pn->next;
pn = pn->next;
}
return *ppn = newn; /* add & return new node */
}
void printNode (node *head)
{
for (; head; head = head->next)
printf (" %d", head->data);
putchar ('\n');
}
void freeNode(node *head)
{
while (head != NULL)
{
node *victim = head;
head = head->next;
free(victim);
}
}
int main()
{
int n, i, blnk, mstk;
blnk = mstk = 0;
node *headM = NULL; /* declare pointers and initialize NULL */
node *headB = NULL;
printf ("Enter the number of questions: ");
/* you must VALIDATE every user-input */
if (scanf ("%d", &n) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
empty_stdin(); /* remove '\n' (and any other chars from user) */
/* before calling fgets() below */
if (n == 0) /* check 0 BEFORE VLA declaration */
return 0;
char ques[2*n], ans[2*n]; /* declare question/answer VLAs, don't skimp */
printf("Enter your given answers: ");
if (!fgets(ques, sizeof ques, stdin)) /* read ques from stdin */
return 1;
ques[strcspn(ques, "\r\n")] = 0; /* trim '\n' from end of ques */
printf("Enter the solution: ");
if (!fgets(ans, sizeof ans, stdin)) /* read ans from stdin */
return 1;
ans[strcspn(ans, "\r\n")] = 0; /* ditto for ans */
for(i = 0; i < n; ++i) /* loop n times */
{
if(ques[i] == '.') /* if blank */
{
add (&headB, i + 1); /* add to list headB */
++blnk; /* increment counter */
}
else if(ques[i] != ans[i]) /* if mistake */
{
add (&headM, i + 1); /* add to list headM */
++mstk; /* increment counter */
}
}
printf ("Your result:\n\tMistakes: %d\n\tBlanks: %d\n"
"Your mistakes are following:\n", mstk, blnk);
printNode(headM);
printf("\nYour blanks are following:\n");
printNode(headB);
freeNode(headM); /* no need to pass the address of the pointer to free */
freeNode(headB); /* there won't be a list left when freeNode is done */
return 0;
}
内容很多,慢慢看吧
例子Use/Output
$ ./bin/llquestions
Enter the number of questions: 6
Enter your given answers: 1..223
Enter the solution: 123124
Your result:
Mistakes: 2
Blanks: 2
Your mistakes are following:
4 6
Your blanks are following:
2 3
(注意:1..223
和123124
中的,5
不是错误,2
在正确的位置在最后)
检查一下,如果您还有其他问题,请告诉我。