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

结构体指针无法访问二维char数组值,循环外内容为空

电路模拟程序的两个核心问题:params输出异常与内存错误

问题描述

我正在编写一个模拟电路的程序,定义了如下Gate与Node结构体:

typedef struct Gate
{
    kind_t kind;
    int size;     // size of DECODER and MULTIPLEXER
    char **params; // length determined by kind and size (CHANGED FROM INT TO CHAR)
                  // includes inputs and outputs, indicated by variable numbers
} Gate;

typedef struct Node
{
    Gate *data;
    struct Node *next;
} Node;

在读取文件构建门电路链表的while循环内,printf可正常输出params数组内容,但循环外的for循环输出为空。相关逻辑代码如下:

// Linked list of gates & attributes
while (fscanf(fp, "%16s", str) != EOF)
{
    if (strcmp(str, "AND") == 0)
    {
        head = makeGate(fp, head, AND);
        length++;
    }
    else if (strcmp(str, "OR") == 0)
    {
        head = makeGate(fp, head, OR);
        length++;
    }
    else if (strcmp(str, "NAND") == 0)
    {
        head = makeGate(fp, head, NAND);
        length++;
    }
    else if (strcmp(str, "NOR") == 0)
    {
        head = makeGate(fp, head, NOR);
        length++;
    }
    else if (strcmp(str, "XOR") == 0)
    {
        head = makeGate(fp, head, XOR);
        length++;
    }
    else if (strcmp(str, "NOT") == 0)
    {
        //head = makeGate(fp, head, NOT);
        //length++;
    }
    else if (strcmp(str, "PASS") == 0)
    {
        //head = makeGate(fp, head, PASS);
        //length++;
    }
    else if (strcmp(str, "DECODER") == 0)
    {
        //
    }
    else if (strcmp(str, "MULTIPLEXER") == 0)
    {
        //
    }
    printf("%s\n", head->data->params[2]);
}

// plugs in values to circuit
for (int i = 0; i < 3; i++)
{
    printf("Stored string: %s\n", head->data->params[i]);
}

makeGate函数实现如下:

Node *makeGate(FILE *fp, Node *head, kind_t inGate)
{
    char str[17];
    Node *new_node = (Node *)malloc(sizeof(Node)); // Node of linkedlist that contains gate structure
    new_node->data = (Gate *)malloc(sizeof(Gate)); // Gate structure that keeps information about a gate
    new_node->next = head;

    new_node->data->kind = inGate;
    new_node->data->size = 3;
    new_node->data->params = malloc(3 * sizeof(char*));
    for (int i = 0; i < 3; i++)
    {
        new_node->data->params[i] = malloc(17 * sizeof(char));
    }

    fscanf(fp, "%16s", str);
    new_node->data->params[0] = str;
    fscanf(fp, "%16s", str);
    new_node->data->params[1] = str;
    fscanf(fp, "%16s", str);
    new_node->data->params[2] = str;
    return new_node;
}

此外,程序存在内存泄漏问题,尝试释放内存时会触发“释放未malloc地址”的错误,怀疑可能是节点丢失,但暂无解决思路。


问题1:params输出异常的原因与修复

核心原因

makeGate函数中,你为params的每个元素都分配了堆内存,但随后直接把栈上的str数组地址赋值给了params[i]。栈内存在函数返回后会被系统回收或被其他操作覆盖,所以循环内(makeGate刚执行完,栈内存尚未被破坏)能正常输出,但循环外栈内存已失效,导致输出为空或垃圾值。

修复方案

不要直接赋值指针,而是用strcpy把str的内容复制到已经分配好的堆内存中:

// 替换makeGate中赋值的部分
fscanf(fp, "%16s", str);
strcpy(new_node->data->params[0], str);
fscanf(fp, "%16s", str);
strcpy(new_node->data->params[1], str);
fscanf(fp, "%16s", str);
strcpy(new_node->data->params[2], str);

这样params的每个元素都指向堆上保存的字符串副本,不会随栈内存失效而丢失。


问题2:内存泄漏与释放错误的原因与修复

核心原因

  1. 节点丢失:链表采用头插法构建,但如果未完整遍历整个链表就释放内存,会导致后续节点无法被访问,造成内存泄漏。
  2. 释放顺序错误:释放内存需要从内到外逐层进行:先释放params的每个字符串,再释放params数组,接着释放Gate结构体,最后释放Node节点。顺序颠倒或跳过某一步,会触发内存错误。
  3. 错误释放栈地址:之前的代码中params[i]指向栈内存,尝试释放这些地址会触发“释放未malloc地址”的错误,修复问题1后该情况会消失,但仍需注意释放顺序。

修复方案

编写专门的内存释放函数,遍历整个链表并逐层释放内存:

void freeCircuit(Node *head) {
    Node *current = head;
    while (current != NULL) {
        Node *next = current->next;
        // 释放params的每个字符串
        for (int i = 0; i < current->data->size; i++) {
            free(current->data->params[i]);
        }
        // 释放params数组
        free(current->data->params);
        // 释放Gate结构体
        free(current->data);
        // 释放Node节点
        free(current);
        current = next;
    }
}

使用时直接调用freeCircuit(head)即可完整释放所有分配的内存,避免泄漏和释放错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:05:15