【C语言】一文详解指针(初阶)
创始人
2024-03-30 13:54:26
0

一、指针是什么

要了解指针,那我们先说说什么是内存?

内存就是计算机中的存储数据的区域
而指针是内存中的一个最小单元的编号,也就是地址
我们平时口头语中所说的指针,通常指的是指针变量,是用来存放内存地址的变量

那么内存在计算机中是如何编号的呢?

对于32位的计算机,我们假设有32根地址线,那么把每根地址线通电,就会产生高低压和低电压,把电信号转换成数字信息,用二进制表示,就是0和1。

那么32根地址线产生的地址就会是:
在这里插入图片描述

假设计算机中的内存条一个长方形表示一块内存单元,0,1,2,3…表示一个编号(在计算机中编号(地址)用16进制表示):

在这里插入图片描述
在计算机中一个地址是一个字节,那么我们就可以计算32位的计算机可编址的大小:
在这里插入图片描述
下面我们举个例子加深对指针变量的理解:

#include 
int main()
{int a = 10;int* pa = &a;*pa = 20;printf("%d", a); // 20return 0;
}

上述这个例子当中,pa是用来存放地址的,也就是指针变量
*pa就是通过pa里边的地址,找到a,然后把a的值改为20

二、指针和指针类型

我们都知道,变量有不同的类型,整型、浮点型等。指针也是有类型的。

我们给指针相应的类型:

char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;

那么指针类型有什么意义?

2.1、指针不同类型的解引用

首先我们举个例子:

#include 
int main()
{int a = 0x11223344;int* pa = &a;*pa = 0; // 内存中的字节全改为0,即00 00 00 00//char* pc = &a;//*pc = 0; //内存中的字节改为00 33 22 11,只改了第一个字节return 0;
}

pa在内存中的结果:
在这里插入图片描述
pc在内存中的结果:
在这里插入图片描述

由上述例子可知:
指针类型决定了解引用操作的时候,访问了几个字节 char* 访问一个字节,int* 访问4个字节

2.2、指针±整数

下面我们来看看指针±整数会出现什么结果:
在这里插入图片描述

由上图可知int * 指针+1,则跳过一个整型,向后走了4个字节。
          char * 指针+1,则跳过一个字符,向后走了1个字节。
指针类型决定了指针的步长,也就是向前或向后走一步要多大距离

三、野指针

野指针就是指针指向的位置是未知的、随机的、不正确的,没有明确限制的

3.1、造成的原因:

1、指针未初识化

#include 
int main()
{int* p; // p就是野指针*p = 20;return 0;
}

2、指针越界访问

#include 
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;for (i = 0; i <= sz; i++) // 越界访问,造成野指针{*p = i;p++;}return 0;
}

3、指针指向的空间已释放

#include 
int* test()
{int num = 100;return # // 出函数,num空间就不存在了
}
int main()
{int* p = test();*p = 200; // 找不到原空间,此时p是野指针return 0;
}

3.2、如何规避野指针:

1、指针初识化

int* p = NULL;

2、小心指针越界访问
3、指针指向空间释放,及时置NULL

//开辟动态空间
int* p = malloc();
//使用//释放
free(p);
p = NULL;

4、避免返回局部变量的地址
5、指针使用之前检查有效性

int* p = NULL;if(p != NULL){printf("%d\n", *p);}

四、指针的运算

4.1、指针±整数

举个例子:

#include 
#define N 5
int main()
{int arr[N];int* vp = arr;int i = 0;//指针+-整数;指针的关系运算for (i = 0; i < 5;i++){*vp++ = 0;}return 0;
}

由于++优先级比 * 高,所以++只作用于vp,即 *(vp++),所以数组内的元素都为0

在这里插入图片描述

4.2、指针的关系运算

