我定义数组时真正发生了什么

时间:2014-07-28 16:40:40

标签: c arrays string pointers memory-address

我编写程序来理解数组和指针之间的区别:

#include <stdio.h>

void main()
{
    char arr [] ="hodaya",*ptr=arr;
    printf("arr=%p\n",arr);
    printf("&arr=%p\n",&arr);
    printf("ptr=%p\n",ptr); 
    printf("&ptr=%p\n",&ptr);
}

结果:

arr=0xbfd26265

&arr=0xbfd26265

ptr=0xbfd26265

&ptr=0xbfd26260

所以我看了下面的答案:

how-come-an-arrays-address-is-equal-to-its-value-in-c

它回答了我的大多数问题,我只留下了一个问题!

我明白当我定义指针时我定义了(在特定地址中)一个空格用于保持地址,因此我可以像这样获取指针地址:&ptr

但是当我定义数组时会发生什么?

2 个答案:

答案 0 :(得分:3)

首先,除非您的编译器文档显式void main()列为main函数的有效签名,否则请改用int main(void)。在大多数情况下,main 假定将值返回给运行时环境(即使它只是EXIT_SUCCESS)。

让我们来谈谈宣言

char arr [] ="hodaya";

"hodaya"是一个字符串文字;它存储为char的7个元素数组(6个字符加0个终结符),以便在程序启动时分配并保持直到程序退出。字符串文字不是可修改的,并且尝试更新字符串文字会导致未定义的行为(这可能意味着从您的代码崩溃到访问冲突到按预期工作)。您应始终将字符串文字视为只读,并且永远不要将它们传递给尝试修改它们的函数(例如strcpystrtok等)。

arr被声明为char的数组,并且已初始化,其中包含字符串文字"hodaya"的内容。数组的大小取自初始化程序的大小(7)。该声明大致相当于:

char arr[7];
strcpy( arr, "hodaya" );

它也可以写成

char arr[] = {'h', 'o', 'd', 'a', 'y', 'a', 0 };

相同的结果(arr使用字符串"hodaya"初始化),语法略有不同。在这种情况下,不会创建字符串文字。

由于您将arr声明为main本地(据说自动存储持续时间,意味着当函数退出时将释放内存),您可以修改arr[0]arr[6]的内容。

现在让我们谈谈ptr的声明。

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,表达式为类型“{元素数组T”将被转换(“衰减”)为“指向T的指针”类型的表达式,表达式的值将是第一个元素的地址在数组中。结果不是左值;也就是说,它不能成为作业的目标。

这很重要,也是很多混淆的来源。 arr 不是指针;它不包含地址。当编译器在大多数上下文中看到arr时,它将用它的第一个元素的地址替换,并且结果表达式的类型将是char *。但是,如果arr是一元&运算符的操作数,则替换不会发生。表达式的是相同的(数组的地址与数组的第一个元素的地址相同),但类型是不同的;而不是char *&arr的类型是char (*)[7](指向char的7元素数组的指针)。

因此,在宣言中

char *ptr = arr;

arr不是一元&运算符(或任何其他运算符)的操作数,因此应用转换规则,以及{{{}的第一个元素的地址 1}}写入arr

当你完成时,你的记忆看起来像下面这样(地址并不意味着反映任何真实世界的架构):

ptr

同样,Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- "hodaya" 0x40040 'h' 'o' 'd' 'a' 0x40044 'y' 'a' 0 ?? ... arr 0x7fffb220 'h' 'o' 'd' 'a' 0x7fffb224 'y' 'a' 0 ?? ptr 0x7fffb228 0x7f 0xff 0xb2 0x28 arr仅在函数ptr的生命周期内存在。字符串 文字main存在于整个程序的生命周期中。

注意:我使用gcc 4.1.2在SLES 10盒子上编译了上面的例子(在解决了几个问题之后),是的,它为"hodaya"中的字符串文字创建了一个条目,甚至虽然它只用于初始化.rodata

答案 1 :(得分:-3)

arr保存数组中第一个元素的地址(&arr[0])。

在这里,您始终在阅读元素的地址而不是值。

arr[0] = 'a', arr[1] = 'b', arr[2] = 'c', arr[3] = 0;

char *ptr = arr;
*ptr++ = 'a', *ptr++ = 'b', *ptr++ = 'c', *ptr = 0;