【知其所以然】语义"陷阱"---数组和指针
数组和指针经常出现于编程语言中、也许上课的时候老师也说过数组和指针有区别、参考书上也应该讲过,你是不是也不曾透彻的理清过?
这篇博文主要从内存和编译的角度指出了数组和指针在访问方式上的区别、至于他们在函数调用的区别、以及它们的联系将在下一篇中详细讨论。
为了说的清楚些、会先说一些基础的部分、如果你已经掌握大可跳过
What's a Declaration? What's a Definition? 声明和定义
c语言的对象必须有且只有一个定义,但可以有多个声明(extern)这里说的对象和面向对象中的对象没有关系。
A definition is the special kind of declaration that creates an object; a declaration indicates a name
that allows you to refer to an object created here or elsewhere。
定义是一种特殊的声明、它创建了一个对象;声明简单的说明了在其他地方创建的对象的名字,它允许你使用这个名字。
可以简单的这样理解:
声明Declaration:描述在其他地方创建的对象,并不分配内存。(可以出现在多个地方)
定义Definition:产生一个新的对象,并分配内存。(只能出现一次)
How Arrays and Pointers Are Accessed -数组和指针是如何访问的
数组和指针在内存中的访问方式是不一样的。这里先要注意一下“地址y”和“地址y的内容”的区别。“地址y”表示变量y在内存中的地址,而“地址y的内容”指的是
位于这个地址中的内容,也就是变量y的值。大多数编程语言中用同一个符号来表示这两个东西,而由编译器根据上下文环境判断它的含义。
以一个简答的赋值为例:
上文中的x指的是x所代表的地址,而y的含义是y的内容。
出现在赋值符号左边的值称为左值、赋值符号右边的称为右值。编译器为每个变量分配地址(左值)。这个地址在编译时可知且一直存在,而它的右值在运行时
才能知道。通俗的说:每个变量都有一个地址,这个地址在编译时可以知道,而地址里存储的内容(也就是变量的值)只有在运行时才能知道。如果需要用到变量
的值,(也就是已知地址存储的值)那么编译器发出指令从指定地址读入变量值并放入相应寄存器中。
这里的关键是地址在编译时可知、如果要对进行一些操作(比如说加上偏移量之类的)可以直接操作。相反、对于指针,必须在运行时取得它的地址,然后才能
对它进行接触引用操作。下图展示了对数组下标的引用:
这样我们就可以解释为什么extern char a[]和extern char a[100]相同的原因了。这两个什么都是表名a是一个数组,也就是一个内存地址,
数组内的字符可以由这个地址找到。
和上面不同的是,如果声明的是一个指针,如 extern char *p,它表示p指向一个字符,为了取得这个字符,必须知道地址p的内容,把它作为字符的地址
并从这个地址中取得这个字符。
如果是数组a[],那么可以直接用数组名来访问数组中的元素,因为它的内容就是第一个元素, 他的下一个地址也就对应了下一个数组元素的地址。
如果是指针*a,先要取出地址a的内容,再把它作为变量的地址并从这个地址中取得变量的内容。
数组和指针的其他区别:
定义指针时,编译器并不为它所指向的对象分配空间,只为指针本身分配空间。除非在定义同时付给一个指针一字符窜常量进行初始化。
如:char *p = "breadfruit";
一般情况下初始化指针时创建的字符串变量被定义为只读。如果试图修改就会出现未定义的行为。
这篇文章主要是从访问形式上对数组和指针的区别做了些小的总结,而对于数组和指针在函数调用中、已经更本质的区别、什么时候数组
和指针又是等同的、将在下一篇博文中给出。如果完全弄清楚了、对今后的编程也会有不小的帮助。
参考资料:《expert c programming》
欢迎任何形式的转载,请注明出处:http://www.cnblogs.com/yanlingyin/
一条鱼~ @博客园