C语言动态数组结果随机异常:未改代码却输出不稳定问题求助
动态数组存储单词索引时结果不稳定的问题分析与修复
问题重现
你实现了C语言动态数组,用于存储字符串中匹配单词的起始索引,但调用findWord("hello, world, hello", "hello")时,结果有时正确有时错误,核心是存储的指针指向无效内存,触发未定义行为。
你的代码片段
动态数组结构体定义
typedef void (*PrintArrayElement)(const void* element); typedef struct { size_t size; size_t capacity; void** array; PrintArrayElement printElement; // Callback } dynamic_array;
添加元素函数
void arrayAddItem(dynamic_array* container, void* item) { if (container->size == container->capacity) { void** temp = container->array; container->capacity <<= 1; container->array = (void **)realloc(container->array, container->capacity * sizeof(void*)); if (!container->array) { printf("Out of Memory\n"); container->array = temp; return; } } container->array[container->size] = strdup(item); container->size++; }
查找单词索引函数
dynamic_array* findWord(char str[], char keyword[]) { dynamic_array* indexes; arrayInit(&indexes, 16, printInt); int i = 0; int start = 0; int end = 0; size_t len = strlen(str); while (i < len) { while (i < len && !isalpha(str[i])) { i++; } if (isalpha(str[i])) { start = i; while (i < len && isalpha(str[i])) { i++; } end = i; char* word = (char*)malloc(end - start + 1); strncpy(word, &str[start], end - start); word[end - start] = '\0'; if(strcmp(word, keyword) == 0) { printf("%d\n", start); arrayAddItem(indexes, &start); } free(word); } } return indexes; }
问题根源
错误使用
strdup:strdup是字符串专用的复制函数,会从传入的char*指针开始复制直到遇到'\0'。但你传入的是&start(int变量的地址),strdup会把这个地址当成char*读取内存,而int变量后不一定有'\0',这会导致内存越界读取,复制的内容完全不可控,触发未定义行为——这就是结果时对时错的核心原因。存储局部变量地址:
start是findWord函数的局部变量,每次循环都会被覆盖,函数执行结束后局部变量的内存会被释放。你把&start存入动态数组,相当于存储了一个野指针,后续访问时内存内容可能已被其他操作覆盖,导致读取到错误值。
修复方案
1. 修改arrayAddItem函数,正确存储任意类型元素
替换错误的strdup为通用的内存分配+值复制逻辑,让函数支持任意类型的元素存储:
void arrayAddItem(dynamic_array* container, void* item, size_t item_size) { if (container->size == container->capacity) { void** temp = container->array; container->capacity <<= 1; // 去掉不必要的强制类型转换,realloc返回void*可直接赋值 container->array = realloc(container->array, container->capacity * sizeof(void*)); if (!container->array) { printf("Out of Memory\n"); container->array = temp; return; } } // 为当前元素分配独立内存,复制传入的值 void* elem = malloc(item_size); if (!elem) { printf("Out of Memory\n"); return; } memcpy(elem, item, item_size); container->array[container->size] = elem; container->size++; }
2. 修复findWord函数的两处问题
- 调用
arrayAddItem时传入元素大小sizeof(int); - 避免越界访问
str[i],先检查i < len再判断字符类型:
dynamic_array* findWord(char str[], char keyword[]) { dynamic_array* indexes; arrayInit(&indexes, 16, printInt); int i = 0; int start = 0; int end = 0; size_t len = strlen(str); while (i < len) { while (i < len && !isalpha(str[i])) { i++; } // 先判断i是否越界,再检查字符类型 if (i < len && isalpha(str[i])) { start = i; while (i < len && isalpha(str[i])) { i++; } end = i; char* word = (char*)malloc(end - start + 1); strncpy(word, &str[start], end - start); word[end - start] = '\0'; if(strcmp(word, keyword) == 0) { printf("%d\n", start); // 传入元素大小,正确存储int值 arrayAddItem(indexes, &start, sizeof(int)); } free(word); } } return indexes; }
3. 补充动态数组销毁函数(避免内存泄漏)
记得实现销毁函数,遍历释放每个元素的内存,再释放数组本身:
void arrayDestroy(dynamic_array* container) { if (!container) return; for (size_t i = 0; i < container->size; i++) { free(container->array[i]); } free(container->array); free(container); }
验证
修改后调用findWord("hello, world, hello", "hello"),动态数组会存储两个独立分配的int内存块,分别保存0和14,访问时不会出现野指针或越界问题,结果稳定。
内容的提问来源于stack exchange,提问作者somerandomname
相关产品推荐
相关产品推荐

