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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9460260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:52:12  来源:igfitidea点击:

What is the difference between char a[] = ?string?; and char *p = ?string?;?

c++pointers

提问by Sachin Mhetre

As the heading says, What is the difference between

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

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

This question was asked to me in interview. I even dont understand the statement.

这个问题是面试时问我的。我什至不明白这句话。

char a[] = ?string?

Here what is ?operator? Is it a part of a string or it has some specific meaning?

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

回答by Alok Save

The ?seems to be a typo, it is not semantically valid. So the answer assumes the ?is a typo and explains what probably the interviewer actually meant to ask.

?似乎是一个错字,它在语义上无效。所以答案假设这?是一个错字,并解释了面试官可能真正想问的问题。



Both are distinctly different, for a start:

首先,两者明显不同:

  1. The first creates a pointer.
  2. The second creates an array.
  1. 第一个创建一个指针。
  2. 第二个创建一个数组。

Read on for more detailed explanation:

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

The Array version:

阵列版本:

char a[] = "string";  

Creates an array that is large enough to hold the string literal "string", including its NULLterminator. The array stringis initialized with the string literal "string". The array can be modified at a later time. Also, the array's size is known even at compile time, so sizeofoperator can be used to determine its size.

创建一个足够大的数组以容纳字符串文字“string”,包括其NULL终止符。该数组string使用字符串文字“string”进行初始化。该数组可以在以后修改。此外,即使在编译时,数组的大小也是已知的,因此sizeof可以使用运算符来确定其大小。



The pointer version:

指针版本:

char *p  = "string"; 

Creates a pointer to point to a string literal "string". This is faster than the array version, but string pointed by the pointer should not be changed, because it is located in a read only implementation-defined memory. Modifying such an string literal results in Undefined Behavior.

创建一个指向字符串文字“string”的指针。这比数组版本快,但不应更改指针指向的字符串,因为它位于只读实现定义的内存中。修改这样的字符串文字会导致Undefined Behavior

In fact C++03 deprecates[Ref 1]use of string literal without the constkeyword. So the declaration should be:

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

const char *p = "string";

Also,you need to use the strlen()function, and not sizeofto find size of the stringsince the sizeofoperator will just give you the size of the pointer variable.

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



Which version is better and which one shall I use?

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

Depends on the Usage.

取决于用法。

  • If you do not need to make any changes to the string, use the pointer version.
  • If you intend to change the data, use the array version.
  • 如果不需要对字符串进行任何更改,请使用指针版本。
  • 如果您打算更改数据,请使用阵列版本。


Note:This is a not C++ but this is C specific.

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

Note that, use of string literal without the constkeyword is perfectly valid in C. However, modifying a string literal is still an Undefined Behavior in C[Ref 2].

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

This brings up an interesting question,
What is the difference between char* and const char* when used with string literals in C?

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



For Standerdese Fans:
[Ref 1]C++03 Standard: §4.2/2

对于 Standerdese 粉丝:
[Ref 1] C++03 标准:§4.2/2

A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ] For the purpose of ranking in overload resolution (13.3.3.1.1), this conversion is considered an array-to-pointer conversion followed by a qualification conversion (4.4). [Example: "abc" is converted to “pointer to const char” as an array-to-pointer conversion, and then to “pointer to char” as a qualification conversion. ]

不是宽字符串文字的字符串文字 (2.13.4) 可以转换为“指向 char 的指针”类型的右值;宽字符串文字可以转换为“指向 wchar_t 的指针”类型的右值。无论哪种情况,结果都是指向数组第一个元素的指针。仅当存在显式适当的指针目标类型时才考虑这种转换,而不是一般需要将左值转换为右值时。[注意:不推荐使用此转换. 参见附录 D。] 为了在重载决议 (13.3.3.1.1) 中进行排名,此转换被视为数组到指针的转换,然后是限定转换 (4.4)。[示例:将“abc”转换为“指向const char的指针”作为数组到指针的转换,然后作为限定转换转换为“指向char的指针”。]

C++11 simply removes the above quotation which implies that it is illegal code in C++11.

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

