近期对C/C++里指针的一些认识
C语言系最大的特点就是指针
在C语言系里,指针实际上就是一个地址。
int num = 0;
int *ip = #
printf("pointer: 0x%.8lx address: 0x%.8lx",ip, &num);
这里打印出来的pointer
,address
将会是一样的值,如果在64位机器上运行,可以将精度调成更高的。
指针的运算
我听说以前C语言没有泛型指针,也就是现在的void,当时用char*
可以表示指向任意一个类型的指针。
为什么可以这样呢?以下面的代码为例
int num = 0;
int *ip = #
char *cp = (char *)#
那么cp
和ip
的值实际上是一样的,但是他们又不一样的地方:
- 这里有一点需要说明的是下面叙述中
&num+4
在程序里实际上是和指针运算一样的,我这里当做地址加减,纯粹的地址加减。
- 对
ip
进行运算,比如ip++
将会得到&num + sizeof(int)
,而对cp
进行运算,同样的,cp++
,得到的是&num + sizeof(char)
,也就是指针运算不一样 -
&ip[1]
,&cp[1]
,也是不一样的,这个就和第一点类似
也就是最主要的就是对地址的解释不一样(我是这么理解的),那么在返回char*后,可以使用casting,强制转换类型,既然返回的地址是一样的,那么我把这个地址按照我想要的方式去解释,然后再把地址里的内容取出来就是我想要的东西。
更直观的看看下面的代码
int *ip = (int *)malloc(2*sizeof(int));
char *p = (char*)ip;
*ip = 1;
*((int *)p+1) = 2;
printf("ip[0]:%d ip[1]%d",ip[0],ip[1]);
将会输出一下结果ip[0]:1 ip[1]2
,代码中把ip
地址首先按照char*
解释,赋值给了p
,然后在第四行,又将p
地址按照int*
来解释,那么p+1
自然就到了&ip[0]+4
的位置。
指针和数组的联系
稍微了解一点C语言的人都知道,数组和指针是不分家的,数组名就是一个指针,也是数组的起始地址,一个数组既可以通过下标访问,又可以通过指针访问。在程序实际执行过程中,指针访问是要快一点的,下标访问每次迭代出下标后,程序会根据下标运算出地址,实际上做了重复运算,这里不重点叙述。
一个数组array[5]
,有五个元素,首地址是array
,也是&array[0]
,array[i]
,*array+i
,*&array[0]+i
都是等价的。
多维数组
看看下面的代码:
int array[4][5];
int *p = (array+1);
int *end = &array[3][4];
while(p != end){
*p = 1;
p++;
}
要想看懂这段代码,唯一的关键就是理解
int *p = (array + 1);
在干什么,实际上这句代码和下面这句代码是等效的
int *p = array[1];
array
是一个4元素数组,每个元素由5 int数组构成,所以array[1]
是一个5 int 数组的名称,也就是首地址,和array+1
, 相当于&array[0]+sizeof(int[5])
,所以上面的代码就做了一件事,遍历了array[1] [0]
之后的所有元素,赋值为1。
总结
数组名称是首地址,也是指针,对它进行运算就是相当于首地址加上其中元素长度。
指针和数组还有函数的优先级
指针的优先级比数组[]还有函数()都低,因此在声明一个函数指针时必须这样:
int (*p)(int arg);
这里p是一个指针,指向一个函数,函数接收一个int的参数,返回一个int 值
再来看看指针和数组的优先级
int *p[5];
int (*p)[5];
第一行大家都比较熟悉,是一个数组,有5个int*
的元素
第二行可能就比较陌生了,p是一个指针,指向一个拥有5个int元素的数组
数组和指针的区别
- 最明显的区别应该就在size上了,比如下面的代码
char arr[5];
char *p;
第一行声明了一个5元素的字符数组,sizeof(arr)
将会返回5,而sizeof(p)
将会返回8(在64位机器上)
这里又要提到一个很不常见的声明:
char arr[0];
声明了一个0元素的数组,那么sizeof(arr)
是多少呢,如果你实验一下就会发现,居然是0,这个可以当做指针来用的居然不占空间,也是很奇特的。