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

如标题所示,有什么区别

char a[] = ?string?; and char *p = ?string?; 

这个问题是在面试时问我的。 我甚至不明白这个说法。

 char a[] = ?string? 

这是什么? 运营商? 它是一个string的一部分,还是有一些特定的含义?

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

数组声明char a[6]; 要求留出6个字符的空间,以名字a 。 也就是说,有一个名字为a的位置,可以放六个字符。 指针声明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是数组还是指针产生不同的代码是很重要的。 给定上面的声明,当编译器看到expression式a[3] ,它会发出代码,从位置a开始,移动三个元素,并在那里获取字符。 当它看到expression式p[3] ,它会发出代码,从位置p开始,在那里获取指针值,向指针添加三个元素大小,最后获取指向的字符。 在上面的例子中, a[3]p[3]碰巧都是字符l ,但是编译器不同。

资料来源: comp.lang.c常见问题列表·问题6.2

这个? 似乎是一个错字,它不是语义上的有效。 所以答案是假设? 是一个错字,并解释了可能是面试官实际上要问的。


两者截然不同,首先是:

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

阅读更详细的解释:

arrays版本:

 char a[] = "string"; 

创build一个足够大的数组来保存stringstring“string”,包括NULL终止符。 数组string使用stringstring“string”进行初始化。 该数组可以稍后修改 。 此外,数组的大小即使在编译时也是已知的,所以sizeof运算符可以用来确定它的大小。


指针版本:

 char *p = "string"; 

创build一个指向string文字“string”的指针。 这比数组版本快, 但指针指向的string不应该被改变 ,因为它位于只读的实现定义的内存中。 修改这样的string会导致未定义的行为

实际上C ++ 03弃用了[Ref 1]没有使用const关键字的string。 所以声明应该是:

 const char *p = "string"; 

另外,你需要使用strlen()函数,而不是sizeof来查找string的大小,因为sizeof运算符只会给你指针variables的大小。


哪个版本更好,哪个版本可以使用?

取决于使用情况。

  • 如果不需要对string进行任何更改,请使用指针版本。
  • 如果您打算更改数据,请使用arrays版本。

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

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

这提出了一个有趣的问题,
与C中的string文字一起使用时,char *和const char *有什么区别?


对于Standerdese粉丝:
[参考文献1] C ++ 03标准:§4.2/ 2

不是宽string文字的string文字(2.13.4)可以转换为“指向char的指针”types的右值。 一个宽string文字可以被转换为“指向wchar_t的指针”types的右值。 无论哪种情况,结果都是指向数组的第一个元素的指针。 只有在有明确的适当的指针目标types时,才会考虑这种转换,而不是当一般需要将左值转换为右值时。 [ 注意:此转换已被弃用 。 见附录D.]为了在重载分辨率(13.3.3.1.1)中进行sorting,这个转换被认为是一个数组到指针的转换,然后是一个资格转换(4.4)。 [例如:“abc”被转换为“指向const char的指针”,作为数组到指针的转换,然后到“指向char的指针”作为限定转换。 ]

C ++ 11只是删除上面的引用,这意味着它是C ++ 11中的非法代码。

[参考2] C99标准6.4.5 / 5“string文字 – 语义”:

在翻译阶段7,一个字节或值为零的代码被附加到每个多字节字符序列,这是由一个或多个string产生的。 然后使用多字节字符序列来初始化静态存储持续时间和长度的数组,以便足以包含该序列。 对于string文字,数组元素的types为char,并且用多字节字符序列的单个字节进行初始化; 对于宽string文字,数组元素的types为wchar_t,并用宽字符序列初始化…

没有说明这些数组是否是不同的,只要它们的元素具有适当的值。 如果程序试图修改这样一个数组,行为是不确定的。

 char a[] = "string"; 

这将分配堆栈上的string。

 char *p = "string"; 

这会在堆栈上创build一个指向进程数据段文字的指针。

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

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

在这4个段中,文本段是READ ONLY段,其余三个段是READWRITE

char a[] = "string"; – 这个statemnt会为堆栈中的7个字节(因为是局部variables)分配内存,并且会在最后保留所有6个字符( s, t, r, i, n, g )加NULL字符( \0 )。

char *p = "string"; – 这个语句将为堆栈中的4个字节(如果是32位的机器)分配内存(因为这也是一个局部variables),它将保存值为"string"的常量string的指针。 这6个字节的常量string将在文本段中。 这是一个恒定的价值。 指针variablesp只是指向那个string。

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

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

但是你可以改变variablesp的值,因为它的局部variables在栈中。 如下所示

 char *p = "string"; printf("%s", p); p = "start"; printf("%s", p); 

这是允许的。 这里我们改变存储在指针variablesp中的地址作为stringstart地址(再次start也是文本段中的只读数据)。 如果你想修改*p值,就意味着去dynamic分配内存。

 char *p = NULL; p = malloc(sizeof(char)*7); strcpy(p, "string"); 

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

char *p = "string"; 创build一个指向存储stringstring"string"只读存储器的指针。 试图修改string,指出导致未定义的行为。

char a[] = "string"; 创build一个数组并通过使用stringstring"string"来初始化它的内容。

它们在内存的存储位置上有所不同。 理想情况下,第二个应该使用const char *。

第一个

 char buf[] = "hello"; 

创build一个足够大的自动缓冲区来保存字符并将其复制(包括空终止符)。

第二个

 const char * buf = "hello"; 

应该使用const,并简单地创build一个指向通常存储在静态空间的内存中的指针,以修改它是非法的。

相反的(你可以安全地修改第一个,而不是第二个)的事实是从函数返回第二个指针是安全的,但不是第一个。 这是因为第二个将保持有效的内存指针超出函数的范围,第一个不会。

 const char * sayHello() { const char * buf = "hello"; return buf; // valid } const char * sayHelloBroken() { char buf[] = "hello"; return buf; // invalid } 

a声明char数组的数组 – 一个char数组被终止。

p声明了一个指针,指向一个不可变的,终止的Cstring,其确切的存储位置是实现定义的。 请注意,这应该是const限定的(例如const char *p = "string"; )。

如果使用std::cout << "a: " << sizeof(a) << "\np: " << sizeof(p) << std::endl; ,你会看到他们的大小差异(注:价值可能会因系统而异):

 a: 7 p: 8 

这是什么? 运营商? 它是一个string的一部分,还是有一些特定的含义?

 char a[] = ?string? 

我假设他们曾经有过双引号的"string" ,有可能被转换为“精明的引号”,那么就不能一直这样表示,转换成?

C和C ++有非常相似的指针数组关系…

我不能说出你所询问的两个语句的确切内存位置,但是我发现他们的文章对于理解char指针声明和char数组声明之间的一些区别很有意思。

为了清楚:

C指针和数组的关系

指向数组的C ++指针

我认为重要的是要记住,C和C ++中的数组是一个指向数组第一个元素的常量指针 。 因此你可以在数组上执行指针运算。

char * p =“string”; <—这是一个指向string的第一个地址的指针。

以下也是可能的:

 char *p; char a[] = "string"; p = a; 

此时,p现在引用第一个内存地址(第一个元素的地址)

所以* p =='s'

*(p ++)=='t'等。 (或*(p + 1)=='t')

而同样的事情会对a:*(a ++)或*(a + 1)也等于't'

char [] arr =“hello”; char * p =“hello”;

现在我们可以做arr [2] ='x';

但是p [2] ='c'会产生运行时错误:)