神奇的“数组转指针”

简介:

在论坛上看到类似下面的一段代码:

a.c:
int a[10]={1,2,3,4,5,6,7,8,9,0};
int *b = a;

b.c:
extern int *a;
extern int b[];

void main()
{
int x, y;
x = a[3];
y = b[3];
}

编译后运行,在main函数中,x和y分别等于什么呢?


用gdb对程序进行调试:
Breakpoint 1, main () at b.c:7
7 x = a[3];
(gdb) p a
$1 = (int *) 0x1
(gdb) p b
$2 = 0x804a068
(gdb) p *b
$3 = 134520896
(gdb) p **b
$4 = 1

可以看到,a的值是1,那么a[3]将是一个越界访问;**b的值才是1,那么b[3]应该还是个越界访问。

数组名被申明成指针、指针被申明成数组名,为什么会产生这样的结果呢?指针与数组名难道不能转换吗?

将数组名赋值给指针,这种转换是由编译器来完成的,编译器会生成一条“将数组名这个不变量的值赋给指针”的指令。然而,b.c在编译过程中,申明的指针a和数组名b是未决的符号(需要通过链接来解决)。所以,这里的类型转换不是编译器能干的事情。然后,在接下来的链接过程中,链接器也不干转换的事情,因为它只关心符号,不关心类型。于是:

在a.c中:
a被定义为数组名,a是一个不变量,没有自己的存储空间,这个不变量的值为134520896(见gdb的打印)。
b被定义为指针,b是一个变量,有自己的存储空间,这个存储空间里面存放的值是a的值,即134520896。

a.c与b.c编译生成的中间文件进行链接后,在b.c中(b.c生成的二进制文件中):
a被申明为指针,a是一个变量,有自己的存储空间,它的存储空间的地址是从a.c中链接过来的,是a.c中的a的值,即134520896。既然a的存储空间的地址是134520896,那么a的值自然就是1了。
b被申明为数组名,b是一个不变量,没有自己的存储空间,它的值是从a.c中链接过来的,是a.c中的b的存储空间的地址,即0x804a068。


可见,在链接过程中,因为数组名本身没有存储空间,所以链接时导出的是数组名所指代的数组的存储空间的地址;而指针本身是有存储空间的,所以链接时导出的是指针本身的地址。如果在这一过程中,数组名和指针发生转换,则会是错位的。


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
30天前
|
C语言
指向结构体数组的指针
指向结构体数组的指针
13 2
|
30天前
|
存储 算法 C语言
通过指针引用数组元素
通过指针引用数组元素
20 0
|
30天前
|
C语言 C++
数组元素的指针
数组元素的指针
10 0
|
30天前
|
存储 C++
使用字符指针变量和字符数组的比较
使用字符指针变量和字符数组的比较
10 0
|
23天前
|
存储 程序员 C++
使用字符指针变量和字符数组的比较
使用字符指针变量和字符数组的比较
14 1
|
23天前
|
存储 安全 Java
防止数组元素的指针被修改
防止数组元素的指针被修改
14 1
|
30天前
|
存储 算法 C++
什么是指针数组
什么是指针数组
14 3
|
1月前
|
存储 算法 C语言
C++系列十二:指针数组
C++系列十二:指针数组
|
1月前
|
算法 搜索推荐
LeetCode刷题---215. 数组中的第K个最大元素(双指针,快速选择)
LeetCode刷题---215. 数组中的第K个最大元素(双指针,快速选择)
|
1月前
|
存储 编译器 C语言
C语言指针与数组
C语言指针与数组

热门文章

最新文章