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的地址=].
当我执行下一段代码时
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的地址=].