数组按值传递与按引用传递是否相同?代码表现存疑咨询
嘿,这个问题其实是C/C++里一个非常经典的“坑”——很多刚接触数组传参的开发者都会踩进去,误以为数组是按值传递,但实际规则完全不是你想的那样。我来给你拆解清楚:
首先直接点破核心:在C和C++中,当你把数组作为函数参数传递时,它并不会按值传递,而是会被自动转换成指向数组第一个元素的指针。这就是为什么你在display函数里打印的&b[i]和main里的&num[i]完全一致——因为b本质上就是指向num数组首元素的指针,操作b[i]其实就是直接操作原数组的元素。
你的代码到底发生了什么?
看一下你的display函数声明:
void display(int b[5], int size)
在C++编译器的眼里,这个声明和下面的写法是完全等价的:
void display(int* b, int size)
编译器会自动把数组类型的参数调整为指针类型。所以当你调用display(num,5)时,传递的并不是整个数组的副本,而是num数组首元素的地址(也就是&num[0])。这就导致display函数里的b[i]和main里的num[i]指向同一块内存区域,地址自然一模一样。
那怎么实现真正的“按值传递”数组?
如果想要传递数组的副本(也就是修改函数内的数组不会影响原数组),有几种靠谱的方法:
方法1:用std::array(C++11及以上推荐)
std::array是C++标准库提供的容器,它可以像普通变量一样按值传递:
#include <iostream> #include <array> void display(std::array<int, 5> b, int size) { std::cout << "\nIn display function:\n"; for (int i = 0; i < size; i++) { std::cout << b[i] << " at: " << &b[i] << "\n"; } // 修改b的元素,不会影响原数组 b[0] = 99; } int main() { std::array<int, 5> num = {2, 4, 6, 8, 10}; std::cout << "In main function:\n"; for (int i = 0; i < 5; i++) { std::cout << num[i] << " at: " << &num[i] << "\n"; } display(num, 5); // 打印原数组,第一个元素还是2 std::cout << "\nAfter display call, num[0] is: " << num[0] << "\n"; return 0; }
运行这段代码你会发现,display里的b元素地址和main里的num完全不同,修改b也不会影响原数组,这才是真正的按值传递。
方法2:把数组包装在结构体里(兼容C和旧版C++)
如果是在C环境或者不能用C++11的场景,可以把数组放进结构体里——结构体是支持按值传递的:
#include <stdio.h> struct ArrayWrapper { int arr[5]; }; void display(struct ArrayWrapper b, int size) { printf("\nIn display function:\n"); for (int i = 0; i < size; i++) { printf("%d at: %p\n", b.arr[i], &b.arr[i]); } b.arr[0] = 99; } int main() { struct ArrayWrapper num; num.arr[0] = 2; num.arr[1] = 4; num.arr[2] = 6; num.arr[3] = 8; num.arr[4] = 10; printf("In main function:\n"); for (int i = 0; i < 5; i++) { printf("%d at: %p\n", num.arr[i], &num.arr[i]); } display(num, 5); printf("\nAfter display call, num.arr[0] is: %d\n", num.arr[0]); return 0; }
传递结构体时会生成整个结构体的副本,里面的数组自然也是独立的副本,同样能实现按值传递的效果。
方法3:传递数组的引用(注意:这是按引用传递,不是值传递)
如果你想让函数直接操作原数组,但又想明确是引用传递(避免指针的歧义),可以用数组的引用作为参数:
void display(int (&b)[5], int size) { printf("\nIn display function:\n"); for (int i = 0; i < size; i++) { printf("%d at: %p\n", b[i], &b[i]); } // 修改b的元素会直接影响原数组 b[0] = 99; }
此时b是原数组的引用,地址还是和原数组一致,但写法上更明确是引用类型,避免了指针隐式转换的迷惑性。
你的代码里的其他小问题
顺便提两个容易忽略的细节:
using namespace std;在你的代码里没必要,因为你用的是C风格的printf和scanf,没用到std命名空间的内容;void main()不是C++的标准写法,标准应该用int main()并返回0;scanf("%d", pause);这里必须传&pause,不然会导致未定义行为(scanf需要变量的地址来存储输入值)。
内容的提问来源于stack exchange,提问作者Kamal Ahmad

