栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言的几个小概念(指针数组、数组指针、指针函数、函数指针)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言的几个小概念(指针数组、数组指针、指针函数、函数指针)

前言

近日学习函数指针,有感而发!

一、指针数组(指针的数组)

指针数组首先是一个数组,说到数组首先我们关心的是数组长度和数组元素,而指针数组就是一个长度在中括号里给定的、数组元素均为指针的一个数组,因此叫指针数组,像整型数组,字符数组应该都是这么命名的。
例如:int *p [ 4 ] ;(这里要提一下的是,在识别这个定义的时候中括号的优先级是大于星号的,所以首先中括号和 p 结合,形成一个 p 数组,然后 p 再和星号结合形成一个指针, 最终构成一个指针数组。)

这个数组里面有四个指针元素,每个指针都指向一个地址,每个地址后面都存着相应的数据,这个就是指针数组。

二、数组指针(数组的指针)

数组指针首先他是一个指针,他和指针数组的区别是,数组指针是指向一个中括号内给定大小的空间,他是一个指针指向一个数组,指针数组是一个数组,包含一些指针(这两个概念比较拗口,希望大家多看两遍理解一下)

这个东西有点像二维数组,当然这个 q 单独拿出来的时候实际上指向的是第一行的首地址,然后你在输出第一个元素的时候你用 *q 先找到第一行,然后 **q 找到第一个元素,如下:

当我们想要调出数组内的其他元素时可以进行以下操作:

这里要引出一个问题:

数组指针、指针、一维数组、二维数组、有什么区别和联系?
解:
(1)上面我将一个二维数组赋值给一个数组指针,有结果说明这样的操作是被允许的;但是我在操作的时候有这样的疑问,那为什么不能将一个一维数组赋值给一个数组指针呢?

这个错误是,你不能将一个 int 类型的指针赋值给一个 int 类型的指针数组,这个很好理解,他们不是一个类型么,但是要怎么解决这个问题呢?之后我将 a 的地址赋值给这个数组指针问题得到了解决;

可是为什么呢?
这里要说一下数组名 a 和 &a 的区别,他们表示的意义实际上是不同的,a 表示的是数组首元素的地址,而 &a 是数组地址,虽然他们的值相同,但是当你对他们进行加一操作的时候 a 加一就是向后跳一个而 &a 加一就是跳过整个数组

仔细想想数组指针寻找元素的过程,我是不是进行了 *(*(q+1)+1) 这样的操作,而在上面我操作的时候使用的是 *((*p)+1) 大家看这两个操作,他们分别指向了第二行的第二个元素和第一行的第二个元素,这说明我对数组指针变量进行加减操作的时候改变的是他们的行数,那说明你在给他赋值的时候应该给一个能够每次跳一行的值,而不是每次跳一个的值,因而这里要使用 &a。
以上就是数组指针一维数组之间的联系,即数组指针加一向后移动一行 &a 加一也向后移动一行。

(2)上面我在将一维数组赋值给一个数组指针,有这样的思路主要是我在想一个一维数组和一个只有一行元素的二维数组有什么区别呢?
于是,有了下面的程序

问题还是出在这一行,这里错了当然就还是跟上面说的一样,你需要将 a 改为 &a,当然把 b 赋值给数组指针这句可以通过说明二维数组 b 就被处理成一个数组指针,可见虽然他们的分配的空间相同,方式也相同,但是实际上他们的数组名表示的意义是不相同的,a 表示的是数组首元素的地址,而 b 表示数组首地址。

为什么会有这样的差别呢?
我想是因为你在定义的时候,采用的方式不同,这里说一下我认为的中括号的意义;
一个就是你在定义数组的时候规定好他的长度;
再一个就是你可以通过中括号找到一个数组首地址往后 n 个(中括号里面的数)单位长度的数据;
这时可以想象二维数组 b[1][5] 寻找元素的过程,首先通过 b[0] 找到首行偏移零个单位长度的地址(这里的单位长度就指的是单行数组长度了,想象一个三行五列的二维数组,那 b[1] 是不是说的是第二行呢,这也验证了我们上面说的 b 表示的是数组首地址),然后再通过 b[0][3] 找到首元素偏移三个单位长度的元素最后输出。
这里的 b[0] 就是首元素地址了,下图作为参考:

当然,如果你真的想定义一个一维数组,你最好不要选择定义一个只有一行的二维数组,这样你的代码别人用起来可能就会出现问题,就像你再定义一个 int 类型的变量的时候你会选择定义一个只有一个元素的数组吗?不会,那这里就也不要这么操作!(本人只是思考里面的联系,并不提倡哦!)
以上就是一维数组和二维数组的联系,即一维数组和二维数组分配空间的方式一样,但是他们数组名的作用不一样。

(3)那二级指针和二维数组有什么联系呢?我们通常想的是,既然一维数组可以赋值给一个一维数组,那二维数组可不可以赋值给一个二维数组呢?但实际上这两个并没有什么联系

