关于指针的一些基本常识
这两天因为工作需要,很是纠缠于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’所在的内存 |