数组名和指针一样吗

在C语言里经常将数组名当成指针或者将指针当成数组来使用,那么两者到底一样吗?

以下面代码为例
在a.c中定义一个数组

//在a.c文件中
char array[] =”1234567890”;

然后再main.c中声明这个数组

//在main.c文件中
#include <stdio.h>
extern char *array;  //将array声明成指针
void main(int argc, char **argv) {
	char a = array[2];
	printf("%c\n", a);
}

可以看到在a.c中定义array为一个char型的数组,而在main.c中将array声明成一个char型的指针,这样的代码运行起来有问题吗?

通过测试,会发现这个程序运行的时候会死机。不能运行的原因,就是因为指针和数组是有区别的。

一、指针与数组的区别

这两者的区别体现在编译器对这两个不同类型变量的处理方法。

以下面定义的两个变量为例

char array[] = "1234567890";
char *p_array = "1234567890";

1. 在内存中的区别

这两个变量在编译后生成的符号表里的显示:
在这里插入图片描述

从上图中可以看出,编译器编译之后生成的符号表中,数组名array对应的地址就是数组所在的地址,而且其所占的大小也是数组的大小。如下图所示:
在这里插入图片描述

而编译器对于指针的处理,可以看出指针变量的大小是4个字节,也就是说指针变量所在的地址并不是字符串所在的位置,字符串的地址是指针变量的值。如下图所示,指针变量的地址是0x2000000C,而字符串的地址是0x08001A54,字符串的地址是p_array这个指针变量的值。

在这里插入图片描述

2. 代码运行的区别

通过查看编译后的汇编语言也能看出区别

将array声明成数组类型

当在main.c中将array声明为数组类型时

//在main.c中
extern char array[]; //声明为数组类型
int main()
{
    char c;
    c = array[2];
    while(1);
}

生成的汇编语句如下:

在这里插入图片描述

其先将0x20000000(即array所在地址)保存到r0寄存器中,然后再将0x20000000这个地址加2,即0x20000002这个地址的值保存到r4寄存器中,从而获得array[2]的值。

将array声明为指针类型时

当在main.c中将array声明为指针类型时

//在main.c中
extern char *array; //声明为指针类型
int main()
{
    char c;
    c = array[2];
    while(1);
}

生成的汇编代码如下:

在这里插入图片描述

其先将0x20000000保存到r0寄存器,然后再将0x20000000这个地址存储的值保存到r0寄存器,之后再将r0的值加2,再读取数据保存到r4寄存器中。

通过对比这两组汇编语句,发现指针生成的汇编语句比数组生成的汇编语句多了一句。对于数组变量,其取数据用的就是数组名所在的地址,而对于指针变量,其取数据用的是指针变量所在地址里的值。

二、开始处代码的问题

通过上面的对比,可以得出最开始处代码的主要问题是array的定义和声明不一致

变量array在a.c中被定义成数组,因此在编译的时候是按照数组编译的,也就是说array的地址就是数组的地址,array所在地址存放的就是array数组的数据。但是在main.c中声明的时候却将array声明成了指针,所以编译器在编译main.c的时候则是将array当指针编译的,也就是说编译器认为array存放的是一个地址,这样的话,在main.c文件中调用char c=array[2]时,编译器也是将array当成指针处理的,所以在array内存的位置存放的是数据0x31323334(也就是字符’1’’2’’3’’4’),编译器会把这个数据当成指针所指向的地址,然后从这个地址取数据,这是一个非法地址,那么肯定是无法得到正确数据的,所以程序无法正确运行。

三、解决方法

解决方法也很简单,那就是“使声明和定义相匹配”。变量的定义是一个数组,那么声明的时候也要是数组,定义是指针,那么声明也要是指针。比如上面的代码中,在main.c中将声明改成
extern char array[];

四、总结

在应用的时候,我们总是将数组和指针混用,但是对于编译器来说,对这两种变量类型的处理方法是不同的。但是只要使变量的声明和定义相匹配就行,这样编译器就能够正确的处理数据了。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值