一 . 指针的使用和传值调用
(1)strlen 的模拟实现
库函数 strlen 的功能是求字符串长度,统计的是字符串中 ' \0 ' 之前的字符个数,函数原格式如下:
我们的参数 str 接收到一个字符串的起始地址,然后开始统计字符串中 ' \0 ' 之前的字符个数,最终返回长度。现在我们来模拟实现 strlen 函数,只要从起始地址开始,向后逐个遍历字符,每遇到一个字符,判断其是否为 ' \0 ',若不是,则计数器 + 1,是则停止
(2)传值调用和传址调用
这两个的区别,我们可以通过一道题深入理解:
写一个函数,交换两个整型变量的值:
1 . 传值调用:
上图就是传值调用,看似没有问题,但我们的运行结果却出乎了我们的意料,a、b 的值并没有按照我们预想的那样交换,这是为什么呢?我们可以通过调试中的监视来观察观察:
在上方两个调试的图中,我们可以看到,在我们的 Swap1 中,的的确确是将我们的 x、y 的值进行了交换,但是我们也可以看到,a、b (实参)的地址和 x、y (形参)的地址是截然不同的,这就证明,a、b 和 x、y 有着本质上的区别,我们改变的是在 Swap1 中的 x、y ,并不是我们想要改变的 a、b(地址不同,证明 a、b 和 x、y 向内存申请的空间并不是同一块空间,这两者之间没有必要联系)
这里就引出一个重要概念:当实参传递给形参的时候,形参会单独创建一份临时空间来接收实参,对形参的修改不影响实参!!!
我们想要通过一个函数来达到交换变量值的目的,我们应该打破表象看本质,从变量的地址下手,用另一种方法——传址调用
1 . 传址调用:
如图,使用传址调用时,我们通过调试可以看到,a、b 和 *pa、*pb 的地址是一样的,通过地址去改变这两个变量的值,就可以从本质上去修改它俩的值
总结:传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用;如果函数内部要修改主调函数中的变量的值,就需要传址调用
二 . 数组名的理解
之前我们提到过使用指针访问数组内容,我们知道了,数组名其本质就是首元素的地址,如下图:
这个时候就有小伙伴发出真挚的疑问了:讲道理,如果数组名就代表着首元素的地址,我们之前所见到的sizeof(arr)为什么是 40 而不是 4/8 呢?如下图:
这里呢就是我们的一个例外情况了哈,有关于数组名的使用有两个例外:(重点重点重点!!!)
(1)sizeof(数组名):当 sizeof ()中单独放置数组名,这里的数组名就表示整个数组,计算的是整个数组的字节大小
(2)& 数组名 :这里的数组名表示整个数组,取得是整个数组的地址(整个数组的地址与数组首元素的地址是有区别的)
三 . 指针访问数组
关键点的解读都在代码中为诸君做了注释,我就不过多赘述了
四 . 一维数组传参的本质
不知道大家有没有注意过,我们跟数组打了那么多次交道,sizeof()我们也用过多次,但我们一直都是在函数外部计算数组的元素个数,然后再通过传参的方式将 sz (元素个数)传递给函数。那么我们可不可以通过传参过来的数组直接在函数内部计算数组中的元素个数呢?不妨一试:
可以看到我们这个输出结果并不像我们预想的那样,问题就出在我们数组的传参上
在上面第二点我们提到过,数组名的本质是首元素地址。所以函数形参的部分理论上应该是使用指针变量来接收首元素的地址,那么在函数内部,我们这个时候使用 sizeof()计算的就不是一个数组的字节大小了,而是计算的一个地址的字节大小
不管我们怎么去传参,本质都是以指针形式表现的,如图:
总结:在函数内部我们使用sizeof()计算的都是对其首元素地址的字节大小(4 或 8由编译环境决定)。所以在函数内部是没法求数组的元素个数的
五 . 二级指针
众所周知,指针变量那也是变量,是变量就有地址,我们指针本身就是指向一个地址的,那么它本身作为一个变量而言,它的地址又存放在哪里呢?
这就是我们所谓的二级指针,这文字理解起来有点绕昂,跟俄罗斯套娃一样,咱们上图理解:
如图,这段代码的含义就是:
(1)创建了一个整型变量 a 并赋值为 10
(2)取出 a 的地址存放在指针(一级指针)pa 中
(3)同理再取出 pa 的地址存放在指针(二级指针)ppa 中
总结:二级指针的本质存放的就是一级指针的地址
文字、图片的表达能力终究有限,还望诸君见谅,自己细心一层一层地捋开指针之间的嵌套关系
六 . 指针数组
指针数组?到底是指针还是数组呢?一时半会捋不清的小伙伴们不妨类比一下我们学习过的知识:整型数组——存放整型的数组;字符数组——存放字符的数组
由此观之,指针数组就是用来存放指针的数组
指针数组当中的每一个元素都是一个指针,或者说每个元素都是指向内存中一块空间的地址
(1)指针数组模拟二维数组
不知道大家可还记得二维数组,我们可以先来回顾一下
想更仔细了解的,可以点链接查看我之前的博客哦,里面较为详细的介绍了二维数组的相关知识:二维数组 和 变长数组_变长二维数组-CSDN博客
接下来我们利用指针数组来模拟实现我们的二维数组:
前面提到过:指针数组就是用来存放指针的数组,我们这里三个数组——arr1、arr2、arr3,又新创建了一个 *parr ,而在这其中,将这三个数组放进去,又因为数组名就是首元素的地址,所以这里三个数组放到 parr 中时都是属于 int* 类型的指针,看下图更好理解:
应该注意的是:以上代码只是我们运用指针数组模拟实现的二维数组,并不是真正意义上的二维数组,因为它们的每一行并非连续的
这里没有什么生冷硬的知识,都是将我们学到过的知识点串联起来就可以得出,相信以诸君的聪明才智,定能轻松拿捏!
OKK,今天有关于指针的小部分知识就跟大家聊到这里,咱们下期再见咯。与诸君共勉!!!