一. 解读复杂指针声明
右左法则:首先从标识符开始阅读,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。一旦解析完括号里所有的东西,就跳出括号。重复这个过程直到整个声明解析完毕。
- int *a[10]
- // 首先 a 右边是[],说明 a 是一个具有10个元素的数组
- // 其次 a 左边是 int*,说明 a 的元素是 int 类型的指针
- int (*a)[10]
- // 首先 a 左边是一个 * 号,说明 a 是一个指针
- // 跳出括号,右边是 [], 说明 a 是一个指向具有10个元素的数组的指针
- // 左边是 int,说明元素的类型是 int
- int (*func)(int *p);
- // 首先找到 func,它左边是一个 * 号,这说明 func 是一个指针
- // 然后跳出这个圆括号,先看右边,也是个圆括号,这说明 (*func) 是个函数,而 func 是指向这个函数的指针
- // 这个函数具有 int* 类型的参数,返回值类型为 int
- int (*func[5])(int* p)
- // 首先找到 func, 右边是[],说明 func 是一个具有5个元素的数组
- // 其次 func 左边有一个 *,说明 func 的元素是指针,要注意 * 不是修饰func的,而是修饰 func[5]的
- // 跳出这个括号,右边也是一个括号,说明 func 数组的元素是函数类型的指针
二. 数组首地址 a, &a, &a[0]
以a[10]为例:
1. a 作为右值时,代表数组首元素的首地址,而非数组首地址。
也就是 a[0] 的地址。int i = *(a+1),这里a是右值,所是代表首元素的首地址,a+1代表下一个元素的首地址,即&a[1]。
2. a 是整个数组的名子。
所以 sizeof(a) 的值为 size(int) * 10 = 40,代表整个数组的大小。
3. &a 即为取 a 的首地址,也即是整个数组的首地址。
所以 sizeof(&a) 的值为 4。
但是在VC6.0里显示的是40,这是不对的。code:block里显示的是4。
int * p = (int*)(&a+1) 中 &a+1 代表下一个数组的首地址,显然是越界的。
4. &a[0] 代表首元素的首地址。
所以 sizeof(&a[0]) 的值为 4。
5. &a[10] 很显然,数组越界了,但是他的sizeof是多少呢?
也是4,因为关键字sizeof求值是在编译的时候,虽然并不存在a[10]这个元素,但是这里并没有真正访问a[10],而是根
据数组元素的类型来确定其值。所以sizeof(a[10])不会出错。
6. a[-1]代表什么意思?
首先要明白下标的形式被编译器解析成指针的形式,即a[1] 解析成 *(a+1),那么a[-1]就被解析成*(a-1)。
三. 指针数组 & 数组指针
数组指针:首先它是一个指针,它指向一个数组。也可以理解为"数组的指针。"
int *p1[10]
int (*p2)[10] 各代表什么?要弄清这个问题,首先要知道[ ]优先级比*要高。
p1先与[ ]结合,构成一个数组定义,数组名为p1,int*修饰的是数组的内容,即数组的每个元素。
p2中()的优先级比[ ]高,所以*号先与P2构成一个指针的定义,指针变量名为P2,int修饰的是数组的内容,即数组的每个元素。数组在这里没有名子。
四. 函数指针 & 指针函数
指针函数:带指针的函数,也就是返回指针的函数。
- char * fun(char* a, char* b) //定义为 指针函数
- {...... }
- int main()
- {
- char* (*p)(char* p1, char* p2); //定义为 函数指针
- p = &fun; //把函数地址赋给他
- //p = fun; //这样写也行
- (*p)("aa", "bb"); //使用函数指针
- return 0;
- }
五. 指针常量 & 常量指针
- const char* p1; //常量指针,指向常量的指针
- char const* p2;
- char* const p3; //指针常量,指针是常量
怎么记?
a. 可以先把类型名去掉,然后看 const 离谁近,就修饰谁。
b. 也可以const 在 * 左边的为常量指针,const 在 * 右边的为指针常量。
六. 野指针
野指针是怎么造成的?1. 指针变量被创建而没有初始化。
2. 指针 p 被 free 或者 delete 之后, 没有置为 NULL。
转载于:https://blog.51cto.com/nyc1991/1122129