01月10, 2018

extern char *s与extern char s[]的区别

首先,C在语言中,指针和数组是完全不同的两个东西。我们先把这两个概念的固有想法完全抛弃。

考虑C中是不能将数组作为参数传递的,因此当我们使用到数组名,编译器会自动转化成数组中首元素的地址进行传递,也就是arr这个名字等价于&arr[0]

不过,数组名这个东西比较特殊,它也是可以取地址的。我们可以这样理解:数组名是“数组”这种变量的变量名,当直接用这个变量名的时候,我们拿到的是它的首地址,当对这个变量名取地址的时候,我们得到的是这个数组变量的地址,虽然它的值依然是数组的首地址,但是如果对它进行加1操作,则增加的值将是整个数组的长度。例如int arr[5];&arr+1则是增加了5个int长度后的地址。

但需要注意的是,这种转换并不总是发生的。因为指针和数组是完全不同的两个东西。

其实,最核心的区别在于:指针本身是一个变量,它是保存在内存中的,在内存中占据空间;而数组名究竟代表了什么,这是由编译器计算出来的,通常它的值在编译的时候会被指定为数组中首元素的地址。因此通常在程序中使用数组名的时候就等于是使用这个首元素的地址。

因此,当我们要使用一个指针找到它的指向的内存的值的时候,在机器语言层面实际上是先在内存中找到这个指针变量所在的位置,读取它的值,然后再根据这个值(存的是地址),找到它指向的数据。而数组名的话,就省去了第一个步骤,即这个数组名直接就是它所指向的数据的地址,是在编译后就写死在机器指令中的,因此一条指令就可以读取这个地址指向的值了。

理解了这一点之后,于是我们就不难理解为什么在int a[5]; int *p=a里,sizeof(p)sizeof(a)不一样了。

于是我们再看这样的一个例子:

extern char *s;
extern char s[];

我们知道extern是一个声明,引入了其他cpp文件中的变量,使得它能够在这个文件中使用。

假设在其他文件中定义了一个字符串,在本文件中的这两种写法是完全不一样的。

extern char *s;则表示我要先读s变量的值,把这个值当做地址去找值。因此如果外部文件中定义了extern char s[]="ABCDE";,那么本文件中的s的行为会将"ABCDE"当成地址,再从这个地址找值。

同理,如果外部文件定义了extern char *s="ABCDE";而我用extern char s[];的话,它会将外部文件中的s变量存的地址当做字符串输出出来。

本文链接:https://debug.fanzheng.org/post/difference-between-pointer-and-array.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。