字符 a[] = ?字符串?有什么区别;和字符 *p = ?字符串?;
What is the difference between char a[] = ?string?; and char *p = ?string?;?
正如标题所说,两者之间有什么区别
char a[] = ?string?; and
char *p = ?string?;
这个问题是在采访中问我的。我什至不明白这句话。
char a[] = ?string?
这里?
运算符是什么?它是字符串的一部分还是具有某些特定的含义?
?
似乎是一个错别字,它在语义上无效。因此,答案假设?
是一个错别字,并解释了面试官可能真正想问的问题。
首先,两者明显不同:
- 第一个创建一个指针。
- 第二个创建一个数组。
请继续阅读以获取更详细的说明:
阵列版本:
char a[] = "string";
创建一个足够大的数组,以保存字符串文本"字符串",包括其NULL
终止符。数组string
使用字符串文本"string"进行初始化。数组可以在以后修改。此外,数组的大小即使在编译时也是已知的,因此可以使用sizeof
运算符来确定其大小。
指针版本:
char *p = "string";
创建一个指向字符串文本"字符串"的指针。这比数组版本更快,但指针指向的字符串不应更改,因为它位于只读实现定义的内存中。修改此类字符串文本会导致未定义的行为。
事实上,C++03 弃用[Ref 1] 使用没有 const
关键字的字符串文字。所以声明应该是:
const char *p = "string";
此外,您需要使用 strlen()
函数,而不是sizeof
来查找字符串的大小,因为 sizeof
运算符只会为您提供指针变量的大小。
更好,我应该使用哪个版本?
取决于使用情况。
- 如果不需要对字符串进行任何更改,请使用指针版本。
- 如果要更改数据,请使用数组版本。
注意:这不是C++,但这是特定于 C 语言的。
请注意,使用不带 const
关键字的字符串文字在 C 中是完全有效的。但是,修改字符串文本仍然是 C[Ref 2] 中的未定义行为。
这就提出了一个有趣的问题,
在 C 语言中与字符串文字一起使用时,char* 和常量 char* 有什么区别?
对于斯坦德德斯球迷:
[参考文献 1]C++03 标准: §4.2/2
不是宽字符串文本的字符串文本 (2.13.4( 可以转换为类型为"指向字符的指针"的右值;宽字符串文本可以转换为类型为"指向wchar_t的指针"的右值。在任一情况下,结果都是指向数组第一个元素的指针。仅当存在显式的适当指针目标类型时,才考虑此转换,而不是在一般需要从左值转换为右值时考虑此转换。[注意:此转换已弃用。见附件D。为了在重载分辨率 (13.3.3.1.1( 中进行排名,此转换被视为数组到指针的转换,然后是限定转换 (4.4(。[示例:"abc"作为数组到指针的转换转换为"指向常量字符的指针",然后转换为"指针到字符"作为限定转换。
C++11 只是删除了上述引文,暗示它是 C++11 中的非法代码。
[参考文献 2]C99 标准 6.4.5/5 "字符串文字 - 语义":
在转换阶段 7 中,值为零的字节或代码将追加到由一个或多个字符串文本生成的每个多字节字符序列。然后,使用多字节字符序列初始化静态存储持续时间和长度刚好足以包含该序列的数组。对于字符串文本,数组元素的类型为 char,并使用多字节字符序列的各个字节进行初始化;对于宽字符串文本,数组元素的类型为 wchar_t,并使用宽字符序列进行初始化...
如果这些数组的元素具有适当的值,则无法指定这些数组是否不同。如果程序尝试修改此类数组,则行为未定义。
第一个是数组,另一个是指针。
数组声明
char a[6];
请求留出六个字符的空间,以名称a
表示。也就是说,有一个名为a
的位置,六个角色可以坐在该位置。另一方面,指针声明char *p;
请求一个保存指针的位置。指针的名称为p
,并且可以指向任何地方的任何字符(或连续的字符数组(。声明
char a[] = "string"; char *p = "string";
将产生可以像这样表示的数据结构:
+---+---+---+---+---+---+----+ a: | s | t | r | i | n | g | | +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g | | +-----+ +---+---+---+---+---+---+---+
重要的是要认识到,像
x[3]
这样的引用会根据x
是数组还是指针生成不同的代码。给定上面的声明,当编译器看到表达式a[3]
时,它会发出代码以从位置a
开始,将三个元素移过它,然后在那里获取字符。当它看到表达式p[3]
时,它会发出代码以从位置p
开始,在那里获取指针值,向指针添加三个元素大小,最后获取指向的字符。在上面的例子中,a[3]
和p[3]
恰好是字符l
,但编译器到达那里的方式不同。
来源: comp.lang.c 常见问题列表 ·问题 6.2<</strong>
char a[] = "string";
这会在堆栈上分配字符串。
char *p = "string";
这会在堆栈上创建一个指针,该指针指向进程数据段中的文本。
?
写它的人不知道他们在做什么。
堆栈、堆、数据段(和 BSS(和文本分隔是进程内存的四个段。定义的所有局部变量都将在堆栈中。使用 malloc
和 calloc
以动态方式分配的内存将位于堆中。所有全局变量和静态变量都将位于数据段中。文本段将具有程序的汇编代码和一些常量。
在这 4 个部分中,文本段是READ ONLY
段,在所有其他三个部分中用于READ
和WRITE
。
char a[] = "string";
- 此 statemnt 将为堆栈中的 7 个字节分配内存(因为局部变量(,并将保留所有 6 个字符(s, t, r, i, n, g
(加上 NULL 字符 (