0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言中的指针解析

dyquk4xk2p3d 来源:码农的荒岛求生 2023-11-21 09:51 次阅读

大家好,有很多同学问能不能发下之前的文章,后续我会找一些之前阅读量不错的发下,本文首发于2021年12月,以下是正文。

假定给你一块非常小的内存,这块内存只有8字节,这里也没有高级语言,没有操作系统,你操作的数据单位是单个字节,你该怎样读写这块内存呢?

wKgZomVcDWWARKLQAACL_JnoXgg180.png

注意这里的限定,再读一遍,没有高级语言,没有操作系统,在这样的限制之下,你必须直面内存读写的本质

这个本质是什么呢?

本质是你需要意识到内存就是一个一个装有字节的小盒子,这些小盒子从0到N编好了序号。

这时如果你想计算1+2,那么你必须先把1和2分别放到两个小盒子中,假设我们使用Store指令,把数字1放到第6号小盒子,那么用指令表示就是这样:

store 1 6

注意看这条指令,这里出现了两个数字:1和6,虽然都是数字,但这两个数字的含义是不同的,一个代表数值,一个代表内存地址
与写对应的是读,假设我们使用load指令,就像这样:
load r1 6

现在依然有一个问题,这条指令到底是数字6写入r1寄存器还是把第6号小盒子中装的数字写入r1寄存器?
可以看到,数字在这里是有歧义的,它既可以表示数值也可以表示地址,为加以区分我们需要给数字添加一个标识,比如对于前面加上$符号的就表示数值,否则就是地址:
store $1 6
load r1 6
这样就不会有歧义了。
现在第6号内存中装入了数值1:

a2bb2bbe-880d-11ee-939d-92fbcf53809c.png


即地址6代表数字1:

地址6 -> 数字1

但“地址6”对人类来说太不友好了,人类更喜欢代号,也就是起名字,假设我们给“地址6”换一个名字,叫做a,a代表的就是地址6,a中存储的值就是1,用人类在代数中直观的表示就是:
a = 1

就这样所谓的变量一词诞生了。

a2e8e842-880d-11ee-939d-92fbcf53809c.png



我们可以看到,从表面上看变量a等价于数值1,但背后还隐藏着一个重要的信息那就是变量a代表的数字1存储在第6号内存地址上,即变量a或者说符号a背后的含义是:



表示数值1



该数值存储在第6号内存地址


到现在为止第2个信息好像不太重要,先不用管它。

既然有变量a,就会有变量b,如果有这样一个表示:

b = a

把a的值给到b,这个赋值在内存中该怎么表示呢?

很简单,我们为变量b也找一个小盒子,假设变量b放在第2号小盒子上:

a313f19a-880d-11ee-939d-92fbcf53809c.png




可以看到,我们完全copy了一份变量a的数据。
现在有了变量,接下来让我们升级一下,假设变量a不仅仅可以表示占用1个字节的数据,也可以表示占用任意多内存的数据,就像这样: a345399e-880d-11ee-939d-92fbcf53809c.png

现在变量a占据5个字节,足足占用了整个内存的一大半空间,此时如果我们依然想要表示b = a会怎样呢?

如果你依然采用copy 的方法会发现我们的内存空间已经不够用了,因为整个内存大小就8字节,采用copy的方法仅这两个变量代表的数据就将占据10字节。
怎么办呢?

不要忘了变量a背后可是有两个含义的,再让我们看一下:


表示数值1



该数值存储在第6号内存地址



重点看一下第2个含义,这个含义告诉我们什么呢?

它告诉我们不管一个变量占据多少内存空间,我们总可以通过它在内存中地址找到该数据,而内存地址仅仅就是一个数字,这个数字和该数据占用空间的大小无关。
啊哈,现在变量的第2个含义终于排上用场了,如果我们想用变量b也去指代变量a,干嘛非要直接copy一份数据呢?直接使用地址就不好了,就像这样:

a3737cdc-880d-11ee-939d-92fbcf53809c.png



变量a在内存中地址为3,因此变量b中我们可以仅仅存储3这个数字即可。
现在变量b就开始变得非常有趣了。

首先变量b没什么特殊的,只不过变量b存储的东西我们不可以按照数值来解释,而是必须按照地址来解释。

当一个变量不仅仅可以用来保存数值也可以保存内存地址时,指针诞生了。

有很多资料仅仅说指针就是地址,但小风哥认为这是一种偷懒的解释,仅仅停留在汇编层面来理解,有失偏颇,在高级语言中,指针首先是一个变量,只不过这个变量保存的恰好是地址而已,指针是内存地址的更高一级抽象

如果仅仅把指针理解为内存地址的话你就必须知道所谓的间接寻址。

这是什么意思呢?
如果使用汇编语言来加载变量a的值该怎么写呢?

load r1 1


想一想,这是不是会有问题,因此这样的话该指令会把数值3加载到r1寄存器中,然而我们想要把内存地址1中保存的数值也解释为内存地址,这时必须为1再次添加一个标识,比如@:
load r1 @1


这时该指令会首先把内存地址1中保存的值读取出来发现是3,然后再次把3按照内存地址进行解释,3指向的数据就是变了a:
地址1 -> 地址3 -> 数据a


这就是所谓的间接寻址,Indirect addressing,在汇编语言下你必须能意识到这一层间接寻址,因为在汇编语言中是没有变量这个概念的

