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

C语言结构体存管道字符串遇段错误,内存分配方式是否合理?

C结构体指针数组的内存分配问题

问题背景

  1. 定义了trader结构体及对应数组:
struct trader {
    int pid;
    char *order[1000];
    int number_of_orders;
};

struct trader traders[50];
  1. 程序从管道读取字符串并尝试存入对应trader的order数组,原实现触发段错误:
for(int i = 0; i< sizeof(traders) / sizeof(struct trader); ++i){
        if(child_pid == traders[i].pid){
            int pip_read = read(fdTrader, read_input, sizeof read_input);
            read_input[pip_read] = '\0';
            read_input[strlen(read_input)-1] = '\0';

            if(traders[i].number_of_orders < 1000){
                strcpy(traders[i].order[traders[i].number_of_orders], read_input);
                traders[i].number_of_orders++;
            }

            write(fdExchange, "ACCEPTED 0;", strlen("ACCEPTED 0;"));
            kill(child_pid, SIGUSR1);
            init_orderbook(i,read_input,traders[i]);
        }
    }

段错误信息:

==60==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f23dd6a7166 bp 0x7ffedaee18f0 sp 0x7ffedaee18c8 T0)
==60==The signal is caused by a WRITE memory access.
==60==Hint: address points to the zero page.
  1. 后续在main函数中添加了内存分配代码,询问该方式是否合理:
for (int i = 0; i < 50; i++) {
    for (int j = 0; j < 1000; j++) {
        traders[i].order[j] = malloc(50 * sizeof(char));
    }
}

问题分析与解答

原段错误根源

段错误的核心原因是:trader结构体中的order是指针数组,默认初始化后所有指针都是NULL野指针。原代码直接调用strcpy往traders[i].order[xxx](即NULL地址)写入数据,触发了对零页内存的非法写操作,这正是AddressSanitizer报错的原因。

现有内存分配方式的合理性

你当前的预分配方式能解决段错误,但存在明显的内存浪费和潜在风险:

  • 可行之处:为每个order指针分配了50字节的合法内存,strcpy有了有效写入地址,不会再触发野指针错误。
  • 不合理之处:
    • 内存浪费:提前给50个trader的1000个order全部分配内存,但实际场景中大部分trader可能不会产生这么多订单,大量内存会被闲置。
    • 缓冲区溢出风险:固定分配50字节,如果读取的字符串长度超过50,strcpy会越界写入,导致内存损坏,甚至再次触发崩溃。

优化方案

  1. 按需动态分配:不要预分配所有内存,而是在每次获取到订单字符串时,根据实际长度分配内存:
// 替换原strcpy代码块
size_t input_len = strlen(read_input);
char *order_buf = malloc(input_len + 1); // 额外分配1字节存储字符串终止符
if (order_buf != NULL) {
    strcpy(order_buf, read_input);
    traders[i].order[traders[i].number_of_orders] = order_buf;
    traders[i].number_of_orders++;
} else {
    // 处理内存分配失败的情况,比如记录错误信息
}
  1. 限制读取长度避免溢出:如果能确定订单字符串的最大长度,定义一个常量宏,读取时限制长度,同时按该长度分配内存:
#define MAX_ORDER_LENGTH 50

// 读取管道时限制长度,预留终止符空间
int pip_read = read(fdTrader, read_input, MAX_ORDER_LENGTH - 1);
if (pip_read > 0) {
    read_input[pip_read] = '\0';
    // 后续处理...
}

// 分配内存时使用固定长度
traders[i].order[traders[i].number_of_orders] = malloc(MAX_ORDER_LENGTH);
  1. 务必释放内存:程序结束或不再使用traders数组时,遍历所有已分配的指针释放内存,避免内存泄漏:
for (int i = 0; i < 50; i++) {
    for (int j = 0; j < traders[i].number_of_orders; j++) {
        free(traders[i].order[j]);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:09:59