文档章节

解读 C 语言中的指针

数通畅联
 数通畅联
发布于 2016/07/21 16:04
字数 2011
阅读 27
收藏 7

我想对很多学习C语言的新手来说,指针无疑是一个难点。但是,我觉得指针也是C语言特别重要的一个特性。也许,你在除了C和C++以外的编程语言中,很少看到指针。而C++中,也多用引用,而非指针。指针,作为一种高效的工具,可谓是一把双刃剑——用得好,可以大大提高程序效率,但用的不好,就是很多bug的滋生地。

这或许也是人们对指针褒贬不一的原因吧。就我个人而言,我还是很喜欢这个特性,因为我需要经常和硬件以及一些底层的软件打交道。这个时候,指针便体现出它独特的魅力。指针的知识很多,有一本经典的书叫《C和指针》,如果有兴趣可以读一读。这里,我主要总结一些如何去解读指针(说实话这个东西实在是很容易让人困惑)的方法,一方面给自己做查询用,另一方面,希望可以给别人一些帮助。

一,基本概念

关于指针的基本概念,我就不详细介绍了,因为有许多书都介绍的很详细。这里我只介绍一部分。指针指向一个地址,而指针本身在大多数系统上都是一个无符号整数(在32bit机上是4byte,在64bit机上是8byte)。下面用一个例子来说明其机制:

在上面的例子中,先定义了一个指针p,它的类型是int,也就是说它只能指向一个int型的变量,而不能指向其他类型的变量。最后我们将a变量的地址赋给p。在这个过程中,涉及到两个内存块,一个是存放指针p的内存(用&p可得到内存地址),一个是存放a的值的内存块(用&a可以得到内存地址)。而第一个内存存的p的值经过赋值语句后也就是&a的值了。另外一个注意点是, *(星号)和变量类型以及变量名之间可以有任意个空格,也可以没有。比如下面三种方式都是一样的:

在上面的例子中,先定义了一个指针p,它的类型是int,也就是说它只能指向一个int型的变量,而不能指向其他类型的变量。最后我们将a变量的地址赋给p。在这个过程中,涉及到两个内存块,一个是存放指针p的内存(用&p可得到内存地址),一个是存放a的值的内存块(用&a可以得到内存地址)。而第一个内存存的p的值经过赋值语句后也就是&a的值了。另外一个注意点是, *(星号)和变量类型以及变量名之间可以有任意个空格,也可以没有。比如下面三种方式都是一样的:

解读方法:

看下面一个例子:

二,数组首地址a,&a,&a[0]

注:a,&a,&a[0]的含义虽然不同,但是他们三个的值是相等的!

以int a[3]为例说明:

  1. a作为右值时,代表数组首元素的首地址,而非数组地址。 也就是a[0]的地址。int i = (a+1),这里a是右值,所以代表首元素的首地址,a+1代表下一个元素的首地址,即&a[1]。

  2. a是整个数组的名字。所以sizeof(a)的值为sizeof(int) * 3 = 40,代表整个数组的大小。

  3. &a即为取a的首地址,也即整个数组的首地址。所以sizeof(&a) = 4。 int p = (int)(&a+1)中的&a+1代表下一个数组的首地址,显然是越界的。

  4. &a[0]代表首元素的首地址。 所以sizeof(&a[0]) = 4。

  5. &a[3],很显然数组越界了,但它的sizeof是多少呢? 也是4,因为关键字sizeof求值是在编译的时候,虽然并不存在a[3]这个元素,但是这里并没有真正访问a[3],而是根据数组元素类型来确定其值的。所以sizeof(a[3])不会出错。

  6. a[-1]代表什么意思?首先要明白下标的形式被编译器解析成指针的形式,即a[1]被解析成(a+1)。那么,a[-1]被解析成*(a-1)。

关于数组首元素的首地址和数组的首地址的区别:其实,数组首元素的首地址和数组首地址的值是相同的,即&a[0]和a(以及&a)是相等的,但是而这含义不一样。首元素的首地址加1后,是第二个元素的首地址(之所以一直说首地址,是因为有的类型存储时会占多个地址),但数组的首地址加1后是“下一个数组的地址”,这里的下一个数组只是为了说明加1时加了整个数组的大小,而不是一个元素的大小。

有一点比较容易混淆:a虽然代表整个数组,但(a+1)却代表下一个元素的首地址,即和(&a[0]+1)一样,下一个数组的形式为:(&a+1)。 下面以一个程序来说明:

输出结果:

说明(下面的行数只计算main函数内有代码的行):

  1. 程序第1行定义了一个具有3个元素的整型数组。

  2. 第2行打印了long型的大小。因为我是64bit的,所以一个long是8byte。

  3. 第3行打印了*(a+1)的值,结果和a[1]的值相等。说明a虽然代表整个数组,但作为右值时,的确代表首元素的首地址。

  4. 第4行输出值为12,是整个数组的大小。

  5. 第5行打印了一个出界元素的大小,没有报错,验证了上面第5条。

  6. 第6行打印了a[-1]和*(a-1),输出值相等。验证了上面第6条。

  7. 第7行打印了a和&a[0],值相等。说明数组的首地址和首元素的首地址是相等的。

  8. 第8行打印了a,(a+1),(&a+1),由结果就可以看出首元素的首地址加1是加了一个数组元素的大小,而数组首地址加1是加了一个数组的大小。

