指针和数组联用
- 不同类型指针变量之间的区别
- 数组的指针
- 指针数组
不同类型指针变量之间的区别
在了解数组和指针联用之前,我们先对指针变量进行补充。我们对比一下int *p1和char *p2
的区别?
相同点:
- 都是指针变量
- 都是用来保存一个内存地址编号
- 占用的内存空间大小一样
int main(){
int a = 10;
char b = 'e';
int *p1 = &a;
char *p2 = &b;
// 输出指针变量所指向值的内容
printf("%d %c\n",*p1,*p2);
// 输出指针变量所占空间大小
printf("%d %d\n",sizeof(p1),sizeof(p2)); // 8 8
// 输出指针变量所指向空间的大小
printf("%d %d\n",sizeof(*p1),sizeof(*p2)); // 4 1
}
注意: 这里指针变量再32位机器上占用的内存空间是4个节,再64位机器上占用的空间是8个节。这是因为指针变量保存的是一个内存地址的编号,32位机器内存地址编号最大值为 2 32 − 1 2^{32}-1 232−1,可以用4个字节的变量保存。而在64位机器内存地址编号最大值为 2 64 − 1 2^{64}-1 264−1,可以用8个字节的变量保存。
不同点:
- int *p1的作用就是指针变量p1将他所指向的内存空间中的二进制当作int类型进行处理。
- char *p2的作用就是指针变量p2将他所指向的内存空间中的二进制当作char类型来处理。
p1++和p2++的区别,我们来看以下代码:
int main(){
int a = 10;
char b = 'e';
int *p1 = &a;
char *p2 = &b;
printf("%p %p\n%p %p",p1,p2,p1++,p2++);
return 0;
}
p1自增后输出的地址比开始多了4个字节,p2自增后输出的地址比开始多了1个字节,即当指针变量进行自增的时候,偏移的是一个数据类型,而并非一个字节。
数组的指针
一个变量有一个地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,他们都有相应的地址。所谓的数组的指针是指数组的起始地址。即数组名表示数组的首地址,因此数组名也是一种指针。在前面我们知道了数组可以通过下标进行访问。而当指针进行自增操作时,偏移的是数据类型的个数,所以这里我们还可以通过【数组名+偏移量】进行数组中元素的访问。
语法:
*(数组名+偏移量)
- 这里的偏移量指的访问元素的位置。
- 数组名加偏移量实际上是一个地址,然后通过指针运算符
*
将其地址中的内容进行取出。
代码如下:
int main(){
int ch[] = {1,2,23,33,3,3,5};
// 使用下标进行访问数组的第三个元素
printf("%d\n",ch[2]); //23
// 使用偏移量访问数组的第三个元素
printf("%d\n",*(ch+2)); //23
return 0;
}
指针数组
指针数组就是存放指针的数组,本质是数组,数组中的每个元素都是指针。
语法:
数据类型 *数组
- 数据类型支持所有的数据类型。
- 数组中的所有元素都是指针类型,即地址
数组中保存了几个整型常量的地址(需要注意的是这里保存的是地址而并不是整型常量)。
代码如下:
int main(){
int a = 10,b = 12,c = 13;
int *ch[3];
// 给指针数组进行初始化
ch[0] = &a;
ch[1] = &b;
ch[2] = &c;
// 因为ch[0] = &a,则对&a 进行指针运算符则相当于对数组进行操作
// 所以想得到a的内容需使用 *ch[0]
printf("b is%d\n",*ch[1]);
return 0;
}
注意:
int *ch[3]等价于(int *)ch[3]
;因为[]
比*
的优先级要高先与ch
进行匹配。所以这里就可以将他理解为他是一个int *
类型的数组。