【问题标题】:Linked list not accepting new nodes when called in a loop循环调用时链表不接受新节点
【发布时间】:2021-11-10 06:31:05
【问题描述】:

代码的问题是我不能在不影响之前分配的节点的情况下分配新节点,同时使用 switch。它不断使用最新的给定节点输入重新分配

链表结构节点链表的结构分配如下

typedef struct stringData {
char *s;
struct stringData *next;
} Node;

创建插入和打印链表下面是创建和打印链表的代码

Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = s;
newNode->next = NULL;
return newNode;
}

void insert(Node **link, Node *newNode) {
newNode->next = *link;
*link = newNode;
}

void printList(Node *head) {
while (head != NULL) {
    printf("%s\n", head->s);
    head = head->next;
}
}

ma​​in 编译时我无法在运行时分配链表,也就是说,我必须在切换时分配多个节点。如何我可以删除这个错误吗?

Node *head = NULL;
Node *tail = NULL;
Node *n;

char message_arr[10] = {};
int choice =0;  
int len;
char str[20];

n = createNode("Hi");
insert(&head, n);
tail = n;
        
        
n = createNode("Hello");
insert(&tail->next, n);
tail = n;
       
        
        
        
n = createNode("How are you");
insert(&tail->next, n);
tail = n;
int index,ind;       
        
        
 while(choice!=6)       
 
 {
 printf("\nChoose one option from the list\n");  
    printf("\n 1. New Message  2. Display all messages  3.Delete all messages\n");  
    printf("\nEnter your choice?\n");         
    scanf("\n%d",&choice);  
    switch(choice)  
    {  
        case 1:  
        printf("\nEnter new message\n");
        scanf("%s",message_arr);
        
        n = createNode(message_arr);
        insert(&tail->next, n);
        tail = n;
        break;  
          
        case 2:  
        printf("\nMessages so far:\n\n");
        printList(head);     
        break;  
        
        case 3:
        printf("\nDeleting all messages.....\n");
        free_list(head);
         printf("\nMessages deleted.....\n");
        break;
        case 6:
        exit(0); 
        
        break;  
        default:  
        printf("Please enter valid choice."); 
        
        
          
    }  
    
    
 }
return(0);    

输出 从列表中选择一个选项 1. 新消息 2. 阅读消息 3. 显示所有消息 4. 删除一条消息 5. 删除所有消息

Enter your choice?
1

Enter new message
morning


Choose one option from the list 1. New Message  2. Read a Message  3. 
Display all messages  4. Delete a message 5.Delete all messages

Enter your choice?
1

Enter new message
giya

Choose one option from the list

1. New Message  2. Read a Message  3. Display all messages  4. Delete a 
message 5.Delete all messages

Enter your choice?
3

Messages so far:

Hi
Hello
How are you
giya
giya

当我调用交换机的第一个案例输入“新消息”两次时,已经分配的第一个消息也被第二个替换并显示两次为giyagiya

【问题讨论】:

  • 请注意,每个节点都将指向同一个字符串,因此数据将是最新条目。欢迎来到 StackOverflow!请发布完整的Minimal Reproducible Example,可以复制/粘贴和编译。我建议您使用tour 并阅读How do I ask a good question?
  • "编译时无法在运行时分配链表"。那是什么意思?为什么“不能”?是否有错误或不正确的行为?请给出准确的输入、预期行为和实际行为。
  • scanf("\n%d",&choice); ==> scanf("%d",&choice); 并始终检查 scanf 返回的值。那就是进行的转换次数。此外,您没有限制输入到 char message_arr[10] 的字符串长度,最大为 9,因此您可以轻松进行缓冲区溢出。
  • C 和 C++ 是非常不同的语言。除非您询问它们的差异,否则请不要同时标记两者。
  • 我也更新了我的输出,你能检查一下@kaylum

标签: c++ c switch-statement runtime-error singly-linked-list


【解决方案1】:

>当我调用交换机的第一个案例输入“新消息”两次时,已经分配的第一个消息也被第二个替换,并显示两次为giyagiya em>

原因是您所有新创建的节点s 成员指针都指向同一个缓冲区message_arr。这就是为什么在显示它们时,它们都会打印message_arr 缓冲区的当前内容,这是您输入的最后一个值。

为了更好地理解它:

首先您为列表中新创建的节点输入值morning

     ---------
 --->|   |   |-->NULL     
     ---------            
       |
       |                   message_arr
       |                  ---------------------
       |_________________>|m|o|r|n|i|n|g| | | |
                          ---------------------

那么您在列表中为新创建的节点输入了值giya

     ---------   ---------
 --->|   |   |-->|   |   |--->NULL  
     ---------   ---------         
       |           |
       |           |        message_arr
       |           |----> ---------------------
       |----------------->|g|i|y|a| | | | | | |
                          ---------------------

为了解决这个问题,在创建新节点后,你应该为Node结构的s指针成员分配内存,并将message_arr缓冲区的内容复制到分配的内存中。或者,您可以使用strdup() 来解决此问题:

Node *createNode(char *s) {
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->s = strdup(s);    // <----------

strdup() 函数返回一个指向新字符串的指针,该字符串是传递给它的字符串的副本。 strdup() 为新字符串分配内存并返回其指针。完成后请务必使用free() 释放它。请注意,strdup() 不是 C 标准的一部分。

由于您已将CC++ 标签添加到您的问题中,因此这种初始化方式很重要:

char message_arr[10] = {};

空初始化器符合C++ 标准,但在C 中不符合标准,尽管一些C 编译器接受它。

C,你应该这样做:

char message_arr[10] = {0};

这在C++ 中也是可以接受的。

遵循良好的编程习惯,确保检查malloc()scanf() 等的返回值。另外,确保检查choice 的用户输入是否有效。您应该检查,当用户将输入作为choice 提示符的某个字符而不是数字时会发生什么!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多