电子发烧友App

硬声App

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

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

3天内不再提示
电子发烧友网>电子资料下载>C语言|源代码>C语言的精髓——指针详解

C语言的精髓——指针详解

2017-11-30 | docx | 17KB | 次下载 | 1积分

资料介绍

  C语言的精髓——指针详解

  朱有鹏

  1.2、指针变量的类型作用

  对于普通变量的来说,其类型的作用主要有这么几个方面:

  (1)程序员写代码时识别用:不涉及强制转换时,知道该变量中应该存放什么类型的数值。

  (2)空间大小的说明:比如int为4个字节空间

  (3)存储结构说明:float和int虽然空间大小都是4字节,但是其存储结构完全不同

  对于指针变量来说,其类型的作用与上面基本一致,只是其类型是由普通类型+*构成,*个数表明了指针变量的级数,指针变量用来存放地址。当不涉及强制转换时,其对应关系为:

  某类型一级指针变量 = 该类型一级地址

  某类型二级指针变量 = &(该类型一级指针变量)

  n+1级指针变量 = &(n级指针变量)

  所有普通变量的地址都是一级地址,所有一级指针变量的地址都是二级地址,类推n级指针变量的地址就是n+1级地址,但是我们这里必须强调一下,使用指针的目的就是为了更加方便的访问空间,但是如果级数超过3级以上,实际上不但降低了程序的可读性,也会降低对空间的访问速度,所以过高级数的指针变量没有太大的意义。

  Int *p = &a;

  p中只存放了a首字节地址,但是int说明了*p希望访问的空间有4个字节,所以从p所指a的第一个字节向后数3个字节空间,一共4个字节空间才是*p的实际希望访问到的完整空间。

  1.3、为什么需要指针

  不管多么高大上的程序,最终都是运行在硬件上的,所有对于硬件的设置和访问,全部都是通过对内存操作实现的,广义上的内存可以包括,寄存器、缓存、常说的内存等,这些内存空间都是由一个个的字节构成的,每个字节都有地址,对于这些空间的访问,大多都是通过地址实现的。

  如果就站在c自身的角度,也可以看到指针的好处,举个例子的话,比如fun1函数有一个自动局部变量a,他的作用域被局限在了fun1函数内部,fun2函数是无法访问的,如果fun2想要访问fun1中a的话,我们可以将a的地址传递给fun2函数,当然前提是fun1的a没有被自动释放。

  对于c语言有了解的都知道,函数也是有作用域的,跨文件的作用域又称为链接域,为了防止本文件的函数(比如名叫fun的函数)不被其它文件的同名函数干扰,同时也希望不去干扰别人,我们往往会在fun函数的前面加一个static标志,将其作用域固定为本文件,其它文件通过fun函数名是无法访问的。但是如果其它文件的function函数,又确实希望访问这个函数时,怎么办呢?我们只需要将fun函数的地址传递给function函数,就可以跨文件访问fun函数,并且不会受到static的影响。

  所以在c语言中,地址还是扩大变量或者函数作用范围的有效手段,当然指针好处很多,这里不再赘述。

  1.4、高级语言如javac#的指针到哪里去了

  C++就不说了,里面保留了指针的使用,初学java,c#等高级语言的同学,都会因为里面没有指针而困惑,甚至在想,难道这些高级语言就不需要访问内存空间了吗?凡是有过java异常处理的同学,都会发现java中有一种空指针异常,大多是因为我们使用了没有实例化的对象名导致的,因为没有实例化就没有分配内存空间。

  既然有空指针异常,就证明java是使用了指针的,只是全部都由类的底层封装好了,不需要我们关心,目的就是为了省去指针这一难点,使得java简单实用,但是由于不能直接操作指针,面对频繁使用指针的底层开发而言,java和c#多少会显得有心无力。

  1.5、指针使用值三部曲

  (1)定义(声明)

  例: int *p=NULL; //初始化一下,防止野指针

  (2)关联

  例: int a= 10;

  p = &a;//a空间的首地址给了p,所以p里面的地址常量指向了a空间,因此简称p-》a空间

  (3)引用

  (a)读空间:读值操作,前提是里面存有数据才行

  例:int b = *p;//等价于 b = a;

  (b)写空间:向空间写入新的值

  例: int *p = 30;//等价于a = 30;

  2、指针涉及到的一些符号的理解

  2.1、*的理解

  在c语言中,*的用途有两个,一个是用于表示乘号,第二个与指针有关,虽然这两种用途用都会用到*,但这两者没有任何关系。*在指针中的用途主要有两个方面,第一种是用在指针定义的时候,与前面的类型结合,用于表示被定义指针变量的类型,*个数表明了定义的指针变量的级数,例如:

  int *p;int* p;

  *靠前靠后都没关系,这时的*与p是两个不同的东西,星号表明p是一个一级指针变量,用于存放一个一级地址。但是需要注意下面的情况:

  int *p1,*p2;//p1和p2都是int型的一级指针变量。

  int *p1,p2;//p1是int型的一级指针变量,p2只是一个普通的int型变量。

  第二种就是解引用,解引用时,*p表示的就是p所指向的空间,这时的*也称为取空间操作,找到p所指向的空间,必须强调的是,这时的*p是一个整体,不能割裂来看,比如:

  int *p = &a;

  *p = 10;//等价于a=10;但是写成* p = 10;就不对了

  *作为解引用时(也就是取空间操作时),得到p所指向的空间后,我们的用途有两种,一个是读空间内容,还 有就是向空间写入新的内容。

  2.2、取地址符&的理解

  取地址符使用时,直接写在变量名称的前面,然后&和变量一起构成了一个新的符号,表示变量空间的首地址,准确讲是变量的首字节地址。比如int a;int *p = &a;这里必须注意,&a是一个完整的不可分割的整体,之所以用这种方式来表示空间的地址,是因为我们没有办法直接得到变量a的地址,只能是使用&a来表示,当编译时会将&a变成a空间的地址赋值给p;

  2.3、指针变量的初始化和指针变量赋值之间的区别

  首先必须强调,指针变量的初始化与普通变量的初始化没有任何区别,只是指针变量里面的存放的是一个特殊的值“地址”,这个值具有指向作用,可以用来访问它所指向的空间,如果你刨去它地址的含义,实际上变量中存放的不过就是一个普通值。

  (1)指针变量的初始化

  Int a=10;

  Int *p=&a;

  此时的*,只是说明p是一个一级指针变量,不能把这时的*当成了解引用。

  (2)指针变量的赋值

  Int a=10;

  Int *p=NULL;

  p=&a;//将a空间地址的赋值给p

  不少同学可能一直觉得p=&a,应该写成*p=&a;这是错误的理解,这时的*是取空间操作,如果写成*p=&a,就表示将a的空间地址存放到p所指向的空间,p所指向的空间其实就是a,*p=&a的等价写法就是a=&a;相当于把地址给了a自己,显然是不对的。

  (3)初始化和赋值注意点

  从形式上看,我们已经知道了初始化和赋值的区别,同时要知道初始化只能有一次,但是赋值可以有多次。

  2.4、左值与右值

  (1)什么是左值和右值

  比如:int a=10;等式的左边称为左值,右边称为右值。

  (2)左值

  在c语言中,左值指的都是变量空间。对左值执行的操作都是写空间操作。

  (3)右值

  在c中,右值有两种形态,一种是直接写一个数值,比如int a=10;就是典型的这种情况。那么另外的一种情况就是,右值可能也是一个变量,比如int b=10; int a=b;这个时候右值就是一个变量。当变量作为左值是,对变量实现的是写操作,如果变量作为右值时,对变量实现的是读操作,读出后赋给右值,这一点要了解。

  2.5、定义指针后,需要会关心的一些内容

  (1)例子1

  Int a =10;

  Int *p=&a;

  合理我们必须了解与指针变量p相关的一些内容。

  p:表示int*型的一级指针变量空间,里面存放的是变量a的地址。

  *p:表示p所指向的空间,指的就是a的空间,只不过是通过地址找到的。

  &p:表示指针变量p自己的空间地址,它需要是int **的二级指针变量来存放。

  思考一下,**p=20可不可以?

  回答:不可以,**p改写成等价形式*(*p),里面的*p等价于a,最后变成了*a,由于a的值等于10,*a就是*10,引用地址10所指向的空间,显然10这个地址指向的空间是不存在的,所以错误。

  (2)例子2:

  Int a =10;

  Int *p=&a;

  Int **p1=&p;

  对于指针变量p,需要关心p、*p、&p,但是在上例中已经描述过了,不再赘述。

  对于指针变量p1来说,需要如下几个方面的问题:

  p1:一个int **型的二级指针变量空间,用于存放一个二级地址,恰好*p的地址就是二级地址。

  *p1:引用取空间操作,找到p1所指向的空间,指的就是p的空间。

  **p1:将其中的*p1替换成为p,**p1就变成了*p,指的就是a的空间。

  &p1:指的是二级指针变量p1的空间地址,是一个三级地址。

  只要大家理解前面的例子1和例子2,对于三级指针的情况,道理是类似的,但是我们前面就说过,构建三级以上的指针实际上没有太大的意义,除了某些极少数的情况外,并不会为我们的程序带来多少好处。

  思考一下:***p1可不可以?

  答:不可以,根据取空间操作,***p1最终变成了*10,显然也是错误的。

  (3)多级指针链断线的问题

  Int a =10;

  Int *p;

  Int **p1=&p;

  Int b=**p1;

  **p1,原是想通过**p1访问到a的空间,将a空间的内容赋给b,但是这里是不对的,因为中间的指针变量p并没有指向a,指针链断线了,所以我们在使用多级指针的时候,必须注意构建的指针链是否完整。当然这里因为是直接写的比较好理解,如果多级指针链是通过传参的方式来构建的话,很容易出现断链的情况,造成的影响就是,要么访问到是空指针,要么访问到了不该访问的地方,导致严重错误。

