关于多项选择题程序的问题

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 quesans 太短,无法容纳 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..223123124中的5不是错误,2在正确的位置在最后)

检查一下,如果您还有其他问题,请告诉我。