正如标题所说,
之间有什么区别char a[] = ?string?; and
char *p = ?string?;
在采访中我问过这个问题。 我甚至不理解这句话。
char a[] = ?string?
这是什么?
运营商?它是字符串的一部分还是具有某些特定含义?
答案 0 :(得分:89)
?
似乎是一个拼写错误,它在语义上没有效果。所以答案假设?
是一个拼写错误,并解释了面试官可能要提出的问题。
开始时两者都截然不同:
继续阅读以获取更详细的解释:
char a[] = "string";
创建一个足以容纳字符串文字“string”的数组,包括其NULL
终止符。使用字符串文字“string”初始化数组string
。 稍后可以修改数组。此外,即使在编译时也可以知道数组的大小,因此可以使用 sizeof
运算符来确定其大小。
char *p = "string";
创建指向字符串文字“string”的指针。这比数组版本快,但指针指向的字符串不应更改,因为它位于只读实现定义的内存中。修改此类字符串文字会导致未定义行为。
事实上,C ++ 03不赞成 [Ref 1] 使用不带const
关键字的字符串文字。声明应该是:
const char *p = "string";
另外,需要使用strlen()
函数,而不是sizeof
才能找到字符串的大小,因为sizeof
运算符只会给你指针变量的大小。
取决于用法。
注意:这不是C ++,但这是C特定的。 子>
请注意,使用不带const
关键字的字符串文字在C中完全有效。
但是,修改字符串文字仍然是C [Ref 2] 中的未定义行为。
这提出了一个有趣的问题,
What is the difference between char* and const char* when used with string literals in C?
Standerdese粉丝:
[参考1] C ++ 03标准:§4.2/ 2
不是宽字符串文字的字符串文字(2.13.4)可以转换为“指向字符的指针”的右值;可以将宽字符串文字转换为“指向wchar_t的指针”类型的右值。在任何一种情况下,结果都是指向数组第一个元素的指针。仅当存在明确的适当指针目标类型时才考虑此转换,而不是在通常需要从左值转换为右值时。 [注意:此转化已弃用。见附录D.]为了在重载决策(13.3.3.1.1)中进行排序,这种转换被认为是一个数组到指针的转换,然后是一个限定转换(4.4)。 [示例:“abc”转换为“指向const char的指针”作为数组到指针的转换,然后转换为“指向char的指针”作为限定转换。 ]
C ++ 11简单地删除了上述引用,这意味着它在C ++ 11中是非法代码。
[参考2] C99标准6.4.5 / 5“字符串文字 - 语义”:
在转换阶段7中,将值为零的字节或代码附加到由字符串文字或文字产生的每个多字节字符序列。然后使用多字节字符序列初始化静态存储持续时间和长度的数组,该数组足以包含序列。对于字符串文字,数组元素的类型为char,并使用多字节字符序列的各个字节进行初始化;对于宽字符串文字,数组元素的类型为wchar_t,并使用宽字符序列进行初始化...
如果这些数组的元素具有适当的值,则未指定这些数组是否相同。 如果程序试图修改此类数组,则行为未定义。
答案 1 :(得分:84)
第一个是数组,另一个是指针。
数组声明
char a[6];
请求留出六个字符的空格,名称为a
。也就是说,有一个名为a
的位置,可以坐6个字符。另一方面,指针声明char *p;
请求一个持有指针的地方。指针将以名称p
为人所知,并且可以指向任何字符串(或连续的字符数组)。陈述
char a[] = "string"; char *p = "string";
将导致数据结构可以表示如下:
+---+---+---+---+---+---+----+ a: | s | t | r | i | n | g | \0 | +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g |\0 | +-----+ +---+---+---+---+---+---+---+
重要的是要意识到像
x[3]
这样的引用会根据x
是数组还是指针生成不同的代码。鉴于上面的声明,当编译器看到表达式a[3]
时,它会发出代码从位置a
开始,移动三个元素,然后在那里获取字符。当它看到表达式p[3]
时,它会发出代码从位置p
开始,在那里获取指针值,向指针添加三个元素大小,最后获取指向的字符。在上面的示例中,a[3]
和p[3]
恰好都是字符l
,但编译器以不同的方式实现。
答案 2 :(得分:12)
char a[] = "string";
这会在堆栈上分配字符串。
char *p = "string";
这会在堆栈上创建一个指针,指向进程数据段中的文字。
?
是谁写的,不知道他们在做什么。
答案 3 :(得分:7)
堆栈,堆,数据段(和BSS)和文本分段是进程内存的四个段。定义的所有局部变量都将在堆栈中。使用malloc
和calloc
的动态分配的内存将在堆中。所有全局变量和静态变量都将在数据段中。文本段将包含程序的汇编代码和一些常量。
在这4个部分中,文本片段是READ ONLY
片段,其他三个片段中的READ
和WRITE
。
char a[] = "string";
- 这个statemnt将在堆栈中为7个字节分配内存(因为本地变量)并且它将保留所有6个字符(s, t, r, i, n, g
)加上NULL字符(\0
)at结束。
char *p = "string";
- 这个语句将在堆栈中为4个字节(如果它是32位机器)分配内存(因为这也是一个局部变量)并且它将保存常量字符串的指针,其值为{ {1}}。这个6字节的常量字符串将在文本段中。这是一个恒定值。指针变量"string"
只指向该字符串。
现在p
(索引可以是0到5)表示,它将访问堆栈中该字符串的第一个字符。所以我们也可以在这个位置写作。 a[0]
。允许此操作,因为我们在堆栈中有a[0] = 'x'
访问权限。
但READ WRITE
会导致崩溃,因为我们只能p[0] = 'x'
访问文字广告。如果我们对文本段进行任何写操作,就会发生分段错误。
但是你可以改变变量READ
的值,因为它的局部变量在堆栈中。如下所示
p
这是允许的。这里我们将存储在指针变量char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);
中的地址更改为字符串p
的地址(同样start
也是文本段中的只读数据)。如果要修改start
中的值,请选择动态分配的内存。
*p
现在允许char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");
操作,因为现在我们正在写堆。
答案 4 :(得分:6)
char *p = "string";
创建一个指向只读内存的指针,其中存储了字符串文字"string"
。尝试修改p
指向的字符串会导致未定义的行为。
char a[] = "string";
创建一个数组并使用字符串文字"string"
初始化其内容。
答案 5 :(得分:3)
它们在存储内存方面存在差异。理想情况下,第二个应该使用const char *。
第一个
char buf[] = "hello";
创建一个足够大的自动缓冲区来保存字符并将它们复制(包括空终止符)。
第二个
const char * buf = "hello";
应该使用const并简单地创建一个指向内存的指针,该指针通常存储在静态空间中,修改它是非法的。
相反(你可以安全地修改第一个而不是第二个)的事实是,从函数返回第二个指针是安全的,但不是第一个。这是因为第二个将保留在函数范围之外的有效内存指针,第一个不会。
const char * sayHello()
{
const char * buf = "hello";
return buf; // valid
}
const char * sayHelloBroken()
{
char buf[] = "hello";
return buf; // invalid
}
答案 6 :(得分:1)
a
声明一个char
值数组 - 一个char
的数组,它将被终止。
p
声明一个指针,指向一个不可变的,终止的C字符串,其确切的存储位置是实现定义的。请注意,这应该是const
- 合格(例如const char *p = "string";
)。
如果使用std::cout << "a: " << sizeof(a) << "\np: " << sizeof(p) << std::endl;
将其打印出来,您会发现它们的大小不同(注意:值可能因系统而异):
a: 7
p: 8
这是什么?运营商?它是字符串的一部分还是具有某些特定含义?
char a[] = ?string?
我认为它们曾经是双引号"string"
,可能会转换为“智能引号”,然后无法在此过程中表示,并转换为?
。
答案 7 :(得分:0)
C和C ++具有非常相似的指针到数组关系......
我不能说出你要问的两个语句的确切内存位置,但我发现它们有趣且有用,可以理解char Pointer声明和char数组声明之间的一些区别。
为清楚起见:
C Pointer and Array relationship
我认为记住C和C ++中的数组一个常量指针到数组的第一个元素是很重要的。因此,您可以对阵列执行指针运算。
char * p =&#34; string&#34 ;; &lt; ---这是指向字符串的第一个地址的指针。
以下也是可能的:
char *p;
char a[] = "string";
p = a;
此时p现在引用a的第一个内存地址(第一个元素的地址)
所以* p ==&#39; s&#39;
*(p ++)==&#39; t&#39;等等。 (或*(p + 1)==&#39; t&#39;)
同样适用于:*(a ++)或*(a + 1)也等于&#39; t&#39;