下载该资料的人也在下载 下载该资料的人还在阅读
更多 >

评论

查看更多

下载排行

本周

  1. 1储能电源市场分析
  2. 7.99 MB  |  6次下载  |  免费
  3. 2储能电源市场分析报告
  4. 2.61 MB   |  6次下载  |  免费
  5. 3具有DCS-Control™ 功能的 3V 到 17V 0.5A 降压转换器TPS6217x-Q1数据表
  6. 3.17MB   |  1次下载  |  免费
  7. 4磁环电感定制时应该注意什么
  8. 0.32 MB   |  1次下载  |  免费
  9. 5高效降压转换器 MicroSiP™模块TPS82084 (2-A)/TPS82085 (3-A)数据表
  10. 1.75MB   |  次下载  |  免费
  11. 6采用DSBGA封装的LMR24210 42V 输入电压、2A 降压稳压器数据表
  12. 1.82MB   |  次下载  |  免费
  13. 7采用增强型Hotrod™ QFN封装的TPSM560R6 60V输入、1V至6V输出、600mA 电源模块 数据表
  14. 2.06MB   |  次下载  |  免费
  15. 8具有外部参考输入的低引脚数、低VIN(3.0伏至5.5伏)同步降压DC-TO-DC控制器数据表
  16. 1.18MB   |  次下载  |  免费

