char *array 和 char array[] 之间的内存区别是什么?

What the memory difference between char *array and char array[]?

当我执行下一段代码时

int main()
{
    char tmp[] = "hello";
    printf("%lp, %lp\n", tmp, &tmp);
    return 0;
}

我有相同的地址。但是对于下一个代码,它们会有所不同

int main()
{
    char *tmp = "hello";
    printf("%lp, %lp\n", tmp, &tmp);
    return 0;
}

您能解释一下这些示例之间的内存差异吗?

char tmp[] = "hello";是一个6个字符的数组,初始化为"hello[=11=]"(它具有自动存储持续时间并驻留在程序堆栈中)。

char *tmp = "hello"; 是一个指向 char 的指针,用驻留在只读内存中的字符串文字 "hello[=11=]" 的地址初始化(通常在可执行文件的 .rodata 部分中,除了少数实现之外的所有实现都是只读的。

当你有 char tmp[] = "hello"; 时,如上所述,在访问时数组被转换为指向 tmp 的第一个元素的指针。它的类型为 char *。当您获取 tmp 的地址(例如 &tmp)时,它将解析为相同的地址,但具有完全不同的类型。它将是一个 指向数组的指针 char[6]。正式类型是char (*)[6]。并且由于 类型控制指针算法 ,当您推进指针时,使用不同的类型进行迭代将产生不同的偏移量。前进tmp将前进到下一个char。以 tmp 地址前进将前进到下一个 6 字符数组的开头。

当你有 char *tmp = "hello"; 时,你就有一个指向 char 的指针。当你取地址时,结果是 pointer-to-pointer-to char。正式类型是 char ** 反映了两个间接级别。前进tmp前进到下一个char。以 tmp 的地址前进会前进到下一个指针。

char a[] = "hello";

char *a = "hello";

存储在不同的地方。

char a[] = "你好"

在这种情况下,a 成为一个 6 个字符的数组(存储在堆栈中),初始化为“hello[=34=]”。等同于:

char a[6];
a[0] = 'h';
a[1] = 'e';
a[2] = 'l';
a[3] = 'l';
a[4] = 'o';
a[5] = '[=12=]';

char *a = "你好"

检查装配(这不是全部装配,只是重要的部分):

    .file   "so.c"
    .text
    .section    .rodata
.LC0:
    .string "hello" ////Look at this part
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    $.LC0, -8(%rbp)
    movl    [=13=], %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

.section    .rodata
.LC0:
    .string "hello"

这是存储字符串的地方。 char a[] 存储在堆栈中,而 char *a 存储在编译器喜欢的任何位置。一般在rodata.

char tmp[] = "hello";

您正在预留一个 char 数组 ,其大小足以存储字符串 "hello" 并将字符串的内容复制到该数组,例如你在记忆中得到这个:

     +–––+
tmp: |'h'| tmp[0]
     +–––+
     |'e'| tmp[1]
     +–––+
     |'l'| tmp[2]
     +–––+
     |'l'| tmp[3]
     +–––+
     |'o'| tmp[4]
     +–––+
     | 0 | tmp[5]
     +–––+

没有 tmp 对象与数组元素本身分开,因此数组 (tmp) 的地址与其第一个元素 (tmp[0]) 的地址相同).

char *tmp = "hello";

您正在创建指向 char 指针 并使用 地址 中第一个字符的 初始化它36=]string literal "hello",这样你在内存中得到这个:

     +–––+       +–––+
tmp: |   | ––––> |'h'| tmp[0]
     +–––+       +–––+
                 |'e'| tmp[1]
                 +–––+
                 |'l'| tmp[2]
                 +–––+
                 |'l'| tmp[3]
                 +–––+
                 |'o'| tmp[4]
                 +–––+
                 | 0 | tmp[5]
                 +–––+

在这种情况下tmp 一个独立于数组元素的对象,所以tmp的地址不同于[=18的地址=].