[Ref 2]C99 standard 6.4.5/5 "String Literals - Semantics":

[参考 2] C99 标准 6.4.5/5“字符串文字 - 语义”:

In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence; for wide string literals, the array elements have type wchar_t, and are initialized with the sequence of wide characters...

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

在转换阶段 7 中,将一个字节或值为零的代码附加到由一个或多个字符串文字产生的每个多字节字符序列。然后使用多字节字符序列初始化一个静态存储持续时间和长度刚好足以包含该序列的数组。对于字符串文字,数组元素具有 char 类型,并使用多字节字符序列的各个字节进行初始化;对于宽字符串文字,数组元素具有 wchar_t 类型,并使用宽字符序列进行初始化...

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

回答by Alok Save

The first one is array the other is pointer.

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

The array declaration char a[6];requests that space for six characters be set aside, to be known by the name a. That is, there is a location named aat which six characters can sit. The pointer declaration char *p;on the other hand, requests a place which holds a pointer. The pointer is to be known by the name p, and can point to any char (or contiguous array of chars) anywhere.

The statements

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

would result in data structures which could be represented like this:

     +---+---+---+---+---+---+----+
  a: | s | t | r | i | n | g | 
 char a[] = "string";
 char *p = "string"; 
| +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g |
     +---+---+---+---+---+---+----+
  a: | s | t | r | i | n | g | 
char a[] = "string";
| +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g |
char *p = "string";
| +-----+ +---+---+---+---+---+---+---+
| +-----+ +---+---+---+---+---+---+---+

It is important to realize that a reference like x[3]generates different code depending on whether xis an array or a pointer. Given the declarations above, when the compiler sees the expression a[3], it emits code to start at the location a, move three elements past it, and fetch the character there. When it sees the expression p[3], it emits code to start at the location p, fetch the pointer value there, add three element sizes to the pointer, and finally fetch the character pointed to. In the example above, both a[3]and p[3]happen to be the character l, but the compiler gets there differently.

数组声明char a[6];要求留出六个字符的空间,以 name 表示a。也就是说,有一个位置a可以坐六个字符。char *p;另一方面,指针声明请求一个存放指针的位置。指针以 name 为已知p,并且可以指向任何地方的任何字符(或连续的字符数组)。

声明

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

将导致可以这样表示的数据结构:

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

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

Source: comp.lang.c FAQ list · Question 6.2

来源:comp.lang.c FAQ列表·问题6.2

回答by Ignacio Vazquez-Abrams

char buf[] = "hello";

This allocates the string on the stack.

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

const char * buf = "hello";

This creates a pointer on the stack that points to the literal in the data segment of the process.

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

?is whoever wrote it not knowing what they were doing.

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

回答by rashok

Stack, heap, datasegment(and BSS) and text segement are the four segments of process memory. All the local variables defined will be in stack. Dynmically allocated memory using mallocand callocwill be in heap. All the global and static variables will be in data segment. Text segment will have the assembly code of the program and some constants.

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

In these 4 segements, text segment is the READ ONLYsegment and in the all the other three is for READand WRITE.

在这 4 个段中, text 段是READ ONLY段,其他三个段是 forREADWRITE

char a[] = "string";- This statemnt will allocate memory for 7 bytes in stack(because local variable) and it will keep all the 6 characters(s, t, r, i, n, g) plus NULL character (\0) at the end.

char a[] = "string";- 此语句将在堆栈中为 7 个字节分配内存(因为是局部变量),并且将保留所有 6 个字符 ( s, t, r, i, n, g) 加上\0末尾的NULL 字符 ( )。

char *p = "string";- This statement will allocate memory for 4 bytes(if it is 32 bit machine) in stack(because this is also a local variable) and it will hold the pointer of the constant string which value is "string". This 6 byte of constant string will be in text segment. This is a constant value. Pointer variable pjust points to that string.

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

Now a[0](index can be 0 to 5) means, it will access first character of that string which is in stack. So we can do write also at this position. a[0] = 'x'. This operation is allowed because we have READ WRITEaccess in stack.

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

