C语言局部变量返回与动态内存分配代码运行异常问题咨询
问题根本原因
第一段代码运行异常的核心是函数返回了栈区局部变量的内存地址,触发了C语言的未定义行为。
底层原理讲解
C语言程序运行时的内存空间通常分为多个逻辑区域,和该问题直接相关的是栈区与堆区:
- 栈区由操作系统自动管理:函数调用时会在栈区为当前函数开辟专属的栈帧,函数内的非静态局部变量、参数都存储在栈帧中;当函数执行结束返回时,对应的栈帧会被系统自动回收,这片内存的使用权会被释放,后续的函数调用会直接复用这块空闲的栈空间。
- 堆区由程序员手动管理:调用
malloc类函数申请的内存位于堆区,只要不主动调用free释放,这片内存的使用权会一直有效,直到程序退出。
对应第一段代码的执行逻辑:
- 第一次调用
foo(0)时,栈上为foo开辟栈帧,局部数组arr的3个int空间就在这个栈帧里,存入[0,1,2]后返回arr的地址给a1。但foo执行结束后栈帧被回收,a1就成了指向无效内存的野指针。 - 第二次调用
foo(3)时,系统会直接复用第一次foo调用释放的栈空间来创建新栈帧,所以原来a1指向的内存会被覆盖为[3,4,5],调用结束后这个栈帧也被回收,a2同样变成野指针。 - 后续执行
printf时,printf自身的执行也需要占用栈空间,会再次复用这片刚释放的栈内存,把a2指向的内存数据冲成乱码,而a1指向的内容刚好还没被完全覆盖,就出现了你看到的输出结果。这类未定义行为没有任何确定性,换编译环境、运行参数都可能出现完全不同的结果,甚至程序直接崩溃。
修改后代码正常的原因
修改后用malloc申请的数组内存位于堆区,不会随foo函数执行结束被系统自动回收,返回的指针指向的内存是合法有效的,所以可以正常输出预期结果。注意使用完后需要手动调用free(a1)、free(a2)释放堆内存,避免出现内存泄漏问题。
内容的提问来源于stack exchange,提问作者Hayato Koyama
相关产品推荐
相关产品推荐

