0

0

深入理解并打败C语言难关之一————指针(1)

蓮花仙者

蓮花仙者

发布时间:2025-04-26 14:42:34

|

313人浏览过

|

来源于php中文网

原创

前言:

已经好久没有写文章,最近的生活比较忙,我到现在为止已经学完了C语言的大部分内容了,所以我决定每天出一篇文章来复习我学过的知识,今天先来讲指针的相关知识,行了我也不多废话了,现在开始进入正文

深入理解并打败C语言难关之一————指针(1)

正文:

1.内存与地址

1.1内存

立即学习C语言免费学习笔记(深入)”;

 我们可以引入一个案例来解释一下内存是什么:假如你有一个朋友叫做小明,有一天你住进了一个酒店,你想要邀请小明来酒店来找你玩耍,如果你不告诉小明你的房牌号的话,他只能从一楼开始一个房间一个房间的来找你,这样会显的很麻烦,如果你直接告诉他你的门牌号的话,他会直接找到你人在哪里。我们把这个故事的内容类比到计算机当中去,这个酒店我们称之为一个内存,酒店里有很多的房间,我们把一个房间称之为一个内存单元,每一个内粗单元都有一个相对应的编号,我们把内存单元的编号称之为地址,地址也叫做指针,所以,内存单元的编号 == 地址 == 指针,所以这就是指针的实际意义,他就是一个地址。

1.2.如何理解编址(这部分内容其实我也不太明白,所以我从网上找点资料来进行完善了)

深入理解并打败C语言难关之一————指针(1)

  将这个之前我先从这放一张图来更好的理解编址,CPU访问内存的某个字节空间的时候,必须要知道这个字节空间在内存的什么位置,并且因为内存中字节很多,所以需要给内存进行址(就比如酒店的房间很多,需要给房间编号一样),计算机中的编址,并不是把每一个字节的地址记录下来,而是通过硬件设计完成的。钢琴,吉他上面没有写到“剁、来、咪、发、唆、拉、西”这样的信息,但演奏者照常能够精确知道。本质上是一种约定出来的共识

⾸先,必须理解,计算机内是有很多的硬件单 元,而硬件单元是要互相协同⼯作的。所谓的协 同,至少相互之间要能够进行数据传递。但是硬件与硬件之间是互相独⽴的,那么如何通信呢?答案很简单,用"线"连起来。不过,我们这节课关心的线是地址总线:硬件编址也是如此 我们可以简单理解,32位机器有32根地址总线, 每根线只有两态,表示0,1【电脉冲有⽆】,那么 ⼀根线,就能表示2种含义,2根线就能表⽰4种含 义,依次类推。32根地址线,就能表⽰2^32种含义,每⼀种含义都代表⼀个地址。 地址信息被下达给内存,在内存上,就可以找到 该地址对应的数据,将数据在通过数据总线传传入 CPU内寄存器。

2.指针变量和地址以及指针变量类型的意义

2.1取地址操作符(&)

  对于如何知道内存,取地址操作符可以找到变量什么的所在的地址,下面直接进行演示,对于取到地址的演示  (对了地址的占位符是%p)

代码语言:javascript代码运行次数:0运行复制
#includeint main(){   int a = 12;   printf("%p",&a);   //注意地址的占位符是%p   return 0}
深入理解并打败C语言难关之一————指针(1)

  其实我们每次申请变量的时候就申请了一部分的内存空间,通过前面的了解可以知道 ,每个内存单元都有着编号,所以变量是有地址的,并且因为int是有四个字节空间的,所以每个字节空间对应着一个地址,而取出来的地址其实是最小的地址,不过我们已经知道最小的地址了,顺藤摸瓜就可以找到其余字节的地址了。

2.2指针变量和解引用操作符(*)

  2.2.1指针变量

  通过取地址操作符可以取到任意变量的地址,这些地址是需要存储起来的从而为了后期的使用,我们在初始化一个变量时,会把一个数存在这个变量里,由此可以类推,我们可以把存放指针的变量称之为指针变量,下面是如何进行创建:

代码语言:javascript代码运行次数:0运行复制
#includeint main(){    int a = 12;    int *p = &a;   //这就是指针变量如何进行创建}

对于指针变量,我们可以这样进行理解:以上面的式子举例,p是指针变量的名字,*指的是定义的是指针变量,int指的是地址所对应的类型,这个要记住,以后会有着很多指针类型等着我们去记。

2.2.2解引用操作符(*)

可能很多人会有疑问,我们把一个变量取出地址了并且放在了指针变量里面了,我们未来想要使用这个数的时候要怎么用呢,其实,在C语言中,我们是可以通过地址来改变变量的数的,具体的用法我写在了下面,毕竟取出了地址啥也不可以干那还不如不多废这功夫 

代码语言:javascript代码运行次数:0运行复制
#includeint main(){    int a = 12;    int * p = &a;    *p = 13;    return 0;}

  这样可以把a数值里面的值进行改正 ,* 变量名  =  你想要的值,这就是如何进行解引用操作,可能很多人会想,如果想要把变量的值进行改变,直接 a = 13 不就好了,理论上这么干是没有问题的,但是我们在这可以比喻一下子,我相信各位都接触过《狂飙》这一部胡=剧,在这里面,高启强每一次想杀人的时候都不是靠自己出手,我们可以把它比做成变量,他一般会对老默说:老默,我想吃鱼了,把这种肮脏活交给老莫去做,我们在这里可以把老莫比做成指针变量,很多事情不用老大(变量)去干,让小弟(指针变量)操作就好了。

2.3指针变量的大小

