下面一段代码的运行结果是什么?
#include <iostream> using namespace std; int main(int argc, char** argv) { int a[5] = {1,2,3,4,5}; int* ptr = (int*)(&a + 1); cout<<*(a+1)<<","<<*(ptr-1)<<endl; return 0; }
答对了吗?运行结果为: 2,5。 为什么呢?
因为题目涉及到指针的加减运算,这就涉及到了指&a的类型和&a指向对象的类型等问题。
注意到了吗对整形指针ptr赋值的时候,我们用了类型强制转换,可见&a的类型不是int*,那究竟是什么类型呢?
最简单的方法就是去掉强制类型转换(int*),然后编译,编译器就会提示如下信息:
error: cannot convert 'int (*)[5]' to 'int*' in initialization|
另一种方法就是C++关键字typeid,代码如下:
#include <typeinfo> #include <iostream> using namespace std; int main(int argc, char** argv) { int a[5] = {1,2,3,4,5}; const type_info &t_info = typeid(&a); cout<<t_info.name()<<endl; return 0; }
运行结果为:PA5_i
原来&a的类型是是int (*)[5](PA5_i)!那么这下答案就很明了了,则根据C语言规定:如果指针变量p指向数组中的一个元素,则p+1指向同一数组中的下一个元素,即p+sizeof(a)。&a为指向数组的指针,其中每个元素为由5个整形组成的数组,因而&a+1=(&a+sizeof(int[5]))= &a[6],是指向下一个数组的指针,即数组对象为一个整体。可以发现其实&a+1其实刚刚超出了a的范围,但将p强制类型转换为int*后,此时p又为指向整形的指针,因而 p-1 = p - sizeof(int)= &a[5],因而打印结果为2,5
其实,用typedef为数组定义别名,结果就很容易理解了,因为人们习惯将数组看成是一个连续的对象列表,而不会将其看为是一个数据类型。
应牢记这一点,数组也是一个数据类型。
#include <typeinfo> #include <iostream> using namespace std; typedef int arr[5]; int main(int argc, char** argv) { arr a = {1,2,3,4,5}; cout<<typeid(a).name()<<endl; cout<<typeid(&a).name()<<endl; int* ptr = (int*)(&a + 1); cout<<*(a+1)<<","<<*(ptr-1)<<endl; return 0; }
ps:各种数组的数据类型:
int a[1]:int[1]
int a[1][1]: int(*)[1]
int a[1][1][1]:int(*)[1][1]