神奇的“数组转指针”

简介:

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

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
目录
相关文章
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
147 3
|
12月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
245 4
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
143 2
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
139 1
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
下一篇
oss云网关配置