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

C语言中用指针替代数组实现链表节点添加的异常问题排查

问题与修复方案

问题现象

实现链表数字列表程序时,计划用atoi转换用户输入的整数并反向添加到链表(如原链表3,4,5添加1,2后预期为1,2,3,4,5),但添加节点时仅第一个值正确,其余均为垃圾值,且原链表数据会丢失。

核心错误点

  1. 数组指针赋值错误:main中*numbers = *nodes(input, amount);仅复制了nodes返回数组的第一个元素,未完整复制整个数组,且重复malloc导致内存泄漏。
  2. 循环终止条件错误:add函数中用numbers[a] != '\0'判断数组结束,int数组不会以'\0'(即0)作为结束标志,若输入包含0会提前终止,否则会越界访问垃圾值。
  3. 原链表提前释放:main中打印原链表后直接释放了所有节点,导致后续添加时原链表已为空,无法实现追加效果。
  4. 数组内存分配不通用:nodes函数中malloc(amount * 4)硬编码int字节数,应使用sizeof(int)保证跨平台兼容性。
  5. 输入循环条件错误:main中的输入验证循环用c != 'd' || c != 'a' || c != 'f'作为条件,逻辑永远为真,会导致无限循环,应改为逻辑与c != 'd' && c != 'a' && c != 'f'。

修复后的完整代码

// Implements a list of numbers using a linked list

#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node
{
    int number;
    struct node *next;
}
node;

node *makelist(int argc, char *argv[]);
int check_spaces(char *input);
int *nodes(char *input, int amount);
node *add(node *list, int *numbers, int amount);

/*int delete();
int find();*/

int main(int argc, char *argv[])
{
    // Get linked list
    node *list = makelist(argc, argv);
    // Print linked list
    for (node *ptr = list; ptr != NULL; ptr = ptr->next)
    {
        printf("%i ", ptr->number);
    }
    printf("\n");

    char c;
    // Give choices
    printf("Do you want to (d)delete a node, (a)add a node, or (f)find a node? ");
    // Repeat if incorrect input
    do
    {
        // 处理输入缓冲区的换行符
        scanf(" %c", &c);
        if (c == 'd' || c == 'a' || c == 'f')
        {
            break;
        }
        else
        {
            printf("Wrong input, try again. ");
        }
    }
    while (c != 'd' && c != 'a' && c != 'f'); // 修正循环条件

    // If user chose to "add" node(s)
    if (c == 'a')
    {
        char *input = get_string("What are the node(s) that you want to add? ");
        int amount = check_spaces(input);
        int *numbers = nodes(input, amount); // 直接接收nodes返回的指针,无需重复malloc
        list = add(list, numbers, amount);
        
        // 打印更新后的链表
        printf("Updated list: ");
        for (node *ptr2 = list; ptr2 != NULL; ptr2 = ptr2->next)
        {
            printf("%i ", ptr2->number);
        }
        printf("\n");

        free(numbers);
    }
    // If user chose to "delete" node(s)
    else if (c == 'd')
    {
        printf("Delete function not implemented yet.\n");
    }
    // If user chose to "find" node(s)
    else
    {
        printf("Find function not implemented yet.\n");
    }

    // 最后统一释放链表内存
    node *ptr = list;
    while (ptr != NULL)
    {
        node *next = ptr->next;
        free(ptr);
        ptr = next;
    }

    return 0;
}

// Make linked list
node *makelist(int argc, char *argv[])
{
    // Memory for numbers
    node *list = NULL;

    // For each command-line argument
    for (int i = 1; i < argc; i++)
    {
        // Convert argument to int
        int number = atoi(argv[i]);

        // Allocate node for number
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            // 内存分配失败时,释放已分配的节点
            node *ptr = list;
            while (ptr != NULL)
            {
                node *next = ptr->next;
                free(ptr);
                ptr = next;
            }
            return NULL;
        }
        n->number = number;
        n->next = NULL;

        // If list is empty
        if (list == NULL)
        {
            // This node is the whole list
            list = n;
        }
        // If list has numbers already
        else
        {
            // Iterate over nodes in list
            for (node *ptr = list; ptr != NULL; ptr = ptr->next)
            {
                // If at end of list
                if (ptr->next == NULL)
                {
                    // Append node
                    ptr->next = n;
                    break;
                }
            }
        }
    }
    return list;
}

// Add function: 将numbers数组中的元素按顺序头插,实现1,2添加后在原链表前
node *add(node *list, int *numbers, int amount)
{
    // 遍历numbers数组,依次头插每个元素
    for (int i = 0; i < amount; i++)
    {
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            // 内存分配失败时,释放已分配的新节点和原链表
            node *ptr = list;
            while (ptr != NULL)
            {
                node *next = ptr->next;
                free(ptr);
                ptr = next;
            }
            return NULL;
        }
        n->number = numbers[i];
        // Prepend node to list
        n->next = list;
        list = n;
    }
    return list;
}

// Parse input string to int array
int *nodes(char *input, int amount)
{
    int *y = malloc(amount * sizeof(int));
    if (y == NULL)
    {
        return NULL;
    }
    char *x = input;
    y[0] = atoi(x);
    int i = 0;
    int j = 1;
    while (input[i] != '\0')
    {
        if (input[i] == ' ')
        {
            // 跳过连续空格
            while (input[i+1] == ' ')
            {
                i++;
            }
            x = &input[i+1];
            y[j] = atoi(x);
            j++;
        }
        i++;
    }
    return y;
}

// Count number of numbers in input string
int check_spaces(char *input)
{
    if (strlen(input) == 0)
    {
        return 0;
    }
    int numbers = 1;
    int i = 0;
    while (input[i] != '\0')
    {
        if (input[i] == ' ')
        {
            // 跳过连续空格,避免重复计数
            while (input[i+1] == ' ')
            {
                i++;
            }
            numbers++;
        }
        i++;
    }
    return numbers;
}

/*int delete()
{

}
int find()
{

}*/

关键修复说明

  1. 修正数组指针赋值:删除main中重复的malloc操作,直接用int *numbers = nodes(input, amount);接收动态数组指针,避免内存泄漏和不完整复制。
  2. 修正循环逻辑:add函数改用已知的amount作为循环次数,确保遍历所有输入数字;修正输入验证循环的逻辑运算符,避免无限循环。
  3. 调整内存释放时机:将原链表的释放操作移到程序末尾,保证添加节点时原链表数据存在。
  4. 优化输入处理:在check_spaces和nodes函数中处理连续空格,避免重复计数或转换错误;修正scanf格式符,跳过输入缓冲区的换行符。
  5. 添加容错处理:在makelist和add函数中添加内存分配失败时的资源清理逻辑,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:12:05