C语言通用类型is_in函数判断指针存在性出错问题排查
通用is_in函数的问题分析与修复
核心错误点
- 数组越界写入:pptest仅分配了2个Symbol*的存储空间,有效下标范围是0和1,但测试代码中错误使用了
pptest[2]进行赋值,这属于未定义行为,&F根本没有被存入数组的有效区域内。 - void*指针算术非法:
is_in函数里的array + k是错误操作,C标准中void类型无法直接做指针算术——编译器不知道其指向元素的字节大小。必须参考qsort的设计,增加元素大小参数,通过char来计算正确的内存偏移。 - 参数类型不匹配:调用
is_in时传入的pelement是&F(即Symbol**类型),但ptreq函数中将ptr2强制转换为Symbol*,导致比较逻辑完全错误;同时is_in传给equals的第一个参数是错误偏移的指针,没有正确指向数组中的元素。 - 字符串内存分配错误:
set_symbol函数中malloc(sizeof(content))仅分配了指针大小的空间,而非字符串实际需要的长度+1的空间,会导致缓冲区溢出。
修正后的完整代码
修复后的is_in函数(新增元素大小参数)
int is_in(void* array, int size, size_t elem_size, void* pelement, int (*equals)(void* this, void* that)) { char* arr_base = (char*)array; for(int k = 0; k < size; k++) { // 计算第k个元素的内存地址 void* current_elem = arr_base + k * elem_size; if(equals(current_elem, pelement)) { return 1; } } return 0; }
修复后的ptreq函数(匹配参数类型)
int ptreq(void* ptr1, void* ptr2) { // ptr1是数组中元素的地址(Symbol**),ptr2是传入的目标地址(Symbol**) return *(Symbol**)ptr1 == *(Symbol**)ptr2; }
修复测试代码(修正越界+内存分配错误)
enum SymbolType { TERMINAL, NONTERMINAL } typedef SymbolType; struct Symbol { char* content; SymbolType type; } typedef Symbol; void set_symbol(Symbol* pS, SymbolType type, char* content) { // 为字符串分配足够空间:长度+1(存储结束符) pS->content = malloc(strlen(content) + 1); strcpy(pS->content, content); pS->type = type; } int main(int argc, char* argv[]) { Symbol F, E; set_symbol(&E, NONTERMINAL, "E"); set_symbol(&F, NONTERMINAL, "F"); Symbol** pptest = malloc(2 * sizeof(Symbol*)); pptest[0] = &E; // 修正数组下标为1,避免越界 pptest[1] = &F; // 调用时传入元素大小:sizeof(Symbol*) printf("Is F in pptest? %d\n", is_in(pptest, 2, sizeof(Symbol*), &F, ptreq)); // 释放内存,避免泄漏 free(E.content); free(F.content); free(pptest); return 0; }
内容的提问来源于stack exchange,提问作者Mehdi Charife
相关产品推荐
相关产品推荐

