在计算机内存中,每一块内存都有自己的地址,这里的地址在c语言中就叫指针,详细来说指针就是一个用于存储“另外一个变量地址”的变量。
int a = 0;
printf("%p\n", &a);
这里&a会取出a所占四个字节中地址较小的字节的地址
int a=0;
int *p=&a;//取出a的地址并保存在指针变量p中
我们&a得到的地址是一个数值,比如0X006FFD70,这种变量一般存放在指针变量中,也就是*p,这种变量就是用来存放地址的,存放在指针变量中的值都会被理解为地址。
当然*还有一个重要的用途就是解引用,通过解引用可以找到指针指向的对象。
int a=10;
int *p=&a;
*p=0;
这里第三行*p=0就使用了解引用,意思是通过p存放的地址找到p指向的对象并将值改为0,最结果是a=0。
众所周知变量类型有很多种,每种类型所占的字节也略有差异。
printf("%zd\n", sizeof(int));//4
printf("%zd\n", sizeof(char));//1
printf("%zd\n", sizeof(double));//8
printf("%zd\n", sizeof(float));//4
但是如果是指针变量的情况下会惊奇的发现,如果是x86环境下所有类型都是4个字节,x64环境下都是8个字节。这里的原因是
在x86环境下,指针变量的大小通常为4个字节,这是因为x86架构的内存寻址是基于32位的,即32位地址空间。每个指针变量存储一个内存地址,这个地址是由32位二进制数表示的,因此占据4个字节的存储空间。
而在x64环境下,指针变量的大小通常为8个字节,这是因为x64架构的内存寻址是基于64位的,即64位地址空间。每个指针变量存储一个内存地址,这个地址是由64位二进制数表示的,因此占据8个字节的存储空间。
指针变量的大小与计算机架构的内存寻址位数有关,不同的架构有不同的位数要求,因此指针的大小也会相应地变化。
printf("%zd\n", sizeof(int*));
printf("%zd\n", sizeof(char*));
printf("%zd\n", sizeof(double*));
printf("%zd\n", sizeof(float*));
上面说明了所有指针类型的大小都是一样的,那为什么我们还有各种各样的指针类型呢,因为指针类型决定了,对指针解引用时候有多大权限,一次可以访问多少个字节。例如:char*一次只能访问一个字节,int*一次可以访问四个字节
int n = 10;
int* p1 = &n;
char* p2 = (char*)&n;
printf("%p\n", &n);
printf("%p\n", p1);
printf("%p\n", p1+1);
printf("%p\n", p2);
printf("%p\n", p2+1);
运行结果如下,可以发现char*+1跳过了一个字节,而int*跳过四个字节,指针类型决定了指针的步长有多少。
再举一个例子
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = &arr[0];
for (int i = 0; i < 10; i++) {
printf("%d ", *(p + i));
}
这里程序的最终结果就是把数组中所有的数据都打印出来,得出结论就是p指向了数组首元素的地址,而指针是int类型所以每次指针加1就会向后走4个字节,也就是数组的下个元素的地址,再解引用就是相当于arr[i]的作用。
int the_strlen(char* s)
{
char* p = s;
while (*p) {//不是\0就一直找
p++;
}
return p - s;
}
int main() {
printf("%d ", the_strlen("abcdefg"));
}
上段代码模仿了strlen函数,利用形参接受字符串首元素地址,再通过字符串结尾一定会有\0的特点设计的一个函数,主要原理是通过循环使得指针地址的一直加,再解引用一直判断元素内容最终得出的结果。