然而高级语言则不同,这里有变量的概念,此时地址1代表变量b,但使用变量的一个好处就在于很多情况下我们只需要关心其第一个含义,也就是说我们只需要关心变量b中保存了地址3,而不需要关心变量b到底存储在哪里,这样使用变量b时我们就不需在大脑里想一圈间接寻址这一问题了,在程序员的大脑里变量b直接指向数据a:
b -> 数据a
再来对比一下:
地址1->地址3->数据a#汇编语言层面
变量b->数据a#高级语言层面


这就是为什么我说指针其实是内存地址的更高级抽象,这个抽象的目的就在于屏蔽间接寻址。

当变量不仅仅可以存值也可以存放地址时,一个全新的时代到来了:看似松散的内存在内部竟然可以通过指针组织起来,同时这也让程序直接处理复杂的数据结构成为可能,比如就像下图这样:

a3b43614-880d-11ee-939d-92fbcf53809c.png



这就是所谓的链表了。

a3ef099c-880d-11ee-939d-92fbcf53809c.png



指针这个概念首次出现在 PL/I 语言中,当时是为了增加链表处理能力,大家不要以为链表这种数据结构是非常司空见惯的,这在1964年左右并不是一件容易的事情,关于链表你还可以参考这篇《彻底理解链表》。

值得一提的是,Multics操作系统就是 PL/I 语言实现的,这也是第一个用高级语言实现的操作系统,然而Multics操作系统在商业上并不成功,参与该项目的Ken Thompson, Dennis Ritchie后来决定自己写一个更简单的,Unix以及C语言诞生了,或许是在开发Multic时见识到了PL/I语言中指针的威力,C语言中也有指针的概念。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5056

    文章

    18960

    浏览量

    301743
  • C语言
    +关注

    关注

    180

    文章

    7591

    浏览量

    135773
  • 函数
    +关注

    关注

    3

    文章

    4276

    浏览量

    62311
  • 指针
    +关注

    关注

    1

    文章

    478

    浏览量

    70489

原文标题:彻底理解C语言中的指针

文章出处:【微信号:良许Linux,微信公众号:良许Linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言中指针的定义

    上一节中,我们利用了一个小知识来介绍了一下指针,在上面这个例子中,小明和小丽手中的这个杯子就好比我们C语言中的变量,它确实是实实在在存放一些有具体意义的数据。这个杯套就类似于C
    发表于 08-15 16:24 1785次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言中指针</b>的定义

    C语言中void指针的基本认识及典型应用

    C语言中,*类型就是指针类型,比如 int *p,double *q,虽然是不一样的指针,但是大小却一样sizeof(p) == sizeof(q),因为它们都是同一种类型*类型的。
    发表于 02-01 09:26 1042次阅读

    C语言中指针函数和函数指针的概念及应用示例

    C语言中指针函数和函数指针是强大且常用的工具。它们允许我们以更灵活的方式处理函数和数据,进而扩展程序的功能。
    发表于 08-16 16:14 683次阅读

    C语言中多级指针的概念和使用方法

    多级指针C语言中是一种特殊的指针类型,它可以指向其他指针指针
    发表于 08-16 16:16 935次阅读

    C语言中指针和野指针的概念及产生原因

    C语言中指针是一种非常强大和灵活的工具,但同时也容易引发一些问题,其中包括空指针和野指针
    发表于 08-16 16:18 1198次阅读

    C语言中指针的基本概念和用法

    C语言中指针是一项重要的概念,它允许我们直接访问和操作内存地址。
    发表于 08-17 15:30 693次阅读

    C语言中指针是什么?如何规避野指针

    C语言中指针是什么?有哪几种类型?指针有何作用?如何规避野指针
    发表于 02-25 06:47

    C语言中指针的介绍非常详细

    C语言中指针的介绍非常详细 C语言中指针的介绍非常详细
    发表于 12-25 10:39 57次下载

    基于C语言中指针的基本用法解析

    C语言中其它的知识都学得可以,唯独指针搞不懂。如果是这样,我可以很负责的告诉你,对于这门编程语言,你等于是没学。所以学好指针对于初学者是非
    的头像 发表于 01-09 15:12 4759次阅读

    C语言中的野指针是怎么来的?

    )、malloc函数申请堆内存返回的地址(但未使用free释放,是在堆空间动态申请) 需要注意的是,野指针不是NULL指针,通常NULL指针可以使用if语句来判断,但是C
    的头像 发表于 06-01 16:43 2512次阅读

    C语言中指针(重点)超详细

    C语言中指针1、指针是什么2、指针指针类型2.1、指针
    发表于 01-13 14:10 11次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言中</b>的<b class='flag-5'>指针</b>(重点)超详细

    C语言中的char数组和char指针有什么区别?

    让我们通过下面的例子,来了解 C语言中字符数组和字符指针之间的区别。
    的头像 发表于 01-29 16:35 2589次阅读

    底层解析C指针(一)

    指针C语言中的精髓部分,同样也是C语言的难点所在,下面从最底层来分析C
    的头像 发表于 02-15 14:47 853次阅读
    底层<b class='flag-5'>解析</b><b class='flag-5'>C</b><b class='flag-5'>指针</b>(一)

    C语言中什么是指针数组

    C语言中一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个
    的头像 发表于 03-10 15:26 1624次阅读

    简述C语言中指针重点

    C语言中一个函数可以返回一个整型值、字符值、实型值等,也可以返回指针型的数据,即地址,其概念与以前类似,只是返回的值的类型是指针类型。
    的头像 发表于 03-10 15:28 564次阅读