指针和数组的“不同”

“指针和数组是相同的” --- 错!

注意下面两个声明的区别:

extern int *x; //声明一个指针
extern int y[]; //声明一个数组,定义在其他文件或者是全局变量

我们经常犯的错误:

In file 1:
int mango[1000];

In file 2:
extern int *mango;

file 1中定义的mango数组,到file 2中,被当成指针mango 声明。类型不匹配,编译会出现错误!

搞清楚这个问题,首先要回想一下什么叫定义,什么叫声明

定义:只能出现在一个地方,确定对象的类型并分配内存,用来创建新对象,如:int my_array[100];

声明:可以多次出现,用来描述对象的类型,用于指代其他地方定义的对象(在其他文件里,或者是全局变量) 如: extern int my_array[100]

想明白数组和指针的区别,最好的方式就是理解数组和指针的访问方式,ok, let's go!

首先,我们要理解左值和右值,其实很简单哈,别被这么多概念吓到

X = Y

X在这里就是左值,在等号左边;Y是右值,在等号右边

左值和右值在C语言中有明确的定义:左值 X 的含义是X所代表的地址,在编译时可知,左值表示存储结果的地方;右值Y 表示Y所代表的地址的内容,右值在运行时才可知,表示Y的内容。

“C语言中引入了可“修改左值”这个术语,表示左值允许出现在赋值语句的左边 例如 a = y; a = 3, a是可修改的,这个奇怪的术语是为了与数组名区分,数组名也可用于对象在内存中的位置,是左值 a[1] = 2, 但它不能作为赋值的对象 (如果a是数组名,a = 3是错误的),标准规定,只能给可以修改的东西赋值(这句话,跟人感觉很废 有木有)”。

编译器首先为左值分配一个地址,这个地址在编译时可知,而且该变量在运行时一直保存这个地址,右值只有在运行时才知道,如果需要用到变量中存储的值(右值),编译器首先发出指令从指定地址读入变量值并将它存在寄存器中。

左值表示地址,在编译时可知,所以,如果编译器需要一个地址来执行某种操作,它就可以直接运行操作,不需要增加指令首先取得具体的地址。然而,对于指针,必须首先在运行时取得他的当前值,然后才能解引用才做(指针中存的是指向对象的地址,要取得指向对象的内容,先找指针的地址,取出指向对象的地址,再取出指向对象的值).

char a[9] = "1234567890"; c = a[i];


图A:数组下标引用

9980 是基地址,运行时,编译器 :1)取i的值,将它与9980相加。 2)取地址(9980+i)的内容

所以extern char a[], extern char a[100]等价,这两个声明都提示a是一个数组,也就是一块内存地址,数组内的字符可以从这个地址找到。从一个数组中提取字符,只要简单的从符号表显示的a的基地址加上下标即可。

extern char *p 是怎么运行的呢?

编译器知道了p是一个指针,他指向的对象时一个字符,为了取得这个字符,必须得到地址p的内容,把p的内容当做一个地址,并再从这个地址中取得字符。指针访问增加了一次额外提取:


图B:指针的引用

编译器符号表中p的地址为4624,编译器 1:)取4624的内容,5018。 2)取地址5081的内容

如果定义为指针,但以数组方式引用会怎么样呢?

char *p = "abcdefgh"; c = p[i];


图C:指针下标的解引用

char *p = "abcdefgh"; -------p[3]; 图C方式

char a[] = "abcdefgh"; ------a[3]; 图A方式

但是如果char a[] = "abcdefgh" 用 extern char *p 来声明, 然后用p[3] 开引用其中的元素时会发生什么?

图C的是按照 p首先被定义为指针,然后再用p[3]来解引用,然而如果声明extern char *p, p为指针,那么不管p原来是定义为指针还是数组,都会按照图C的方式进行操作,但是只有当p原来定义为指针时,图C才能正确的找到值。 

当用p[i]这种形式提取声明内容时,实际上得到是一个字符,但是按照上面的方法,编译器会把他当做一个指针,把ASCII 字符解释为地址显然不对。如果程序corrupt,是好事!

另:定义指针时,编译器并不为指针所指向的对象分配内存空间,它只分配指针本身的空间,除非定义时同时对指针一个字符串常量进行初始化: char *p= "breakdfruit";这种情况只对字符串常量有效。float *pip = 3.141; //错误!

在ANSI C 中,初始化指针时所创建的字符串常量被定义为只读,不能对字符串进行修改。然而数组定义的字符串常量可以修改。


指针是C语言的精华,需要多多学习,多多练习。从原理下手比较容易理解。


Reference:

  Expert C






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值