C语言结构体指针函数因同名局部变量声明返回NULL的原因解析
问题背景
完成D&R教材所有课后习题时,基于书中提供的addtree函数针对自定义结构体做修改,用到的结构体定义如下:
struct gnode { char **words; int count; struct gnode *left; struct gnode *right; };
修改后的addtree函数如下,注释中标注了之前触发返回NULL问题的错误写法:
struct gnode *addtree(struct gnode *p, char *w) { int cond; if (p == NULL) { printf("init null node\n"); p = (struct gnode *)malloc(sizeof(struct gnode)); // 此前的错误写法: // struct gnode *p =(struct gnode *)malloc(sizeof(struct gnode)); // 该写法会导致p每次返回值都是NULL p->count = 1; p->words = malloc(8); p->words[0] = strdup2(w); p->left = p->right = NULL; } else if ((cond = compare(w, p->words[0])) == 0) { printf("comp hit\n"); p->count++; p->words = realloc(p->words, p->count * 8); p->words[p->count] = strdup2(w); } else if (cond < 0) p->left = addtree(p->left, w); else p->right = addtree(p->right, w); return p; }
核心疑问:在函数内部声明与形参同名的局部指针变量时,为什么函数每次返回的结果都是NULL?
原因说明
这个问题本质是C语言的变量作用域遮蔽规则导致的:
- C语言中,内层作用域声明的同名变量会直接遮蔽外层作用域的同名变量,二者是完全独立的内存实体,操作互不影响。
- 错误写法里,形参
p是属于整个函数体作用域的变量,当代码进入p == NULL的判断分支后,在分支内部声明struct gnode *p = malloc(...)时,这个新声明的p是仅在当前if分支块内有效的局部变量,会把外层的形参p完全遮蔽。 - 后续在if块内给
p分配内存、给结构体成员赋值的所有操作,修改的都是这个块内的局部p,和外层的形参p没有任何关联。 - 当if块执行结束,块内的局部
p生命周期直接终止,之前malloc得到的内存地址丢失,还会造成内存泄漏。而外层的形参p从进入判断时就为NULL,全程没有被修改过,最后执行return p时,返回的自然就是始终为NULL的外层形参。
额外提示:当前代码还存在数组越界问题:匹配到相同单词执行
p->count++后,count值从1变为2,此时words扩容后的合法下标为0和1,直接写p->words[p->count] = strdup2(w)会访问下标为2的越界内存,正确写法应为p->words[p->count - 1] = strdup2(w);
内容的提问来源于stack exchange,提问作者pen_island
相关产品推荐
相关产品推荐

