C语言链表实现中指针值莫名变更问题求助
问题
我正在学习链表并尝试实现基础功能,编写了如下C语言代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_LEN_NAME 5 #define INSERT_NODE 1 #define APPEND_NODE 2 #define DEL_HEAD 3 #define DEL_TAIL 4 #define SHOW_LIST 5 struct people { int id; char name[MAX_LEN_NAME]; struct people *next; }; typedef struct people people_list; static void node_insert(people_list** head_ref, int id, const char* name); static void node_append(people_list** head_ref, int id, const char* name); static void node_del_head(people_list** head_ref); static void node_del_tail(people_list** head_ref); static void node_show(people_list** head_ref); static void node_insert(people_list** head_ref, int id, const char* name) { people_list* new_node = NULL; new_node = malloc(sizeof(people_list)); memset(new_node, 0, sizeof(people_list)); if (new_node == NULL) { printf("Fail to allocate memory for new node\n"); exit(1); } new_node->id = id; memcpy(new_node->name, name, sizeof(name)); new_node->next = *head_ref; *head_ref = new_node; } static void node_append(people_list** head_ref, int id, const char* name) { return; } static void node_del_head(people_list** head_ref) { return; } static void node_del_tail(people_list** head_ref) { return; } static void node_show(people_list** head_ref) { people_list* current = NULL; current = *head_ref; if (current == NULL) { printf("Empty list, nothing to show\n"); return; } printf("Elements in the list: \n"); while (current != NULL) { printf("id = %d, name = %s\n", current->id, current->name); current = current->next; if (current == NULL) { printf("This is the last element\n"); } } } int main(void) { people_list* list = NULL; #if 0 people_list* second = NULL; people_list* third = NULL; list = malloc(sizeof(people_list)); memset(list, 0, sizeof(people_list)); second = malloc(sizeof(people_list)); memset(second, 0, sizeof(people_list)); third = malloc(sizeof(people_list)); memset(third, 0, sizeof(people_list)); list->id = 1; memcpy(list->name, "duc", sizeof("duc")); list->next = second; second->id = 2; memcpy(second->name, "hy", sizeof("hy")); second->next = third; third->id = 3; memcpy(third->name, "bo", sizeof("bo")); third->next = NULL; #endif char id; char name[MAX_LEN_NAME] = {0}; int option = 0; while (1) { printf("******************\n"); printf("1: Insert new node\n"); printf("2: Append new node\n"); printf("3: Delete head node\n"); printf("4: Delete tail node\n"); printf("5: Show list\n"); printf("Insert your choice: "); scanf("%d", &option); switch (option) { case INSERT_NODE: printf("debug: list=%08Xh\n", list); printf("Enter id's value: "); scanf("%d", &id); printf("Enter name: "); scanf("%s", name); printf("debug: list=%08Xh\n", list); node_insert(&list, id, name); memset(name, 0, MAX_LEN_NAME); break; case APPEND_NODE: printf("Enter id's value: "); scanf("%d", &id); printf("Enter name: "); scanf("%s", name); node_insert(&list, id, name); memset(name, 0, MAX_LEN_NAME); break; case DEL_HEAD: node_del_head(&list); break; case DEL_TAIL: node_del_tail(&list); break; case SHOW_LIST: node_show(&list); break; default: printf ("Invalid input, closing program...\n"); exit(0); break; } } }
测试步骤:
- 插入第一个节点(id=1,name=jon)
- 插入第二个节点(id=2,name=may)
- 显示链表 => 仅第二个节点被打印
调试发现第二个节点的next并未指向第一个节点,而是指向NULL;进一步调试时,控制台日志显示:
Insert your choice: 1 debug: list=001F29A8h => 这是存储第一个节点的地址 Enter id's value: 2 Enter name: may debug: list=00000000h => 指针list的值被清空了???
可见指针list的值在未被显式修改的情况下发生了变更,请求帮忙修复该问题。
问题分析与修复
核心问题:内存越界覆盖指针
main函数中定义的id变量类型为char,但使用scanf("%d", &id)读取整数。char通常占1字节,而int占4字节,这会导致scanf写入时超出id的内存范围,覆盖了相邻的list指针内存,直接将list置为NULL。
次要问题:字符串拷贝长度错误
node_insert函数中使用memcpy(new_node->name, name, sizeof(name)),这里name是函数形参(指针类型),sizeof(name)得到的是指针的字节数(4或8),而非字符串长度,可能导致内存溢出或拷贝不完整,应该用MAX_LEN_NAME作为拷贝长度(确保不超过数组大小),同时手动添加字符串结束符。
其他小问题
APPEND_NODE分支错误调用了node_insert,应该调用node_append;node_append、node_del_head、node_del_tail函数未实现功能,这里补充基础实现。
修复后的完整代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_LEN_NAME 5 #define INSERT_NODE 1 #define APPEND_NODE 2 #define DEL_HEAD 3 #define DEL_TAIL 4 #define SHOW_LIST 5 struct people { int id; char name[MAX_LEN_NAME]; struct people *next; }; typedef struct people people_list; static void node_insert(people_list** head_ref, int id, const char* name); static void node_append(people_list** head_ref, int id, const char* name); static void node_del_head(people_list** head_ref); static void node_del_tail(people_list** head_ref); static void node_show(people_list** head_ref); static void node_insert(people_list** head_ref, int id, const char* name) { people_list* new_node = NULL; new_node = malloc(sizeof(people_list)); if (new_node == NULL) { printf("Fail to allocate memory for new node\n"); exit(1); } memset(new_node, 0, sizeof(people_list)); new_node->id = id; // 拷贝字符串,最多MAX_LEN_NAME-1个字符,留位置存结束符 strncpy(new_node->name, name, MAX_LEN_NAME - 1); new_node->name[MAX_LEN_NAME - 1] = '\0'; // 确保字符串结束 new_node->next = *head_ref; *head_ref = new_node; } static void node_append(people_list** head_ref, int id, const char* name) { people_list* new_node = malloc(sizeof(people_list)); if (new_node == NULL) { printf("Fail to allocate memory for new node\n"); exit(1); } memset(new_node, 0, sizeof(people_list)); new_node->id = id; strncpy(new_node->name, name, MAX_LEN_NAME - 1); new_node->name[MAX_LEN_NAME - 1] = '\0'; new_node->next = NULL; if (*head_ref == NULL) { *head_ref = new_node; return; } people_list* current = *head_ref; while (current->next != NULL) { current = current->next; } current->next = new_node; } static void node_del_head(people_list** head_ref) { if (*head_ref == NULL) { printf("List is empty, cannot delete head\n"); return; } people_list* temp = *head_ref; *head_ref = (*head_ref)->next; free(temp); } static void node_del_tail(people_list** head_ref) { if (*head_ref == NULL) { printf("List is empty, cannot delete tail\n"); return; } if ((*head_ref)->next == NULL) { free(*head_ref); *head_ref = NULL; return; } people_list* current = *head_ref; while (current->next->next != NULL) { current = current->next; } free(current->next); current->next = NULL; } static void node_show(people_list** head_ref) { people_list* current = *head_ref; if (current == NULL) { printf("Empty list, nothing to show\n"); return; } printf("Elements in the list: \n"); int count = 1; while (current != NULL) { printf("Element %d: id = %d, name = %s\n", count++, current->id, current->name); current = current->next; } printf("This is the end of the list\n"); } int main(void) { people_list* list = NULL; int id; // 修正为int类型,匹配scanf的%d格式 char name[MAX_LEN_NAME] = {0}; int option = 0; while (1) { printf("******************\n"); printf("1: Insert new node\n"); printf("2: Append new node\n"); printf("3: Delete head node\n"); printf("4: Delete tail node\n"); printf("5: Show list\n"); printf("Insert your choice: "); scanf("%d", &option); switch (option) { case INSERT_NODE: printf("debug: list=%08Xh\n", (unsigned int)list); printf("Enter id's value: "); scanf("%d", &id); printf("Enter name: "); scanf("%s", name); printf("debug: list=%08Xh\n", (unsigned int)list); node_insert(&list, id, name); memset(name, 0, MAX_LEN_NAME); break; case APPEND_NODE: printf("Enter id's value: "); scanf("%d", &id); printf("Enter name: "); scanf("%s", name); node_append(&list, id, name); // 修正为调用node_append memset(name, 0, MAX_LEN_NAME); break; case DEL_HEAD: node_del_head(&list); break; case DEL_TAIL: node_del_tail(&list); break; case SHOW_LIST: node_show(&list); break; default: printf ("Invalid input, closing program...\n"); exit(0); break; } } }
关键修改点总结
- 将
main中的char id改为int id,解决内存越界覆盖list指针的问题; - 修正
node_insert中的字符串拷贝逻辑,使用strncpy并手动添加结束符,避免溢出; - 实现
node_append、node_del_head、node_del_tail的基础功能; - 修正
APPEND_NODE分支的函数调用; - 优化
node_show的输出格式,更清晰显示链表元素。
内容的提问来源于stack exchange,提问作者dustin2022
相关产品推荐
相关产品推荐