所以当你想要找到二维数组中的一个值时,你想的是先找到这个数据所在行0x4000,然后找到数据所在列,0x4004,然后将这个位置的数据取出来;

这一看,这不是二级指针吗,这不找了两次地址,但看看实际上的二维数组你会发现,这样子是不对的,上面说到数组 b[1] 实际上是指针向后跳 1 个数组长度,所以实际上不管你想要找到哪个位置的元素,都是首元素地址向后一直移动找到的,因此这里只能用一级指针来接收这个二维数组(三维、四维数组也可以用一级指针来接收,大家可以想一下这个过程)

(这里强制类型转换是因为上面说,数组名 b 实际上是一个数组指针,但思考二维数组的实际内存分配,发现我们可以进行这样的操作来寻找数组元素)

上图就可以看出来为什么不能用一个二级指针寻找数组元素了,5 这个地址到底指向了哪里你不知道,你有没有权访问呢?这也说明为什么你不能将一个数字当作地址赋值给一个指针的原因。
以上就是二维数组和二级指针的联系了,即真的没啥联系!(当然两个放到一起说可以帮助咱理解,但是不要混为一谈哦!)

三、指针函数(返回指针的函数)

这个就很简单啦,就是一个返回指针的函数,这个在学习到链表的时候应该会用到不少,我们可以选择返回一个链表的头指针或者指向头节点的指针,这里就不做过多的表述了,下面我给大家贴个例子大家可以康康。

这个temp就是一个头结点指针,init 函数就是一个返回指针的函数——指针函数。

四、函数指针(指向函数的指针)

首先要说一下函数,如果现在你定义了一个函数,那电脑就会自动为它分配一段空间,用来存放你的函数,既然分配了空间,那这个空间就有相应的地址,我们就可以用指针来存放这个地址,于是乎产生了函数指针。
函数指针由于他的特殊性,他的定义方式与其他指针有一定的不同,“int (*p)(int , int );”,需要你在定义这个指针的时候说明形参类型、个数,需要你在指针名外面加上括号(不然就成了一个指针函数了)。然后当我们定义了 一个函数之后,便可将这个函数首地址赋值给这个函数指针(形参类型和个数要一致),操作如下:

除了定义有些许不同,操作起来就可以当作一个函数来使用,当然,我们已经有一个max函数了,这样做岂不是多此一举呢?下面我列举几个函数之针的作用

1)函数指针可以提供封装性能。

当我们定义了一个这样的结构体之后,我们可以将一些功能封装到这个结构体里面,这样当我们在操作结构体的时候,我们就可以通过结构体来调用这些功能,这是不是就很方便呢?比如我们现在定义了两个结构体,一个是雇主结构体,另一个是雇员结构体,现在说明雇员和雇主所拥有的权限不同,那我们就可以在这两个结构体里封装不同的函数指针(总不能把函数封装到结构体里吧,那也太冗长了),这样是不是在创建了一个雇主的时候他拥有的功能就可以和雇员不相同了。

2)函数指针可以作为函数的参数。

这个作用可以让我么的程序变得更简洁,可读性更高,比方说现在有两个函数为函数 A 和函数 B ,他们都需要在执行完之后执行 C 操作,如果要把这三件事写成函数,大家可能会想,那函数写一个函数 C 然后在 C 中调用 A 函数,然后函数 B 和 C 再写一个函数不就行了吗?但是这不是无形中增加了你的代码长度吗,现在我们用函数指针作为函数 C 的参数,这样我们想用哪个的时候只需要将他传入函数就行了。

ps: 我在网上看到一个函数指针的好处,我觉得说的很棒,这里引用一下,供大家参考:使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。
函数指针程序练习的代码我放到下面的链接里,这里就不做过多赘述了,如果大家有兴趣可以康康:
https://blog.csdn.net/qq_55648035/article/details/122098588

五、拓展

说了那么多,指针到底是干什么的呢,实际上它使得我们放在不同区域的代码可以共享内存,并为我们构建复杂的数据结构提供了便利,实际生活中,我们需要用的数据不能每次用到就开辟空间去存储,而指针就为我们节省了空间,而且当我们需要复制较大的内存空间指针就显得很方便,我们只需要构建一个指针指向那片空间即可,这也提高了我们的代码性能,指针真的是看上去很简单,但是可以帮助我们完成很多很多的事情,为我们提供便利,这是一个奇妙的东西,个人还是对它有很大的兴趣的,希望能够跟大家一起探讨!

后记

首先我得感谢浙江大学的翁恺老师,能够写出这么多离不开他的网课,真真正正的对我起到了实质性的帮助,提高了我C语言的兴趣,非常有磁性的声音,真的能让我把他的课二刷甚至三刷,再还得感谢大学期间带过我编程的老师,他们为我悉心解答问题并耐心指导,为我的编程启蒙打下了很好的基础,我喜欢C语言,并把它当作的兴趣爱好来拓展,虽然以后可能用不上,但我会记得这些知识,记得我学习它们的时光!
以上内容仅代表我个人观点,如果哪里有不对的地方,还望大家不吝赐教!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/676750.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号