C++中返回指向数组的指针时为何需要使用&?——decltype相关编译报错解析
嘿,这个问题戳中了C++里数组和指针关系的一个容易混淆的点,咱们一步步把它理清楚:
首先,先明确你的函数返回类型是什么:
decltype(odd) *arrPtr(int i)
odd是int[5]类型的数组,decltype(odd)会保留数组的原始类型,也就是int[5],所以整个返回类型decltype(odd)*就是int(*)[5]——翻译成人话就是:指向包含5个int元素的数组的指针。
接下来看数组名的隐式转换规则:
当你直接写odd的时候,在绝大多数语境下(比如赋值给指针、作为函数实参),C++会自动把数组名隐式转换成指向数组第一个元素的指针,也就是int*类型。这就是你去掉&后编译报错的原因:函数要求返回int(*)[5],但你返回的是int*,两种类型完全不兼容,编译器自然会拒绝。
那为什么加&就没问题?&odd这里取的是整个数组的地址,它的类型正好是int(*)[5],和函数的返回类型完美匹配。这里要纠正你一个小误解:&odd并不是二级指针(二级指针是int**),它是一种专门的“指向数组的指针”类型,虽然它存储的地址值和odd转换后的int*地址值是一样的,但两者的类型语义完全不同——比如你对&odd做+1操作,它会跳过整个int[5]数组的大小(20字节,假设int是4字节),而对odd(也就是int*)做+1操作,只会跳过一个int的大小(4字节)。
咱们用代码验证一下这个差异:
#include <iostream> using namespace std; int main() { int odd[] = {1,3,5,7,9}; cout << "odd的地址:" << odd << endl; cout << "&odd的地址:" << &odd << endl; // 地址值相同,但类型不同 cout << "odd+1的地址:" << odd+1 << endl; // 跳过4字节 cout << "&odd+1的地址:" << (int(*)[5])(&odd+1) << endl; // 跳过20字节 return 0; }
运行后你会看到,odd+1的地址比odd大4,而&odd+1的地址比&odd大20,这就是两种指针类型的本质区别。
最后补充一个小技巧:如果觉得int(*)[5]这种类型太晦涩,C++11及以后可以用using来简化类型定义:
using IntArray5Ptr = int(*)[5]; IntArray5Ptr arrPtr(int i) { return (i%2) ? &odd : &even; }
这样代码可读性会好很多。
内容的提问来源于stack exchange,提问作者LiuYuan

