论指针和数组的区别

在C/C++中,指针的使用的确是一个让人头疼的问题,稍有不慎程序就运行时崩溃。最近又看到很多人纠结于指针问题,下面就结合这些问题谈谈。

 

一个最普遍的问题就是很多人认为指针完全可以和数组进行互换,关于这一点《C专家编程》的作者已经在第四、第九和第十章中作了详细阐述。其结论就是我们不能混淆指针和数组这两个完全不同的概念,它们可互换是有条件的。

 

我们在程序中使用数组大致有4种情况:外部声明,定义,函数参数声明以及作为表达式。这几种情况下只有作为函数参数和在表达式中使用时,两者才能完全等价。其余情况下数组是数组,指针是指针,不能混为一谈。需要说明的是,即使作为表达式,在被sizeof操作符和取地址操作符&作用时,数组也还是数组,不能视作指针。

 

该书举了一个很经典的例子说明外部声明中的数组和指针是不等价的,这里结合不久前看到的一道例题作更明确的解释。

 

文件1:

文件2:

问题是在文件2的下划线处应该填什么内容才能使cout输出9呢?实际上,这个问题就是 《C专家编程》 中第四章例子的扩展。理论上,在一个文件中将arr声明为int型指针,然而在另一个文件又定义为数组是不合法的。原因就在于编译器在看到arr指针声明时,以后出现表达式arr[i]时,会先去取符号表中找arr的地址比如3FA2,然后定位到内存中3FA2的地址,从该地址中取出值比如6FF0,这个值就是arr指向的地址,之后拿这个值加上i个步长得到一个新的地址取出该地址的内容作为这个表达式的值。而当arr作为数组声明时编译器是怎么处理的呢 ?它直接从符号表中取出地址,加上i个步长得到一个新地址取其内容。可以看到,指针作了一次间接引用,总共步骤比作为数组声明多了一步。基于编译器的这种行为,回到上面那个问题,当声明一个外部指针,然而在另一个文件中定义为数组会发生什么呢 ?

 

main函数语句int *ptr = arr;执行完后毫无疑问ptr和arr是指向同一块内存的,但是arr里必须有值才能赋值给ptr,这个值是什么 ?答案是文件2中定义的arr数组中的第0号元素的值,也是我们需要填的值x,这是声明和定义不一致导致的,并不符合我们让ptr指向数组arr首元素的初衷。这样ptr中保存的值为x。接下来*arr = 9;一般情况下是一定会导致runtime error的,原因在于非法写值9到地址为x的内存。最后cout尝试输出非法地址x的值,程序不可避免地崩溃。当然,我们可以对arr数组的首元素作点手脚使得程序正常运行并输出9。分析之后不难发现,程序如果能正常运行,ptr和arr的值一定相等,最后ptr输出的值也必然是9。剩下的问题就是考虑如何 让*arr = 9;这句合法,也就是arr中的值是一块程序可访问的内存。让arr指向哪里呢 ?在另一个文件中不是为数组开辟了空间吗 ?好了,心中有数了,我们要填的下划线部分就是数组范围内的地址了,当然&arr[0]和 &arr[1]都可以啦~注意,这样还不够,我们得到的是一个地址值,要存放在int数组里需要作显式转换,即 (int)&arr[0]或者 (int) &arr[1] 。试运行一下,没有问题。一个声明和定义不一致的问题,给我们带来了这么大麻烦。

 

下面再来看另外一个例子。

在BBS上看到有人问为什么类似这样一段代码不能正常运行。一句一句来分析,arr是一个数组,cout << arr << endl;arr作为表达式,自动转换为指向数组第一个元素的指针,也就是输出数组首地址,没有问题。cout << &arr << endl;注意arr被取地址操作符作用,arr还是一个数组,不是指针,这句取的是数组的地址。要说明的是,对于C++编译器而言,数组就是一个地址(摘自 《C专家编程》 中文版 200页 ),所以得到的还是数组0号元素的地址,与第一句执行结果相同。对于第三条语句,那么为什么不能把这样一个地址赋值给int型指针呢?原因在于类型不匹配!arr是一个数组, &arr是一个指向数组的指针,再看看p是什么,p是一个指向int的指针,两者怎么可以等 ? !要让这句合法,要么改变左边p的类型,要么改变右边的值类型。很明显了,我们需要一个int (*p)[3]类型的指针或者一个int值的地址&arr[0]。这样上述程序就会正常运行,输出三个相同的地址值,至于为什么一样就无须多说了。

 

要少犯错,还是牢牢记住一句话,数组是数组,指针是指针,将数组指针可互换的论断完全抛到脑后吧!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值