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

如何在C语言中调整数组大小?字符串转单词指针数组实现困惑

问题描述

我现在要处理一个由多个单词组成的句子,打算遍历句子,把每个独立单词存到动态分配的内存里,再把每个单词的指针放到指针数组里。但我不知道怎么开辟新内存空间,把原有数据复制到更大的新数组里。

我的实现代码

char** str_to_arr_words (char *str) {
  int length;
  char** arr_words;
  int numOfWords;
  // 循环直至到达句子末尾
  while(*str != '\n'){
    // 循环直至到达单词末尾
    while(*str != '\0'){
      length++;
      str++;
    }
    // 为单词分配内存空间
    char* word = malloc(length);
    // 将str指针移回单词起始位置
    str = str - length;
    // 将句子中的单词复制到其专属内存位置
    for(int x = 0; x < length; x++){
      word[x] = str[x];
    }
    numOfWords++;
    // 将单词地址数组扩容1,并将最新地址存入新数组
    char** newArrWords = malloc(numOfWords);
    for(int x = 0; x < numOfWords - 1; x++){
      newArrWords[x] = arr_words[x];
    }
    newArrWords[numOfWords] = str;
    // 将str指针移至下一个单词的起始位置(+1以跳过'\0')
    str = str + length + 1;
    length = 0;
  }
}
问题分析与修正

原代码的核心问题

  • 变量未初始化:length、numOfWords、arr_words都没有初始值,会触发未定义行为,比如numOfWords初始为随机值,导致计数逻辑完全混乱。
  • 内存分配错误:
    • 指针数组分配时,malloc(numOfWords)未按指针类型大小分配,正确写法应为malloc(numOfWords * sizeof(char*))。
    • 单个单词分配内存时未预留字符串结束符'\0'的位置,必须用malloc(length + 1)才能存储合法C字符串。
  • 数组越界:newArrWords[numOfWords] = str; 数组索引从0开始,numOfWords自增后,正确索引应为numOfWords - 1;且应存储分配好的word指针,而非原字符串的str指针(原指针可能被修改或释放)。
  • 内存泄漏:每次扩容创建新数组后,旧的arr_words未释放,会持续占用内存。
  • 单词遍历逻辑错误:假设单词用'\0'分隔不符合常规句子格式(通常用空格),且原循环会直接跑到字符串末尾,无法区分多个单词。
  • 无返回值:函数声明返回char**,但未返回处理后的指针数组。

修正后的代码

假设单词用空格分隔,句子以换行符'\n'或字符串结束符'\0'结尾:

#include <stdlib.h>
#include <string.h>

char** str_to_arr_words(char *str) {
    // 初始化变量
    int numOfWords = 0;
    char** arr_words = NULL;

    while (*str != '\n' && *str != '\0') {
        // 跳过连续空格,避免空单词
        while (*str == ' ') {
            str++;
        }
        if (*str == '\n' || *str == '\0') {
            break;
        }

        // 计算当前单词长度
        int length = 0;
        char* word_start = str;
        while (*str != ' ' && *str != '\n' && *str != '\0') {
            length++;
            str++;
        }

        // 为单词分配内存(+1预留'\0'位置)
        char* word = malloc(length + 1);
        if (word == NULL) {
            // 内存分配失败,释放已分配资源避免泄漏
            for (int i = 0; i < numOfWords; i++) {
                free(arr_words[i]);
            }
            free(arr_words);
            return NULL;
        }
        // 复制单词并添加结束符
        strncpy(word, word_start, length);
        word[length] = '\0';

        // 用realloc简化数组扩容,自动处理旧内存复制
        numOfWords++;
        char** newArrWords = realloc(arr_words, numOfWords * sizeof(char*));
        if (newArrWords == NULL) {
            // 扩容失败,释放当前单词及已分配数组
            free(word);
            for (int i = 0; i < numOfWords - 1; i++) {
                free(arr_words[i]);
            }
            free(arr_words);
            return NULL;
        }
        arr_words = newArrWords;
        // 将新单词指针存入数组
        arr_words[numOfWords - 1] = word;
    }

    // 给数组末尾添加NULL标记,方便调用者遍历判断结束
    if (numOfWords > 0) {
        char** finalArr = realloc(arr_words, (numOfWords + 1) * sizeof(char*));
        if (finalArr != NULL) {
            arr_words = finalArr;
        }
    }
    if (arr_words != NULL) {
        arr_words[numOfWords] = NULL;
    }

    return arr_words;
}

关键改进点

  • 用realloc简化数组扩容:自动完成旧内存的复制与释放,无需手动循环拷贝,避免内存泄漏。
  • 严格处理字符串结束符:每个单词都添加'\0',保证是合法可使用的C字符串。
  • 增加错误处理:内存分配失败时,释放已分配的所有资源,避免泄漏或崩溃。
  • 适配常规输入格式:跳过连续空格,支持空格分隔的标准句子格式。
  • 数组末尾添加NULL标记:方便调用者通过arr_words[i] != NULL判断数组结束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 20:24:32