为什么指针有类型

既然指针只是地址,为什么指针变量有类型?为什么不能用一种通用类型的变量保存所有的指针?

为什么指针有类型 - 图1

因为指针算术运算会暗渡陈仓。如果对char指针加1,指针会指向存储器中下一个地址,那是因为char就占1字节。

如果是int指针呢?int通常占4字节,如果对int指针加1,编译后的代码就会对存储器地址加4。

  1. int nums[] = {1, 2, 3};
  2. printf("nums 的地址是 %p\n", nums);
  3. printf("nums + 1 的地址是 %p\n", nums + 1);

如果运行上面这段代码,就会发现两个地址相隔不止一个字节。指针之所以有类型,是因为编译器在指针算术运算时需要知道加几。

为什么指针有类型 - 图2

 

为什么指针有类型 - 图3

致命处方案件

上次我们把大英雄留在案发现场调查汤茱蒂,她的丈夫因一段可疑的代码而服用药物过量致死。汤茱蒂到底是写代码的杀人凶手,还是无辜的替罪羊?如果你想知道真相,接着往下读……

他把代码塞进了口袋,说道:“王太太,谢谢你的配合,以后我再也不会打扰你了。”他握了握她的手。“谢谢。”她一边拭去眼角的泪水,一边说道,“你真是个好人。”

“先别急,王太太。”还没等汤茱蒂反应过来,他就已经给她戴上了手铐,“看到你那双精心修饰过的手,我就知道你隐瞒了很多真相。”只有一个以键盘为生的人,指尖才会像她那样布满老茧。

“汤茱蒂,你假装对C语言一窍不通,但事实上,你是一个高手,让我们再看一遍代码。”

  1. int doses[] = {1, 3, 2, 1000};
  2. printf("服用 %i 毫克的药", 3[doses]);

“看到3[doses]这个表达式的时候,我就知道有哪里不对劲,你知道数组变量doses用作指针,那剂致命的1000毫克可以写成这样……”他在一张“舒洁”纸巾上写下一些代码。

  1. doses[3] == *(doses + 3) == *(3 + doses) == 3[doses]

“王太太,你的代码彻底出卖了你,它给王百万服用了1000毫克的药。现在我们要带你去一个地方,在那里你再也无法玩弄C语言的语法……”

为什么指针有类型 - 图4要点

  • 数组变量可以用作指针……

  • ……但数组变量和指针又不完全相同。

  • 对数组变量和指针变量使用sizeof,效果不同。

  • 数组变量不能指向其他地方。

  • 把数组变量传给指针,会发生退化。

  • 索引的本质是指针算术运算,所以数组从0开始。

  • 指针变量具有类型,这样就能调整指针算术运算。

 

这里没有蠢问题

问:我真的需要理解指针算术运算吗?

:有的程序员不使用指针算术运算,因为它很容易出错,但你可以用它有效地处理数组数据。

问:指针能做减法吗?

:能,但小心别让指针越过数组的起点。

问:C语言什么时候对指针算术运算进行调整?

:在编译器生成可执行文件时,编译器会根据变量的类型,用变量的大小乘以指针的增量或减量。

问:然后呢?

:假如编译器看到你对一个指向int数组的指针加2,就会用2乘以4(int的长度),然后对地址加8。

问:C语言在调整指针算术运算时用了sizeof运算符吗?

:本质上如此,sizeof运算符的结果也是在编译时决定的,对各种数据类型,sizeof和指针算术运算都将使用相同的长度。

问:指针可以相乘吗?

:不可以。