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

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;
}

关键修复点说明

  1. 修正memmove逻辑:
    使用&vec->vector[index + 1]和&vec->vector[index]获取指针数组的地址,移动的是指针本身而非字符串内容,移动长度为(vec->active_length - index) * sizeof(char *),确保所有后续元素都右移。

  2. 修复字符串处理的越界问题:
    不再使用value + length这种可能越界的方式判断空终止符,改为检查value[length-1];同时动态分配new_value,避免栈数组越界。

  3. 修正free逻辑:
    free时只遍历active_length,避免无意义地释放未初始化的NULL指针。

  4. insert函数中动态分配字符串:
    与push函数保持一致,使用malloc分配字符串内存,避免直接使用原指针导致后续free错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:24:24