[原创]C/C++中复杂指针声明&&数组名的一点小事
C/C++中指针声明一向是一个难点,当情况复杂时很容易弄错。当然实际情况可能较少用到复杂指针,但是深挖指针的内涵毕竟没有坏处。来看以下一例。
有三个简单函数
int mydb(int a)
{
return 2*a;
}
int mytri(int a)
{
return 3*a;
}
int myqua(int a)
{
return 4*a;
}
Q1. 声明一个指针数组存放以上三个函数。
int (*fun_arr[3])(int) = {mydb, mytri, myqua};
Q2. 声明一个指向数组元素的指针。
int (** pfun)(int) = fun_arr;
Q3. 声明一个数组指针,指向fun_arr
int (*(*parr)[3])(int) = &fun_arr
确定指针类型的步骤:
1. 在一个声明表达式中定位 标识符
例如在Q1中,标识符为fun_arr
2. 根据优先级,将标识符先后与左右操作符相结合。注意声明指针的 * 的优先级低于 声明为数组的 [],圆括号()优先级最高。
例如Q1中,fun_arr优先与[]结合,表明fun_arr是一个数组;Q3中parr被圆括号括住,那么parr先与*结合,表明parr是一个指针。
3. 从标识符开始,由内向外递归结合左右操作符,逐渐扩大结果;并依据当前结果的类型填充“上下文”。
例如,当前结果是指针,那么隐含的下文应该是,指针指向的类型是____?
当前结果是数组,那么隐含的下文应该是,数组元素的类型是____?
分析Q2的指针声明如下:
a. pfun是一个指针: *pfun
b. pfun指向一个指针: (**pfun)
c. 这个指针指向一个函数: (** pfun)()
d. 这个函数的参数是一个int,返回int: int (**pfun)(int)
分析Q3如下:
a. parr是一个指针: (*parr)
b. 它指向一个数组,包含三个元素: (*parr)[3]
c. 数组的元素是指针: * (*parr)[3]
d. 指针指向一个函数 * (*parr)[3] ()
e. 函数接受一个int,返回int : int * (*parr)[3](int)
关于Q3的答案中为什么要把 fun_arr取地址再赋给 parr,这里引出第二个问题
Q4. 数组名称的类型与对数组名取地址的类型一样吗?
即 若int arr[3] = {1,2,3};
arr与&arr的类型是一样的吗?
——————————————
答案是不一样。
arr 的类型是:指向arr中元素的指针,即 int *
&arr的类型是:指向整个arr数组的指针,即 (*)[3]
编译器会对语句: int * pi = &arr;
显示类型不兼容的警告。
知道了这些,可以解决这样的问题:
int arr[3] = {1,2,3};
print("%d\n",*((int *)(&arr+1)-1));
结果是?
————————————————
结果是:3