#include <stdio.h>
#include <string.h>
int main()
{
char *p = "hello";
char q[] = "hello"; // no need to count this
printf("%zu\n", sizeof(p)); // => size of pointer to char -- 4 on x86, 8 on x86-64
printf("%zu\n", sizeof(q)); // => size of char array in memory -- 6 on both
// size_t strlen(const char *s) and we don't get any warnings here:
printf("%zu\n", strlen(p)); // => 5
printf("%zu\n", strlen(q)); // => 5
return 0;
}
7 回答
char*
和char[]
是不同的类型,但并非在所有情况下都立即显现出来 . 这是因为数组衰减为指针,这意味着如果提供类型char[]
的表达式,其中类型char*
之一是预期的,则编译器会自动将数组转换为指向其第一个元素的指针 .你的示例函数
printSomething
需要一个指针,所以如果你试图像这样传递一个数组:编译器假装你写了这个:
让我们来看看:
foo *和foo []是不同的类型,它们由编译器处理不同(指针=指针类型的地址表示,数组=指针可选的数组长度,如果已知,例如,如果数组是静态分配的),细节可以在标准中找到 . 并且在运行时级别它们之间没有区别(在汇编程序中,好吧,差不多,见下文) .
此外,C FAQ中有一个相关的question:
C99 N1256 draft
字符串文字有两种不同的用法:
char[]
:这是“更神奇的”,并在6.7.8 / 14“初始化”中描述:
所以这只是一个捷径:
与任何其他常规数组一样,
c
可以修改 .其他地方:它生成一个:
未命名
char数组What is the type of string literals in C and C++?
带静态存储
如果修改则给出UB
所以当你写:
这类似于:
请注意从
char[]
到char *
的隐式强制转换,这始终是合法的 .然后,如果修改
c[0]
,还可以修改__unnamed
,即UB .这在6.4.5“字符串文字”中记录:
6.7.8 / 32“初始化”给出了一个直接的例子:
GCC 4.8 x86-64 ELF implementation
程序:
编译和反编译:
输出包含:
结论:GCC将
char*
存储在.rodata
部分,而不是.text
.如果我们为
char[]
做同样的事情:我们获得:
所以它存储在堆栈中(相对于
%rbp
) .但请注意,默认链接描述文件将
.rodata
和.text
放在同一段中,该段已执行但没有写入权限 . 这可以通过以下方式观察:其中包含:
你不能改变字符串常量的内容,这是第一个
p
指向的内容 . 第二个p
是一个用字符串常量初始化的数组,您可以更改其内容 .对于这样的情况,效果是相同的:您最终会在字符串中传递第一个字符的地址 .
虽然声明显然不一样 .
下面为字符串和字符指针留出内存,然后初始化指针以指向字符串中的第一个字符 .
虽然以下内容仅为字符串留出内存 . 所以它实际上可以使用更少的内存 .
据我所知,数组实际上是一组指针 . 例如
是一个真实的陈述
char p[3] = "hello"
?应该是char p[6] = "hello"
记得在C的"string"末尾有一个'\0'字符 .无论如何,C中的数组只是指向内存中调整对象的第一个对象的指针 . 唯一不同的是语义 . 虽然您可以将指针的值更改为指向内存中的其他位置,但创建后,数组始终指向同一位置 .
同样在使用数组时,"new"和"delete"会自动为您完成 .