for (vp = &arr[5]; vp > &arr[0];){*--vp = 0; // 先--vp,再*vp,不会越界}

把代码改造为:

int main()
{for (vp = &arr[N - 1]; vp >= &arr[0]; vp--){*vp = 0;}
}

第二个代码在绝大部分的编译器上可以顺利完成,但是还应该避免这样写,因为标准并不保证它可行。

标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但不允许与指向指针第一个之前的那个内存位置的指针进行比较。

4.3、指针-指针

首先我们举个例子:
在这里插入图片描述

由上述可知,指针-指针绝对值的结果为指针之间的元素个数。

在这里插入图片描述

五、指针和数组

数组和指针不是一个东西
数组能够存放一组连续空间的数,数组的大小取决于元素大小
指针是一个变量,是存放地址的,32位下大小为4个字节,64位下大小为8个字节。
联系就是:数组名是地址(指针),数组把首元素的地址交给一个指针变量后,可以通过指针来访问数组。

下面我们来举个例子:

#include 
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("%d ", *p);p++;}printf("\n");return 0;
}

运行结果:
在这里插入图片描述
我们也可以通过数组下标访问每个元素

for (i = 0; i < sz; i++){printf("%d ", *(p+i));}

在这里插入图片描述

六、二级指针

指针变量也是变量,那么指针变量的地址又是存在哪里的呢?
这就是我们所说的二级指针。

int a = 10;
int* p = &a; // p是一级指针变量 
int* pp = &p; // pp就是二级指针变量

在这里插入图片描述

int * 是pp所指向p的类型,p的int是指向a的类型

对于二级指针的运算有:

*p = 200;
// 等价于**pp = 200;
// 等价于a = 200;

举个例子:

#include 
int main()
{int a = 10;int* p = &a;printf("%d\n", *p);int** pp = &p;printf("%d\n", **pp);int* ps = *pp;*ps = 20;printf("%d\n", *ps);return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述

**pp:第一次解引用找到p,再次解引用找到a

七、指针数组

首先问一问指针数组是指针还是数组呢?
当然,是数组,是存放指针的数组。

数组我们已知有:

int arr1[10]; // 整型数组,存放整型的数组
char arr2[10]; // 字符数组,存放字符的数组

那么指针数组又是什么呢?

int* arr3[5]; // 指针数组,存放整型指针的数组
char* arr4[5]; // 存放字符指针的数组

下面我们举个例子:

#include 
int main()
{int a = 10;int b = 20;int c = 30;int* arr[3] = { &a,&b,&c };int i = 0;for (i = 0; i < 3; i++){printf("%d ", *(arr[i]));}return 0;
}

运行结果:
在这里插入图片描述
指针数组的应用:
用一维数组模拟一个二维数组:

#include 
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int arr4[] = { 4,5,6,7,8 };int* arr[4] = { arr1,arr2,arr3,arr4};int i = 0;for (i = 0; i < 4; i++){int j = 0;for (j = 0; i < 5; j++){printf("%d ", arr[i][j]); // 等价于*(*(arr+i)+j)}printf("\n");}return 0;
}

运行结果:
在这里插入图片描述

相关内容

热门资讯

落户政策居然考虑放开! 怎么,我能落户北京了? 大家好,我是孙少睡,这是我的第467篇楼市评论。 很多人的第一反应肯定是有没...
股市必读:ST泉为股东因涉嫌违... 截至2025年12月26日收盘,ST泉为(300716)报收于9.96元,下跌0.8%,换手率0.9...
日本公布犯罪白皮书:2024年... 日本法务省19日公布的2025年版犯罪白皮书显示,日本2024年刑事犯罪案件数量明显上升,其中性犯罪...
中央广电总台副台长王晓真,黑龙... 据央视新闻报道,12月28日,中央广播电视总台《2026年春节联欢晚会》分会场发布。黑龙江哈尔滨、浙...
聚焦全国财政工作会议丨明年财政... (央视财经《经济信息联播》)明年是“十五五”规划的开局之年,财政政策将聚焦哪些关键领域精准发力? ...
原创 中... 12月26日,中国对美国实施了一次重磅反制,针对美国政府前不久批准的111亿美元对台军售,中方决定出...
徐杰11分王少杰遭驱逐 张宁缺... [搜狐体育战报]北京时间12月28日消息,2025-26赛季CBA常规赛继续第7轮角逐。王少杰第三节...
《今日说法》主持人李晓东买茶叶... 12月28日,《今日说法》栏目主持人李晓东发布视频称,此前“被骗1000元买茶叶”事件迎来新进展:该...
3-0领先终于能休息了!莫德里... 在意甲第17轮的一场焦点战中,AC米兰迎战维罗纳。比赛进行到第70分钟时,AC米兰在3-0领先的情况...