【问题标题】:What really happen when I defined array当我定义数组时真正发生了什么
【发布时间】:2014-07-28 16:40:39
【问题描述】:

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

#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

它回答了我的大部分问题,我只剩下一个问题!

我知道,当我定义指针时,我(在特定地址)定义了一个用于保存地址的空间,因此我可以像这样获取指针地址:&amp;ptr

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

【问题讨论】:

  • 您有未定义的行为。 printf 在给定 %p 时期望 void *
  • 定义数组时没有什么特别的事情发生。 char arr[] = "blah";char x = 'p'; 没有什么不同 - 每个都定义了一个与某些存储相关的名称。
  • @OliCharlesworth 所以它定义了一个空间来保存一些字符?因此 arr= &arr ,因为 arr 是第一位的地址? (而不是指针)
  • 当您定义 arr[] 时,您创建了一个名为 arr 的内存块,它大到足以容纳“hodaya”。
  • 令人困惑的是,在许多情况下,数组会自动衰减到指向其第一个元素的指针。由于这种衰减,当您打印array 时,实际上是在打印&amp;array[0]。实际上array[0]array 的地址相同,因此&amp;array[0]&amp;array 具有相同的数值(尽管类型不同)。

标签: c arrays string pointers memory-address


【解决方案1】:

首先,除非您的编译器文档明确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 local to main(据说有自动存储时长,意思是函数退出时会释放内存),你可以修改@的内容987654339@ 到 arr[6]

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

除非它是sizeof 或一元&amp; 运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则表达式 类型为“N- T" 的元素数组将被转换 ("decay") 为类型为 "pointer to T" 的表达式,表达式的值将是数组中第一个元素的地址。结果不是左值;也就是说,它不能成为分配的目标。

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

因此,在声明中

char *ptr = arr;

arr 不是一元 &amp; 运算符(或任何其他)的操作数,因此适用转换规则,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

同样,arrptr 仅在函数 main 的生命周期内存在。字符串 文字 "hodaya" 在整个程序的生命周期内都存在。

注意:我使用 gcc 4.1.2 在 SLES 10 机器上编译了上面的示例(在修复了一些问题之后),是的,它为 .rodata 中的字符串文字创建了一个条目,即使它是仅用于初始化arr

【讨论】:

    【解决方案2】:

    arr 保存数组中第一个元素的地址(&amp;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;
    

    【讨论】:

      猜你喜欢
      • 2021-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多