一.前言
指针作为初学C语言中较为让人头疼的知识点,笔者认为其中难点在于“如何准确的判断出指针及其类型”。本文将紧紧围绕这个点对指针的基础知识点进行详解,希望能抛砖引玉,也希望各位大佬能提出宝贵意见。
二.学习指针前,我们需要知道什么是指针
我们都知道CPU在运行时都是从内存中读取数据,运行结束后又会将数据重新写入内存。由此我们会有一个疑问——内存不可能无限的大,我们如何在有限的内存空间中高效运用有效管理呢?
思考一下,我们是如何利用有限的土地资源并进行管理的呢?
我们会在土地上建造一个又一个的“房间”,“房间”会组成一栋“楼”,“楼”又会组成“小区”……我们也会给每个“房间”分配“门牌号”,让一个一个“人”住到“房间”里。如果我们要找任意一个“人”,只需要知道他的“门牌号”就可以。我们也可以让某个“人”“搬入”或者“搬出”某个“房间”。
类比一下,我们的计算机也是这么处理的。“房间”代表字节,有了字节(房间)可以组成更大的单位,比如千字节(楼),兆字节(小区)……“人”代表数据,占一个比特位,“搬出”和“搬入”分别代表数据的读取和写入。至于“门牌号”就是我们今天的主角——指针。
由此可见,内存单元的编号==地址==指针
指针变量是内存的地址,用来访问内存中的某一块特定的空间,而指针类型决定访问权限,决定如何正确的访问这块空间。
三.如何得到指针变量及指针变量的基本使用
在这里我们介绍两个操作符,分别是取地址操作符(&)和 解引⽤操作符(*)。前者的作用是得到得到变量/数组/函数等空间的地址,后者是对已知的地址进行访问操作。
其中我们对一级指针再取地址就会的到二级指针。
注意,我们应当规范化编程,避免野指针的形成。比如尝试使用assert断⾔,函数不返回函数内创建的数组等……
四.指针的大小及基本运算
指针大小
指针变量的大小取决于环境,32位平台下4个字节,64位平台下8个字节。
指针运算
1.指针-指针
两个指针在同一数组内,得到两个指针间的元素个数。
2.指针+-整数
得到往后/前整数个元素的地址。
3.指针关系运算
可以用>=<判断关系。
五.指针在函数传址中的应用
函数的形参是实参的一份临时拷贝,改变形参不影响实参。使用函数传址调用可以构建联系,实现在函数中改变主函数相关变量值的功能。
六.指针与数组
1.数组的访问与传参本质
数组除了a[0]的访问方式,也可以等价于用指针访问 *(a+0)。其中一维数组传参的本质是传递首元素的地址,二维数组传参的本质是传递首行的数组名。
2.指针数组
指针数组是一种数组,每个元素是指针的数组,可以模拟实现二维数组。
#include <stdio.h>
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
七.函数指针
我们同样可以对函数取地址,其中函数名就是函数地址。函数地址和函数名用法一致能够,利用()即可调用。由此引申出回调函数的概念,即⼀个通过函数指针调⽤的函数。把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
八.特殊指针类型
1.int (*p)[10]
数组指针变量
2.void *
可以接收任意数据类型的地址
结语
以上便是今天的全部内容。如果有帮助到你,请给我一个免费的赞。
因为这对我很重要。
编程世界的小比特,希望与大家一起无限进步。
感谢阅读!