三,指针数组和数组指针

指针数组: 首先它是一个数组,数组的元素是指针,也成为“存储指针的数组”。

数组指针: 首先它是一个指针,它指向一个数组,也可以理解为“数组的指针”。 也可以利用前面的“解读方法”去分析。

四,函数指针和指针函数

函数指针: 指向函数的指针变量。

指针函数: 带指针的函数,也就是返回指针的函数。

五,指针常量和常量指针

怎么记?

  1. 可以先把类型名去掉,然后看const离谁近,就修饰谁。

  2. 也可以const在*左边的为常量指针,const在*右边的为指针常量。

三~五的万能钥匙

其实,关于“指针数组与数组指针、函数指针与指针函数、指针常量与常量指针”的判断,有一个万能钥匙。那就是根据我们强大的中文语法:前边是修饰词,后边才是主语。比如“指针数组”,前面的指针只是修饰词,后面的数组才是主语,所以它是一个数组。

六,野指针

野指针指没有确定指向的指针。造成野指针的情况有:

1. 指针变量创建但没有初始化。

2. 指针p被free或者delete之后,没有置为NULL。

版权声明:感谢原作者的辛苦创作,来源:伯乐在线专栏作者 -时间轨迹,链接:http://blog.jobbole.com/102052/。

本文转载自:http://blog.jobbole.com/102052/

数通畅联
粉丝 91
博文 203
码字总数 195353
作品 6
沈阳
架构师
私信 提问
指针——C语言的灵魂

为什么说C指针是C语言的灵魂? 来自读者对C和指针的解说 他可以直接访问硬件,这是灵活性和效率的体现,程序离硬件越近自然效率越高,当然运用不当也可导致效率低下 难掌握及太危险,如果对指...

生气的散人
2013/03/25
1K
5
【《征服C指针》作者语录】独家公布

内容简介: 本书被称为日本最有营养的C参考书。作者是日本著名的“毒舌程序员”,其言辞犀利,观点鲜明,往往能让读者迅速领悟要领。 书中结合了作者多年的编程经验和感悟,从C语言指针的概念...

生气的散人
2013/02/01
423
0
Go1.6 和 Go语言圣经中文版 正式发布!

Go1.6 和 Go语言圣经中文版 正式发布! Go1.6正式版本发布。在 https://golang.org/doc/go1.6 可以预览Go1.6的发布信息。自Go1.5发布以来的重大变化有以下几个: 《Go语言圣经》 面世标志着G...

chai2010
2016/01/27
10K
18
iOS 编写高质量Objective-C代码(二)

《编写高质量OC代码》已经顺利完成一二三四篇! 附上链接: iOS 编写高质量Objective-C代码(一) iOS 编写高质量Objective-C代码(二) iOS 编写高质量Objective-C代码(三) iOS 编写高质量...

MrLiuQ
2018/08/13
0
0
链表的由来和指针的思考

今天看 C 语言的指针,原来在 C 中,动态增长的数组是很麻烦的。而链表的实现则相对简单。在动态申请内存时,一次申请一大块空间经常会不成功,于是一次申请一点,用链表的形式将现有的关联资...

沙枣
2016/09/03
11
0

没有更多内容

加载失败,请刷新页面

加载更多

Java agentlib参数分析

Java agentlib参数分析 再用intellij idea进行远程调试的时候,具体的配置选项如下: 标红的一行显示了远程调试需要添加的虚拟机参数。这个参数到底有什么意义? 我在命令行输入java命令,输...

Mr_Tea伯奕
29分钟前
1
0
四种软件架构演进史,程序员会一种就很牛了!

如果一个软件开发人员,不了解软件架构的演进,会制约技术的选型和开发人员的生存、晋升空间。这里我列举了目前主要的四种软件架构以及他们的优缺点,希望能够帮助软件开发人员拓展知识面。 ...

我最喜欢三大框架
33分钟前
3
0
如何做高可用的架构设计?

定义目标 既然我们的目标是做到高可用,那么我们就有必要先明确清楚高可用的含义,并通过拆解目标,让目标可以被量化。按照我的理解,可以将目标按照以下三条进行拆解: 1. 保持业务高稳定性...

别打我会飞
34分钟前
1
0
《错误的行为》的读后感优秀范文4000字

《错误的行为》的读后感优秀范文4000字: 第一章经济人和非理性人。本书中的经纪人是指经济学家经济模式中虚拟的理想人物,非理性人是指现实生活中实实在在存在的人,与经济人相对应的人。 ...

原创小博客
45分钟前
3
0
将二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向

作者图解释很好 https://blog.csdn.net/yanxiaolx/article/details/52073221

南桥北木
51分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部