可能会多人会想指针变量的大小会和变量大小是相关联的,对于所以我们先卖个关子,先展示对各个变量地址的打印

深入理解并打败C语言难关之一————指针(1)
深入理解并打败C语言难关之一————指针(1)

  不难看出,这几个变量的地址居然是一样的,很多人对此疑惑了,为什么地址大小是一摸一样的,我也不卖关子了,我直接告诉原因,指针变量的地址和所在的运行环境有关,就比如我这个是x64的运行环境,所以有64个比特位,换算下来刚好是8个字节的长度,所以一共占8个字节,对于原因我也不解释了(这个其实是我直接记下来的,与上面的编址有关)。

2.4.指针的类型

指针有很多的类型,他的类型和对于的常量是息息相关的,比如上面的int * ,除了这个,还有char * , float * , double *等等,这一些都是根据所对应地址的类型所决定的

Adrenaline
Adrenaline

软件调试助手,识别和修复代码中错误

下载

2.5.void*指针

这个指针在后期会有重大的作用,在指针类型中有⼀种特殊的类型是 void * 类型的,可以理解为⽆具体类型的指针(或者叫泛型指 针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+-整数和解引用的运算。对于它,后面模拟某类函数的时候会出现的

3.const来修饰指针

3.1const修饰常量

我直接明了了,被const修饰的常量,是不能在改变它的数值的,对于例子,可以看见下面的例子, 

深入理解并打败C语言难关之一————指针(1)

  这个红线代表着,a是不可以被修改的,因为它已经被const修饰,const是代表着语法进行了限制,简单来说就是不可以被修改,不过我们可以绕过它来进行修改,这时候指针的功能就来了,如下图所示

深入理解并打败C语言难关之一————指针(1)

  就拿我上面《狂飙》的例子一样,大哥不好动手,那么小弟动手就好了,这样的会造成一定的风险,就比如我们就是不想让变量的内容改变,但是这么做的话就会有风险,所以我们更是要对指针进行const的处理,那么现在进入下一节:

3.2.const修饰指针

3.2.1const在(类型)* 的左侧

对于指针使用const要分成两种情况进行讨论,先来讲述下左侧的情况,不废话直接说功能:const在(类型)*的左侧的话,会让解引用指针变量的时候,不能在解引用了(这是用大白话来讲),如果采用官方话来说:const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变,通过这一段的介绍可以看出,const在左边可以阻止改变内容去,但不能组织地址的改变,下面将会讲述如何限制地址的改变

3.2.2const在(类型) * 的右侧

const在(类型) * 的右侧的话,会让其在改变所指向地址的时候,无法进行改变(这是通过大白话进行讲述),如果用严肃的口气说的话:const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。所以从这里就可以看出二者的不同,所以如果合理使用const的话,可以避免很多意外情况的诞生

4.指针进行的运算

4.1 指针+-整数

这一个可以通过数组的案例进行解释,因为数组在内存中是连续存放的,所以只要知道一个元素的地址,就可以找到后面的,不过再说这个之前,先来讲一下这个的逻辑,对于指针+-整数,其实说白了就是类似+1的时候会多加一个类型(此类型指的是指针的类型)的地址,就比如int * 如果+1的话,会多加4个字节的地址,类似这样,下面我们直接进入对于数组如何通过地址打印对应元素:

深入理解并打败C语言难关之一————指针(1)
深入理解并打败C语言难关之一————指针(1)

  通过控制台的数据可以看出二者是完全一样的,对于上面式子的解释,可以这么认为 ,在上面的式子,p代表着数组第一个元素的地址(小小的剧透下,数组名也是数组中第一个元素的地址),在printf的引用中,p + i代表着arr[i]所在的地址,解引用后便就是arr[i]这个具体的数了,所以可以通过这个特性来对于数组进行打印(当然不能仅仅这么肤浅这个用法),对于更高级的请关注我后续的文章(不是我卖关子,很多内容后期学完了才可以听懂)

4.2指减指针

指针减指针的结果是指针与指针之间元素的个数,当然,这个计算是由前提的,它的前提是两个指针指向的是同一个空间,不然二者就没意义了,下面来展示它的用法,这里可以采用对于srlen函数的模拟来实现,我们知道,strlen函数统计的是\0之前的字符个数,通过它可以看出指针减指针的妙用:

深入理解并打败C语言难关之一————指针(1)
深入理解并打败C语言难关之一————指针(1)

  可以看出两者的数值是一样的,从这里可以看出指针减去指针的时候记录的数是两个指针相差的元素个数,因为p代表指针最后所在的位置,它减去刚开始的位置代表着二者相差的字节个数,所以从这里可以看出指针-指针带来的效果,以后这个也会多讲,对于很多函数的模拟会用到这个。

4.3指针之间的运算关系

他们之间的大小关系会是通过地址的大小来确定的,把它类比成变量之间比大小就好,指针和指针之间的运算关系和这个是一样的,可以通过例子来看看怎么比较(这部分没啥好讲的)

代码语言:javascript代码运行次数:0运行复制
#include int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int *p = &arr[0]; int sz = sizeof(arr)/sizeof(arr[0]); while(p

结尾:

今天本来想着写很多大,但是今天2晚上聚餐导致脑子有点昏,所以这篇文章就先写到这里了,预告一下,下一篇 将会讲到野指针,assert断言等重要知识,如果文章出现了错误,恳请您在评论区指出,希望大家多多点赞,我们下一篇见!                                                         

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

400

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

619

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

354

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

259

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

603

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

527

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

645

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

602

2023.09.22

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

58

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.8万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

Excel 教程
Excel 教程

共162课时 | 13.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号