C语言结构体存管道字符串遇段错误,内存分配方式是否合理?
C结构体指针数组的内存分配问题
问题背景
- 定义了
trader结构体及对应数组:
struct trader { int pid; char *order[1000]; int number_of_orders; }; struct trader traders[50];
- 程序从管道读取字符串并尝试存入对应
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.
- 后续在
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会越界写入,导致内存损坏,甚至再次触发崩溃。
优化方案
- 按需动态分配:不要预分配所有内存,而是在每次获取到订单字符串时,根据实际长度分配内存:
// 替换原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 { // 处理内存分配失败的情况,比如记录错误信息 }
- 限制读取长度避免溢出:如果能确定订单字符串的最大长度,定义一个常量宏,读取时限制长度,同时按该长度分配内存:
#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);
- 务必释放内存:程序结束或不再使用
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
相关产品推荐
相关产品推荐