But p[0] = 'x'will leads to crash, because we have only READaccess to text segement. Segmentation fault will happen if we do any write on text segment.

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

But you can change the value of variable p, because its local variable in stack. like below

但是你可以改变 variable 的值p,因为它在堆栈中的局部变量。像下面

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

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

This is allowed. Here we are changing the address stored in the pointer variable pto address of the string start(again startis also a read only data in text segement). If you want to modify values present in *pmeans go for dynamically allocated memory.

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

a: 7
p: 8

Now p[0] = 'x'operation is allowed, because now we are writing in heap.

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

回答by LihO

char *p = "string";creates a pointer to read-only memory where string literal "string"is stored. Trying to modify string that ppoints to leads to undefined behaviour.

char *p = "string";创建一个指向存储字符串文字的只读内存的指针"string"。尝试修改p指向的字符串会导致未定义的行为。

char a[] = "string";creates an array and initializes its content by using string literal "string".

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

回答by CashCow

They do differ as to where the memory is stored. Ideally the second one should use const char *.

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

The first one

第一个

char a[] = ?string?

creates an automatic buffer big enough to hold the characters and copies them in (including the null terminator).

创建一个足够大的自动缓冲区来容纳字符并将它们复制进去(包括空终止符)。

The second one

第二个

char a[] = ?string?

should use const and simply creates a pointer that points at memory usually stored in static space where it is illegal to modify it.

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

The converse (of the fact you can modify the first safely and not the second) is that it is safe to return the second pointer from a function, but not the first. This is because the second one will remain a valid memory pointer outside the scope of the function, the first will not.

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

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

p = a; 

回答by justin

adeclares an array of charvalues -- an array of chars which is terminated.

a声明一个char值数组——一个char终止的s数组。

pdeclares a pointer, which refers to an immutable, terminated, C string, whose exact storage location is implementation-defined. Note that this should be const-qualified (e.g. const char *p = "string";).

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

If you print it out using std::cout << "a: " << sizeof(a) << "\np: " << sizeof(p) << std::endl;, you will see differences their sizes (note: values may vary by system):

如果使用 打印出来std::cout << "a: " << sizeof(a) << "\np: " << sizeof(p) << std::endl;,您会看到它们的大小不同(注意:值可能因系统而异):

##代码##

Here what is ? operator? Is it a part of a string or it has some specific meaning?

##代码##

这里是什么?操作员?它是字符串的一部分还是具有某些特定含义?

##代码##

I assume they were once double quotes "string", which potentially were converted to "smart quotes", then could not be represented as such along the way, and were converted to ?.

我假设它们曾经是双引号"string",它们可能被转换为“智能引号”,然后在此过程中无法这样表示,并被转换为?.

回答by meltdownmonk

C and C++ have very similar Pointer to Array relationships...

C 和 C++ 具有非常相似的指针到数组关系......

I can't speak for the exact memory locations of the two statements you are asking about, but I found they articles interesting and useful for understanding some of the differences between the char Pointer declaration, and a char Array declaration.

我无法说明您所询问的两个语句的确切内存位置,但我发现它们的文章很有趣且有助于理解 char 指针声明和 char 数组声明之间的一些差异。

For clarity:

为清楚起见:

C Pointer and Array relationship

C指针和数组的关系

C++ Pointer to an Array

C++ 指向数组的指针

I think it's important to remember that an array, in C and C++, is a constant pointerto the first element of the array. And consequently you can perform pointer arithmetic on the array.

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

char *p = "string"; <--- This is a pointer that points to the first address of a character string.

char *p = "字符串"; <--- 这是一个指向字符串首地址的指针。

the following is also possible:

以下也是可能的:

##代码##

At this point p now references the first memory address of a (the address of the first element)

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

and so *p == 's'

所以 *p == 's'

*(p++) == 't' and so on. (or *(p+1) == 't')

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

and the same thing would work for a: *(a++) or *(a+1) would also equal 't'

同样的事情也适用于 a: *(a++) 或 *(a+1) 也等于 't'