char a [] =?string?有什么区别?和char*p =?string?;?

Sac*_*tre 47 c++ pointers

正如标题所说,有什么区别

char a[] = ?string?; and 
char *p = ?string?;  
Run Code Online (Sandbox Code Playgroud)

这个问题在接受我采访时被问到了.我甚至不理解这个说法.

char a[] = ?string?
Run Code Online (Sandbox Code Playgroud)

什么是?运营商?它是字符串的一部分还是具有某些特定含义?

Alo*_*ave 91

?似乎是一个错字,它在语义上是无效的.所以答案假定这?是一个拼写错误并解释了面试官可能要提出的问题.


一开始,两者都截然不同:

  1. 第一个创建一个指针.
  2. 第二个创建一个数组.

继续阅读以获得更详细的解释:

阵列版本:

char a[] = "string";  
Run Code Online (Sandbox Code Playgroud)

创建一个足以容纳字符串文字"string"的数组,包括其NULL终结符.string使用字符串文字"string"初始化数组.可以在以后修改该阵列.此外,即使在编译时也可以知道数组的大小,因此sizeof可以使用运算符来确定其大小.


指针版本:

char *p  = "string"; 
Run Code Online (Sandbox Code Playgroud)

创建指向字符串文字"string"的指针.这比数组版本快,但指针指向的字符串不应更改,因为它位于只读实现定义的内存中.修改此类字符串文字会导致未定义的行为.

事实上,C++ 03不赞成[Ref 1]使用不带const关键字的字符串文字.声明应该是:

const char *p = "string";
Run Code Online (Sandbox Code Playgroud)

此外,您需要使用该strlen()函数,而不是sizeof查找字符串的大小,因为sizeof运算符将只给出指针变量的大小.


哪个版本更好,我应该使用哪个版本?

取决于用法.

  • 如果您不需要对字符串进行任何更改,请使用指针版本.
  • 如果要更改数据,请使用阵列版本.

注意:这不是C++,但这是C特定的.

请注意,使用不带const关键字的字符串文字在C中完全有效.但是,修改字符串文字仍然是C [参考文献2]中的未定义行为.

这提出了一个有趣的问题,
当在C中使用字符串文字时,char*和const char*之间有什么区别?


对于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,并使用宽字符序列进行初始化...

如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的.如果程序试图修改此类数组,则行为未定义.

  • 对downvote的任何技术推理都非常感谢. (2认同)

小智 84

第一个是数组,另一个是指针.

数组声明char a[6];请求留出六个字符的空格,以便通过名称来识别a.也就是说,有一个名为a六个字符的位置.char *p;另一方面,指针声明请求一个持有指针的地方.指针将通过名称p来识别,并且可以指向任何位置的任何char(或连续的chars数组).

声明

 char a[] = "string";
 char *p = "string"; 
Run Code Online (Sandbox Code Playgroud)

会导致数据结构可以表示如下:

     +---+---+---+---+---+---+----+
  a: | s | t | r | i | n | g | \0 |
     +---+---+---+---+---+---+----+
     +-----+     +---+---+---+---+---+---+---+ 
  p: |  *======> | s | t | r | i | n | g |\0 |    
     +-----+     +---+---+---+---+---+---+---+ 
Run Code Online (Sandbox Code Playgroud)

重要的是要意识到引用类似于x[3]根据x数组还是指针生成不同的代码.鉴于上面的声明,当编译器看到表达式时a[3],它会发出代码从该位置开始a,移动三个元素,然后在那里获取字符.当它看到表达式时p[3],它会发出代码从该位置开始,在p那里获取指针值,向指针添加三个元素大小,最后获取指向的字符.在上面的例子中,无论是a[3]p[3]碰巧是性格l,但是编译器到达那里不同.

资料来源:comp.lang.c常见问题清单·问题6.2


Ign*_*ams 12

char a[] = "string";
Run Code Online (Sandbox Code Playgroud)

这会在堆栈上分配字符串.

char *p = "string";
Run Code Online (Sandbox Code Playgroud)

这会在堆栈上创建一个指针,指向进程数据段中的文字.

? 是谁写的不知道他们在做什么.

  • 鉴于问题是要求有关微不足道的细节,我认为答案应该更深入地探讨可能性.具体来说,"`char a []`...在堆栈上分配..."假设它在函数内而不是全局,并且进一步引用`a []`而没有提到函数内部实际上是一个运行 - 从常量数据段到堆栈的整个文本的时间副本.`char*`用法创建一个非`constst`指针 - 在堆栈上或作为数据段中的全局 - 并在运行时或(可能)编译时分别初始化它以解决const文本. (5认同)
  • @VJovic:确实如此.在C++ 03中不推荐使用没有`const`限定符的指向字符串文字的指针,所以第二个片段不是合法的C++代码. (2认同)

ras*_*hok 7

堆栈,堆,数据段(和BSS)和文本分段是进程内存的四个部分.定义的所有局部变量都将在堆栈中.动态分配的内存使用malloccalloc将在堆中.所有全局变量和静态变量都将在数据段中.文本段将包含程序的汇编代码和一些常量.

在这4个部分中,文本段是READ ONLY段,而在所有其他三个段中是READWRITE.

char a[] = "string";- 这个statemnt将在堆栈中为7个字节分配内存(因为局部变量)并且它将在末尾保留所有6个字符(s, t, r, i, n, g)和NULL字符(\0).

char *p = "string";- 这个语句将在堆栈中为4个字节(如果它是32位机器)分配内存(因为这也是一个局部变量)并且它将保存值为的常量字符串的指针"string".这个6字节的常量字符串将在文本段中.这是一个恒定值.指针变量p只指向该字符串.

现在a[0](索引可以是0到5)表示,它将访问堆栈中该字符串的第一个字符.所以我们也可以在这个位置写作.a[0] = 'x'.允许此操作,因为我们具有READ WRITE堆栈访问权限.

但是p[0] = 'x'会导致崩溃,因为我们只能READ访问文本分段.如果我们对文本段进行任何写操作,将发生分段错误.

但是你可以改变变量的值p,因为它的局部变量在栈中.如下

char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);
Run Code Online (Sandbox Code Playgroud)

这是允许的.这里我们将存储在指针变量p中的地址更改为字符串的地址start(同样start也是文本段中的只读数据).如果要修改存在的值,*p请转到动态分配的内存.

char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");
Run Code Online (Sandbox Code Playgroud)

现在p[0] = 'x'允许操作,因为现在我们正在写堆.


Lih*_*ihO 6

char *p = "string";创建一个指向只读存储器的指针,其中"string"存储了字符串文字.尝试修改p指向导致未定义行为的字符串.

char a[] = "string";创建一个数组并使用字符串文字初始化其内容"string".