You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
        }
    }
}

测试步骤:

  1. 插入第一个节点(id=1,name=jon)
  2. 插入第二个节点(id=2,name=may)
  3. 显示链表 => 仅第二个节点被打印

调试发现第二个节点的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;
        }
    }
}

关键修改点总结

  1. 将main中的char id改为int id,解决内存越界覆盖list指针的问题;
  2. 修正node_insert中的字符串拷贝逻辑,使用strncpy并手动添加结束符,避免溢出;
  3. 实现node_append、node_del_head、node_del_tail的基础功能;
  4. 修正APPEND_NODE分支的函数调用;
  5. 优化node_show的输出格式,更清晰显示链表元素。

内容的提问来源于stack exchange,提问作者dustin2022

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:01:00