函数内局部char数组指针返回后printf打印异常的原因探究
问题现象说明
情况1:返回局部字符数组指针,printf("%s")无输出
#include<stdio.h> char* getcc(); int main(){ char *cp = getcc(); printf("%s",cp); } char* getcc(){ char c_arr[] = "cow"; return c_arr; }
运行后无任何输出。
情况2:将数组改为全局变量,printf("%s")正常输出
#include<stdio.h> char* getcc(); int main(){ char *cp = getcc(); printf("%s",cp); } char c_arr[] = "cow"; char* getcc(){ return c_arr; }
输出:
cow
情况3:使用printf("%c")逐个打印字符,可输出内容
#include<stdio.h> char* getcc(); int main(){ char *cp = getcc(); printf("%c%c%c",*cp,*++cp,*++cp); } char* getcc(){ char c_arr[] = "cow"; return c_arr; }
输出:
cow
原因分析
局部数组的内存特性:
getcc()里的c_arr是局部变量,存储在栈内存中。当函数执行完毕返回时,该函数对应的栈帧会被销毁,栈上的内存会被标记为可复用状态。此时返回的指针指向的是已经失效的内存区域,属于野指针,用printf("%s")访问时,%s会从指针位置开始读取直到遇到\0,但此时栈内存的数据已经不可靠,可能已经被覆盖,所以无法正常输出字符串。全局数组的内存特性:全局变量存储在静态存储区,这块内存从程序启动到结束都会持续存在,不会随函数调用结束而释放。所以
getcc()返回的指针始终指向有效的内存区域,printf("%s")可以正常读取到完整的字符串。%c逐个打印能输出是巧合:这是未定义行为的一种表现。函数返回后,栈帧虽然被销毁,但如果后续没有其他操作覆盖这块栈内存,原来的字符数据可能暂时还保留着。此时用%c直接读取指针指向的几个字节,刚好能读到原来的字符。但这种行为完全不可靠——只要调整编译器优化等级、在getcc()返回后增加其他函数调用,或者更换运行环境,就可能输出乱码或者程序崩溃,本质还是非法访问了已失效的内存。
内容的提问来源于stack exchange,提问作者Cryogen
相关产品推荐
相关产品推荐

