如何在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
相关产品推荐
相关产品推荐

