C语言动态字符串数组插入函数内存分配异常排查求助
修复StringVector中insert_string_vector的段错误问题
核心错误分析
insert_string_vector函数的段错误根源在于memmove的使用逻辑完全错误:
- 原代码中
memmove(vec->vector[index + 1], vec->vector[index], sizeof(char *))试图将vec->vector[index]指向的字符串内容复制到vec->vector[index+1]指向的内存地址,这不仅逻辑错误,还会因vec->vector[index+1]是未初始化野指针导致内存越界。 - 正确逻辑应该是移动指针数组中的指针元素,把从
index开始的所有指针整体右移一位,为新元素腾出位置。
除此之外,代码还有几个潜在问题:
- 字符串空终止符处理时存在数组越界
- insert函数未对插入字符串做动态分配,直接使用原指针会导致后续free出错
- free函数错误遍历
allocated_length而非实际元素数active_length - 空终止符判断方式存在越界风险
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char **vector; size_t active_length; size_t allocated_length; size_t num_bytes; } StringVector; // -------------------------------------------------------------------------------- StringVector init_string_vector(size_t length) { StringVector vec = {NULL, 0, 0, sizeof(char *)}; char **ptr = malloc(length * sizeof(char *)); if (ptr == NULL) { printf("WARNING: Not enough available memory, exiting!\n"); return vec; } vec.allocated_length = length; vec.vector = ptr; return vec; } // -------------------------------------------------------------------------------- int push_string_vector(StringVector *vec, char *value, size_t length) { if (!vec || !value) return 0; // 检查字符串是否以\0结尾,避免越界 int has_null = 0; if (length > 0 && value[length - 1] == '\0') { has_null = 1; } // 分配足够空间存储字符串(包含\0) size_t str_len = has_null ? length : length + 1; char *new_value = malloc(str_len); if (!new_value) return 0; memcpy(new_value, value, length); if (!has_null) { new_value[length] = '\0'; } // 扩容检查 if (vec->active_length >= vec->allocated_length) { size_t new_capacity = vec->allocated_length * 2; char **resized = realloc(vec->vector, new_capacity * sizeof(char *)); if (!resized) { free(new_value); return 0; } vec->vector = resized; vec->allocated_length = new_capacity; } vec->vector[vec->active_length] = new_value; vec->active_length += 1; return 1; } // -------------------------------------------------------------------------------- void free_string_vector(StringVector *vec) { if (!vec) return; // 只释放实际存在的元素 for (size_t i = 0; i < vec->active_length; i++) { free(vec->vector[i]); } free(vec->vector); vec->vector = NULL; vec->active_length = 0; vec->allocated_length = 0; vec->num_bytes = 0; } // -------------------------------------------------------------------------------- int insert_string_vector(StringVector *vec, char *value, size_t length, size_t index) { if (!vec || !value || index > vec->active_length) return 0; // 处理字符串空终止符 int has_null = 0; if (length > 0 && value[length - 1] == '\0') { has_null = 1; } size_t str_len = has_null ? length : length + 1; char *new_value = malloc(str_len); if (!new_value) return 0; memcpy(new_value, value, length); if (!has_null) { new_value[length] = '\0'; } // 扩容检查 if (vec->active_length >= vec->allocated_length) { size_t new_capacity = vec->allocated_length * 2; char **resized = realloc(vec->vector, new_capacity * sizeof(char *)); if (!resized) { free(new_value); return 0; } vec->vector = resized; vec->allocated_length = new_capacity; } // 将index及之后的指针右移一位 if (index < vec->active_length) { memmove(&vec->vector[index + 1], &vec->vector[index], (vec->active_length - index) * sizeof(char *)); } vec->vector[index] = new_value; vec->active_length += 1; return 1; } // -------------------------------------------------------------------------------- int main() { char a[6] = "Hello"; StringVector vec = init_string_vector(7); push_string_vector(&vec, a, 6); char b[7] = "World!"; push_string_vector(&vec, b, 7); char c[5] = "Goof"; push_string_vector(&vec, c, 5); char d[8] = "Goodbye"; insert_string_vector(&vec, d, 8, 1); for (size_t i = 0; i < vec.active_length; i++) { printf("%s\n", vec.vector[i]); } free_string_vector(&vec); return 0; }
关键修复点说明
修正memmove逻辑:
使用&vec->vector[index + 1]和&vec->vector[index]获取指针数组的地址,移动的是指针本身而非字符串内容,移动长度为(vec->active_length - index) * sizeof(char *),确保所有后续元素都右移。修复字符串处理的越界问题:
不再使用value + length这种可能越界的方式判断空终止符,改为检查value[length-1];同时动态分配new_value,避免栈数组越界。修正free逻辑:
free时只遍历active_length,避免无意义地释放未初始化的NULL指针。insert函数中动态分配字符串:
与push函数保持一致,使用malloc分配字符串内存,避免直接使用原指针导致后续free错误。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

