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

C语言动态数组扩容异常求助:分词存储后used值出现随机乱码

问题分析与修复方案

我来帮你拆解一下代码里的核心问题,你的扩容失败和used值变成随机数的情况,主要是两个关键错误导致的:

1. 结构体设计的本质问题

你定义的Array结构体里,pointer是一个固定大小的二维数组char pointer[DEFAULT_SIZE][256]——这种数组的长度是编译时就固定死的,完全没办法通过realloc实现动态扩容。要做能动态增长的字符串数组,必须把pointer改成指向字符串的指针数组(也就是char **pointer;),这样才能在运行时动态调整数组的长度。

2. append函数的内存操作完全错误

你在扩容时的操作完全偏离了目标:

  • 你重新malloc了一个新的Array对象,又对它调用realloc,但我们要扩容的是原数组里的pointer,不是整个Array结构体本身;
  • 你还重新赋值了函数参数array,这只会修改函数内部的局部指针,对外部传入的args_list没有任何影响,这直接导致原结构体的内存被非法访问,used字段的值被破坏成随机数。

修正后的完整代码

下面是修复后的代码,我会标注关键修改点:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEFAULT_SIZE 3 /* default size of an array of words */

// 修改:把固定二维数组改成指针数组,支持动态扩容
typedef struct {
    char **pointer; // 指向每个字符串的指针数组
    int used;
    int size;
} Array;

// 修改:初始化时要为指针数组分配初始内存
void createArray(Array *array, int start_size) {
    array->used = 0;
    array->size = start_size;
    // 为指针数组分配内存,每个元素是一个char*类型的指针
    array->pointer = malloc(start_size * sizeof(char*));
    if (array->pointer == NULL) {
        fprintf(stderr, "Failed to allocate initial array memory!\n");
        exit(EXIT_FAILURE);
    }
}

// 完全重写的append函数,实现正确的动态扩容
void append(Array *array, char* elem) {
    if (array->used >= array->size) {
        // 扩容策略:每次把数组大小翻倍(比固定加2更高效)
        int new_size = array->size * 2;
        // 重新分配指针数组的内存
        char **new_pointer = realloc(array->pointer, new_size * sizeof(char*));
        if (new_pointer == NULL) {
            fprintf(stderr, "Failed to expand array memory!\n");
            exit(EXIT_FAILURE);
        }
        array->pointer = new_pointer;
        array->size = new_size;
    }
    // 为每个新字符串单独分配内存(要包含字符串结束符'\0'的空间)
    array->pointer[array->used] = malloc(strlen(elem) + 1);
    if (array->pointer[array->used] == NULL) {
        fprintf(stderr, "Failed to allocate memory for string!\n");
        exit(EXIT_FAILURE);
    }
    strcpy(array->pointer[array->used], elem);
    array->used++; // 现在这个值会正常递增了
}

// 新增:内存释放函数,避免内存泄漏
void freeArray(Array *array) {
    // 先逐个释放每个字符串的内存
    for (int i = 0; i < array->used; i++) {
        free(array->pointer[i]);
    }
    // 再释放指针数组本身的内存
    free(array->pointer);
    // 重置结构体状态
    array->pointer = NULL;
    array->used = 0;
    array->size = 0;
}

char *args_str; // passed string
Array args_list; // expandable array holding words

void parse(char* command) {
    createArray(&args_list, DEFAULT_SIZE);
    args_str = strtok(command, " ");
    while (args_str != NULL) {
        append(&args_list, args_str);
        args_str = strtok(NULL, " ");
    }
}

// 测试用例
int main() {
    char test_str[] = "this is a test string with more than three words";
    parse(test_str);
    
    // 打印结果验证
    printf("Parsed %d words:\n", args_list.used);
    for (int i = 0; i < args_list.used; i++) {
        printf("%d: %s\n", i+1, args_list.pointer[i]);
    }
    
    // 别忘了释放内存
    freeArray(&args_list);
    return 0;
}

额外提醒

  • 使用strtok时要注意:它会直接修改传入的字符串,所以如果传入的是字符串字面量(比如parse("this is test");)会导致未定义行为,一定要传入可修改的字符数组(像测试用例里那样);
  • 内存分配后一定要检查malloc/realloc的返回值是否为NULL,避免内存分配失败导致的崩溃;
  • 不再使用动态数组时,一定要调用freeArray释放内存,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:49:50