本月

  1. 1ES9038PRO解码芯片的电路原理图介绍
  2. 0.25 MB   |  35次下载  |  5 积分
  3. 2UHD智能显示SoC VS680产品简介
  4. 0.46 MB   |  11次下载  |  免费
  5. 3STM32国内外发展现状
  6. 1.15 MB   |  11次下载  |  免费
  7. 4ATmega8芯片中文手册
  8. 2.45 MB   |  8次下载  |  1 积分
  9. 5TDK电容器产品指南
  10. 11.88 MB   |  7次下载  |  1 积分
  11. 616A 输出电流,高可靠、高效率 同步降压转换器PCD3201产品手册
  12. 0.47 MB   |  6次下载  |  免费
  13. 7传感芯片选型指南
  14. 3.60 MB   |  6次下载  |  免费
  15. 8储能电源市场分析
  16. 7.99 MB  |  6次下载  |  免费

总榜

  1. 1matlab软件下载入口
  2. 未知  |  935086次下载  |  免费
  3. 2开源硬件-PMP21529.1-4 开关降压/升压双向直流/直流转换器 PCB layout 设计
  4. 1.48MB  |  420050次下载  |  免费
  5. 3Altium DXP2002下载入口
  6. 未知  |  233068次下载  |  免费
  7. 4电路仿真软件multisim 10.0免费下载
  8. 340992  |  191316次下载  |  免费
  9. 5十天学会AVR单片机与C语言视频教程 下载
  10. 158M  |  183316次下载  |  免费
  11. 6labview8.5下载
  12. 未知  |  81567次下载  |  免费
  13. 7Keil工具MDK-Arm免费下载
  14. 0.02 MB  |  73786次下载  |  免费
  15. 8NI LabVIEW中实现3D视觉的工具和技术
  16. 未知  |  70088次下载  |  免费