C语言中无返回值的void函数为何能修改栈外部的字符串变量
问题核心误区澄清
- 第一个误区:这个现象和函数返回值是
void完全无关,哪怕你给函数设置其他返回值类型,只要逻辑不变,一样能修改外部的数组内容。 - 第二个误区:你对「形参是局部变量」的理解本身没有错,但没搞懂C语言中数组作为函数参数的特殊传递规则。
数组参数的传递本质
C语言中不存在「直接把整个数组拷贝进函数栈」的参数传递逻辑,当你把数组名作为实参传入函数时,数组名会自动退化为指向数组首元素的指针。
你写的函数定义:
void copyString (char to[], char from[]) { int i; for ( i = 0; from[i] != '\0'; ++i ) to[i] = from[i]; to[i] = '\0'; }
在编译器处理时,会完全等价于:
void copyString (char *to, char *from)
这里的to确实是存储在函数栈上的局部指针变量,如果你修改的是to本身的值(比如执行to = NULL、to++这类操作),确实不会影响函数外部的实参,因为改的是栈上的局部拷贝。
你的代码修改的是指针指向的原内存
你代码中执行的to[i] = from[i]操作,本质等价于*(to + i) = *(from + i):是拿着局部指针存储的地址,去修改地址指向的内存中的数据。
而to指针存储的地址,就是你在函数外部定义的to数组的首地址,这块内存本身不在函数栈上,属于外部作用域的内存空间,你修改的就是原数组的实际存储内容,所以函数执行结束后,外部自然能拿到修改后的结果。
对比验证示例
你可以尝试修改函数逻辑测试:
void test(char to[]) { // 仅修改局部指针本身的值 to = "test string"; }
调用这个函数之后你会发现,外部的数组完全没有变化,因为这里改的是栈上的局部指针to本身,不会影响原数组的内容,这才是你之前预期的「局部修改不影响外部」的情况。
内容的提问来源于stack exchange,提问作者user14793744
相关产品推荐
相关产品推荐

