一、指针的定义
指针是C语言的灵魂,数据结构的基础。
首先我们给出指针的官方定义:指针(英语:Pointer),是在许多编程语言中用来存储内存地址的变量。
简化一下,指针是变量,它是表示内存地址的。类比一下int,我们知道int表示的是整型,char表示的是字符型,那么指针就是表示的是内存型。
我们知道C语言的数据类型有很多,那么对于这些类型它们都有自己的指针,例如我们常见的int *它就表示用它定义的变量只能存储int类型变量的地址。
浓缩一下:指针就是地址,地址就是指针。
下一个问题,什么是地址?
这里的地址不是说你的家庭住址,而是内存地址,也就是内存单元的编号。计算机中的数据都是按照地址进行存放的,这样好方便查找。类似于你买快递时
你得填上地址,快递员才好将快递送到你的手中。如果你不写的话,后果也是不言而喻的。
代码加画图理解
下面我们用代码来详细解释一下
#include <stdio.h> /*指针 指针就是地址,地址就是指针 我们操作的变量的实质就是操作计算机中的内存 我们通过地址来对内存进行访问 */ int main(){ //声明一个指针p,将它的地址以十六进行打印出来 int *p;// p是一个指针变量,int *表示该变量p只能存储int类型变量的地址 printf("初始p的值为:%d\n", p); //现在我们这个指针变量p进行赋值 int temp = 10; printf("变量temp的地址为%d\n", &temp); p = &temp;//使用'&'取地址符,将temp的地址赋值给p printf("更改前*p的值为:%d 此时p的值为:%d\n", *p,p); temp--; printf("更改后*p的值为:%d 此时p的值为:%d\n", *p,p); /*这个时候p就是指向的temp,注意,如果你修改temp对p是没有任何影响的,但是对*p是有影响的*/ return 0; }
运行结果如下图
我们可以看到在更改之后*p的值发生了改变而p的值却没有变化。因为p是存储的temp的地址,我们只是改变了temp的值,并没有改变它存储的位置。
而*p就不同了*p表示指向的temp的值,所以会跟着改变。
图示
所以*p和temp其实就是一个东西,方便理解的话就是*p就相当于那个箭头,当你访问*p的时候他就会把你带到temp那里。既然*p就等于temp
那么我们 int i = *p 是不是就等同于 int i= temp呢?答案是肯定的,建议自己动手试一下。
三、指针和数组
我们要知道数组的定义是由相同类型的元素的集合所组成的的数据结构,分配一块连续的内存来存储。利用元素的索引来计算元素对应的存储地址。
-
一维数组名是一个指针常量,它存放的是一维数组第一个元素的地址,它的值不能改变
-
一维数组名指向的是数组的第一个元素
它和指针的联系在于 arr[i] == *(arr + i) == i[arr]。一般前面两个比较常见,因为数组是连续存储的并且arr是存放的一维数组的第一个元素的地址
那么arr + i实际上是计算的是arr + i * 指针变量的类型,已知int是占四个字节,例如我们的 arr + 3 就是 arr + 3 * 4,也就是说我们其实是在内存中将
arr往后移动了3 * 4个字节的长度,数组是连续存储的所以就等同于arr[3],访问第四个元素。
代码理解
我们用代码实现一下上述操作,并用指针完成对数组的输出
#include <stdio.h> /*指针和数组 一维数组名是一个指针常量,它存放的是一维数组第一个元素的地址,它的值不能改变 一维数组名指向的是数组的第一个元素 */ void Show_Array(int *p,int len){ for (int i = 0; i < 5; i++) printf("%d ", *(p + i)); } int main(){ // 定义一个数组在我们看来它是存放的数字1到5,但是实际上它存放的是arr[0]到arr[4]; int arr[5] = {1, 2, 3, 4, 5}; /*根据上面的规定我们知道 a是指向的a[0] */ // a[i] == *(a + i) == i[a]; printf("arr[3] = %d *(a + 3) = %d 3[arr] = %d\n", arr[3], *(arr + 3), 3[arr]); //通过数组的首地址和数组的长度既可确定一个数组 Show_Array(arr,5);//arr就等价于 &arr[0],是一个int *类型的值 return 0; }
运行结果如下图:
就此我们可以看到指针和数组的联系在于下标的转化。