一.指针基础
0.指针的大小
指针指向的是一块地址,所以指针存储的是地址,例如在32位系统中。定义了一个int32_t类型的变量。使用int32_t *定义一个指针,使其指向该变量。
设该变量存储在地址为00000000000000000000000000000001(32位地址)中,指针指向该变量,其实就是指针P存储了该变量的首地址
既然指针P里面存储的是首地址(存储空间第一个字节的地址),在32位地址系统中,那么显然指针P里面要存32位二进制数,所以指针P的大小就是4个字节。同理在64位系统中,指针的大小为8个字节。
1.指针的步长
①.char、uint8_t 类型指针
若定义一个char或uint8_t类型的数组,用char*/uint8_t*定义的指针指向该数组
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t buf[8] = {1,2,3,4,5,6,7,8};
uint8_t *p = buf;
printf("p :%p\n",p); //打印P初始指向的地址
printf("p+1:%p\n",p+1); //P+1后的地址
printf("p+2:%p\n",p+2); //P+2后的地址
return 0;
}
根据打印出的值来看,uint8_t类型的指针每次加1,则其内部存储的地址值也加1
(即跳过了一个字节)
②.int16_t类型的指针
若定义一个uint16_t类型的数组,用uint16_t*定义的指针指向该数组
#include <stdio.h>
#include <stdint.h>
int main()
{
uint16_t buf[8] = {1,2,3,4,5,6,7,8};
uint16_t *p = buf;
printf("p :%p\n",p);
printf("p+1:%p\n",p+1);
printf("p+2:%p\n",p+2);
return 0;
}
根据打印出的值来看,uint16_t类型的指针每次加1,则其内部存储的地址值加2
(即跳过了两个字节)
③.int32_t类型的指针
#include <stdio.h>
#include <stdint.h>
int main()
{
uint32_t buf[8] = {1,2,3,4,5,6,7,8};
uint32_t *p = buf;
printf("p :%p\n",p);
printf("p+1:%p\n",p+1);
printf("p+2:%p\n",p+2);
return 0;
}
根据打印出的值来看,uint32_t类型的指针每次加1,则其内部存储的地址值加4
(即跳过了四个字节)
总结
规律其实已经出来了,当执行指针P+1时,P内存储的地址不一定也只加1。地址具体的变化要看该指针是什么类型的,uint8_t(一个字节)则P+1时,其内部地址会跳过一个字节;uint16_t(两个字节)则P+1时,其内部地址会跳过两个字节。以此类推......
二.指针类型转换
前面已经提到,指针内部存储的是地址。
指针的类型有uint8_t,uint16_t,uint32_t,float等等,现在来定义一个uint8_t类型的数组,再定义uint8_t,uint16_t,uint32_t类型的指针。
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t buf[8] = {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
uint8_t *u8_p = buf;
uint16_t *u16_p = buf;
uint32_t *u32_p = buf;
printf("u8_p[0] :%d\n",u8_p[0]);
printf("u16_p[0] :%d\n",u16_p[0]);
printf("u32_p[0] :%d\n",u32_p[0]);
return 0;
}
指针的类型其实起到了一个“翻译”的作用,不同的指针类型指向同一块地址。“翻译”出来的结果是不一样的。
1.翻译的步骤
“翻译”的步骤大概是这样:
假设有一块地址内的数据如下:
用不同的指针去指向该地址的首地址
①.uint8_t
已知 uint8_t 类型的指针,其步长为 1 个字节,所以 u8_p 每次 + 1 ,都是跳过 1 个字节。u8_p[0] 也就是该地址首地址的内容,当作 uint8_t 类型的数据来看,就是 1 。
②.uint16_t
已知 uint16_t 类型的指针,其步长为 2 个字节,所以 u16_p 每次 + 1 ,都是跳过 2 个字节。u16_p[0] 也就是该地址中前 2 个字节的内容,一起当作 uint16_t 类型的数据来看,就是 257 。
③.uint32_t
已知 uint32_t 类型的指针,其步长为 4 个字节,所以 u32_p 每次 + 1 ,都是跳过 4 个字节。u32_p[0] 也就是该地址中前 4 个字节的内容,一起当作 uint32_t 类型的数据来看,就是 16843009 。
2.总结
(1)
其他 float 等类型的指针也是一样,要是这段地址,你想以float类型去翻译它,只需定义一个 float * float_p 类型的指针指向首地址,然后 float_p[0] 就是我们需要的数据。
(2)
如果给你了一个 uint8_t 类型的数组如下:
uint8_t buf[8] = {0xc3,0xf5,0x48,0x40,0x9a,0x99,0xb1,0x40};
要把这个数组里面的数据变成 float 类型的数据,并存储起来,则需要这么做
float value1,value2;
value1 = ((float *)buf)[0]; //指针类型转换
value2 = ((float *)buf)[1];
以上,就是将 uint8_t 类型的数组里面的值,转换成 float 类型的数据
三.指针数组
1.定义
指针数组,其强调的是数组,这个数组里面存的是指针。
假设在存储空间中,有一条字符串 "hello" ,它是这么存储的:
要找到这条字符串,就得知道它的地址,也就是首字节(首个字符)的地址。
而字符串指针数组,里面存的其实就是对应字符串的首地址
buf[0] = 0X00000000;
buf[1] = 0X00000006;