这两天因为工作需要,很是纠缠于C++中的指针(严格意义上来说应该算是C),虽然已经不算是初学者了,但是因为很长时间没有使用,还是有很多混淆的地方,所以干脆在此做一个总结。
首先定义一个最简单的int指针:
1 #include <iostream>
2 using namespace std;
3
4 int main(void)
5 {
6 int *single_pointer;
7 cout<<single_pointer;
8 cout<<*single_pointer;
9 }
可以看到VS2005的输出如下:
究其原因,因为只给出了指针的声明,却没有初始化,因此当执行到cout输出时,会出现访问内存错误的情况。
修改代码:
1 #include <iostream>
2 using namespace std;
3
4 int main(void)
5 {
6 char ch = 'a';
7 char *pointer_1 = &ch;
8 printf("%c\n", ch);
9 printf("%p\n",&ch);
10 printf("%p\n", pointer_1);
11 printf("%p\n",&pointer_1);
12 printf("%c\n",*pointer_1);
13 }
输出结果为:
到这里可以很明显的看出:
0x0018FF2B为字符ch的地址,
指针pointer_1指向字符ch的内存地址,所以pointer_1与对字符ch取地址&ch的打印结果是一样的。
而0x0018FF1C则为指针pointer_1本身的值。
或许这样可以看得更清楚:
只要搞清楚,指针本身也是一种数据类型,占用空间大小为四个字节,就很容易理解这一点了。
接着是二维指针,亦即所谓的指针的指针。
话不多,先贴代码:
1 #include <iostream>
2 using namespace std;
3
4 int main(void)
5 {
6 char **pPointer = NULL;
7 pPointer = (char **)malloc(10 * sizeof(char *));
8
9 *pPointer = "12";
10 *(pPointer + 1) = "345";
11 *(pPointer + 2) = "6789";
12
13 printf("*pPointer: %s\n\n",*pPointer);
14
15 printf("P *pPointer: %p\n",*pPointer);
16 printf("P *(pPointer + 1): %p\n",*(pPointer + 1));
17 printf("P *(pPointer + 2): %p\n\n",*(pPointer + 2));
18
19 printf("& &*pPointer: %p\n",&(*pPointer));
20 printf("& &*(pPointer + 1): %p\n",&*(pPointer + 1));
21 printf("& &*(pPointer + 2): %p\n\n",&*(pPointer + 2));
22
23 printf("P pPointer: %p\n",pPointer);
24 printf("P pPointer + 1: %p\n",pPointer + 1);
25 printf("P pPointer + 2: %p\n\n",pPointer + 2);
26
27 printf("& pPointer: %p\n",&pPointer);
28 printf("& pPointer + 1: %p\n",&pPointer + 1);
29 printf("& pPointer + 2: %p\n\n",&pPointer + 2);
30
31 printf("C **pPointer: %c\n",**pPointer);
32 printf("C **pPointer + 1: %c\n",**pPointer + 1);
33 printf("C **pPointer + 2: %c\n\n",**pPointer + 2);
34
35 printf("S *pPointer: %s\n",*pPointer);
36 printf("S *pPointer + 1: %s\n",*pPointer + 1);
37 printf("S *pPointer + 2: %s\n\n",*pPointer + 2);
38
39 printf("S *pPointer: %s\n",*pPointer);
40 printf("S *(pPointer + 1): %s\n",*(pPointer + 1));
41 printf("S *(pPointer + 2): %s\n\n",*(pPointer + 2));
42
43 printf("& &pPointer: %p\n",&pPointer);
44 printf("& &(*pPointer): %p\n\n",&(*pPointer));
45
46 printf("D sizeof(*pPointer): %d\n",sizeof(*pPointer));
47 printf("D strlen(*pPointer): %d\n",strlen(*pPointer));
48 printf("D sizeof(**pPpointer): %d\n\n",sizeof(**pPointer));
49 }
VS2005下的输出为:
首先明确一点?何为指针?
看一个最简单的指针的定义:char *p
首先,指针本身是一种数据格式,有别于int这样的基本数据类型,它会指向一块指定的内存(所以指针如果没有初始化会出现野指针的情况)。因此,作为指针数据类型,p本身会在内存中占用一块大小为sizeof(void *)在本文中值则为4的内存,同时因为p被声明为char *而不是void *,所以p所指向的内存中存放的是一个char类型的值,占一个字节。
理解这一段之后再来看所谓二维指针的定义,也就很容易理解了。
来看二维指针的定义:char **p,实际上应该理解为(char *) *p
亦即,p为一个指针,p所指向的内存中存放的数据为另一个指针,而这个p指针所指向的指针指向的最终内存块存放的为一个char值,p->another_pointer->char。
笔者做了一个粗略的描述图:
其中temp_1-3三个指针为笔者虚拟的存在,分别代表指针pPointer,pPointer+1与pPointer+2所指向的内存。
此时再来看上面的输出:
pPointer为指向指针的指针,它在内存中的地址为0X0018FF28,它所指向的内存为&*pPointer,也就是上图中temp_1的位置,为0X00520F60,可以看到由于申请内存的大小为10*sizeof(char *),因此temp_1-3的三块地址是连续在一起的。
而*pPointer本身也是一个指针,它所指向的内存地址为0X00415984,该内存中存放的是一个char型的字符,值为‘1’
最后,对代码中的一些输出做一些解释:
名称 | 类型 | 解释 |
pPointer | 指针 | 指针的指针 |
*pPointer | 指针 | pPointer所指向的内存中存放的指针 |
**pPointer | 字符 | 对指针(*pPointer)做解引用操作所获取的值 |
&*pPointer | 地址 | pPointer所指向的内存地址,亦即上文中temp_1指针的地址(区别于指针指向的地址) |
pPointer+1 | 指针 | 指针pPointer所指向的内存的后一块内存,亦即上文中的temp_2 |
*pPointer+1 | 指针 | 指针*pPointer(亦即temp_1)所指向内存的后一块内存,上文中为字符‘2’所在的内存 |