简体   繁体   English

char* 和 const char* 的区别?

[英]Difference between char* and const char*?

What's the difference between有什么区别

char* name

which points to a constant string literal, and它指向一个常量字符串文字,并且

const char* name

char* is a mutable pointer to a mutable character/string. char*是一个指向可变字符/字符串的可变指针。

const char* is a mutable pointer to an immutable character/string. const char*是指向不可变字符/字符串的可变指针。 You cannot change the contents of the location(s) this pointer points to.您不能更改此指针指向的位置的内容。 Also, compilers are required to give error messages when you try to do so.此外,当您尝试这样做时,编译器需要给出错误消息。 For the same reason, conversion from const char * to char* is deprecated.出于同样的原因,不推荐从const char *转换为char*

char* const is an immutable pointer (it cannot point to any other location) but the contents of location at which it points are mutable . char* const是一个不可变指针(它不能指向任何其他位置),它指向的 location 的内容是可变的

const char* const is an immutable pointer to an immutable character/string. const char* const是指向不可变字符/字符串的不可指针。

char *name

You can change the char to which name points, and also the char at which it points.您可以更改name指向的字符,以及它指向的字符。

const char* name

You can change the char to which name points, but you cannot modify the char at which it points. 您可以更改 name指向的字符,但不能修改它指向的字符。
correction: You can change the pointer, but not the char to which name points to ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , see "Examples").更正:您可以更改指针,但不能更改name指向的字符( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx ,请参阅“示例”)。 In this case, the const specifier applies to char , not the asterisk.在这种情况下, const说明符适用于char ,而不是星号。

According to the MSDN page and http://en.cppreference.com/w/cpp/language/declarations , the const before the * is part of the decl-specifier sequence, while the const after * is part of the declarator.根据 MSDN 页面和http://en.cppreference.com/w/cpp/language/declarations*之前的const是 decl-specifier 序列的一部分,而*之后的const是声明符的一部分。
A declaration specifier sequence can be followed by multiple declarators, which is why const char * c1, c2 declares c1 as const char * and c2 as const char .声明说明符序列后面可以跟多个声明符,这就是为什么const char * c1, c2 c1声明为const char *并将c2声明为const char

EDIT:编辑:

From the comments, your question seems to be asking about the difference between the two declarations when the pointer points to a string literal.从评论中,您的问题似乎是在询问指针指向字符串文字时两个声明之间的区别。

In that case, you should not modify the char to which name points, as it could result in Undefined Behavior .在这种情况下,您不应修改name指向的字符,因为它可能导致Undefined Behavior String literals may be allocated in read only memory regions (implementation defined) and an user program should not modify it in anyway.字符串文字可以在只读内存区域(实现定义)中分配,并且用户程序不应以任何方式修改它。 Any attempt to do so results in Undefined Behavior.任何这样做的尝试都会导致未定义行为。

So the only difference in that case (of usage with string literals) is that the second declaration gives you a slight advantage.所以在这种情况下(与字符串文字一起使用)的唯一区别是第二个声明给了你一点优势。 Compilers will usually give you a warning in case you attempt to modify the string literal in the second case.如果您尝试在第二种情况下修改字符串文字,编译器通常会向您发出警告。

Online Sample Example:在线示例示例:

#include <string.h>
int main()
{
    char *str1 = "string Literal";
    const char *str2 = "string Literal";
    char source[] = "Sample string";

    strcpy(str1,source);    //No warning or error, just Undefined Behavior
    strcpy(str2,source);    //Compiler issues a warning

    return 0;
}

Output:输出:

cc1: warnings being treated as errors cc1:警告被视为错误
prog.c: In function 'main': prog.c:在函数“main”中:
prog.c:9: error: passing argument 1 of 'strcpy' discards qualifiers from pointer target type prog.c:9:错误:传递“strcpy”的参数 1 会丢弃来自指针目标类型的限定符

Notice the compiler warns for the second case but not for the first.请注意,编译器会针对第二种情况发出警告,但不会针对第一种情况发出警告。

char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)

constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error

constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok

// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";

lcharp[0] = 'X';      // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error

// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X';          // compile error
((char*)astr)[0] = 'X'; // ok

In neither case can you modify a string literal, regardless of whether the pointer to that string literal is declared as char * or const char * .在这两种情况下,您都不能修改字符串文字,无论指向该字符串文字的指针是声明为char *还是const char *

However, the difference is that if the pointer is const char * then the compiler must give a diagnostic if you attempt to modify the pointed-to value, but if the pointer is char * then it does not.但是,不同之处在于,如果指针是const char *则编译器必须在您尝试修改指向的值时给出诊断信息,但如果指针是char *则不会。

CASE 1:情况1:

char *str = "Hello";
str[0] = 'M'  //Warning may be issued by compiler, and will cause segmentation fault upon running the programme

The above sets str to point to the literal value "Hello" which is hard-coded in the program's binary image, which is flagged as read-only in memory, means any change in this String literal is illegal and that would throw segmentation faults.上面将 str 设置为指向硬编码在程序二进制图像中的文字值“Hello”,在内存中标记为只读,这意味着此字符串文字的任何更改都是非法的,并且会引发分段错误。

CASE 2:案例2:

const char *str = "Hello";
str[0] = 'M'  //Compile time error

CASE 3:案例3:

char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".

The question is what's the difference between问题是两者有什么区别

char *name

which points to a constant string literal, and它指向一个常量字符串文字,和

const char *cname

Ie given即给定

char *name = "foo";

and

const char *cname = "foo";

There is not much difference between the 2 and both can be seen as correct. 2之间没有太大区别,两者都可以看作是正确的。 Due to the long legacy of C code, the string literals have had a type of char[] , not const char[] , and there are lots of older code that likewise accept char * instead of const char * , even when they do not modify the arguments.由于 C 代码的长期遗留,字符串文字具有char[]类型,而不是const char[] ,并且有许多旧代码同样接受char *而不是const char * ,即使它们不接受修改参数。

The principal difference of the 2 in general is that *cname or cname[n] will evaluate to lvalues of type const char , whereas *name or name[n] will evaluate to lvalues of type char , which are modifiable lvalues .两者的主要区别通常是*cnamecname[n]将计算为const char类型的左值,而*namename[n]将计算为char类型的左值,它们是可修改的左值 A conforming compiler is required to produce a diagnostics message if target of the assignment is not a modifiable lvalue ;如果赋值的目标不是可修改的左值,则需要符合标准的编译器来生成诊断消息; it need not produce any warning on assignment to lvalues of type char :它不需要在分配给char类型的左值时产生任何警告:

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostic message

The compiler is not required to stop the compilation in either case;在任何一种情况下,编译器都不需要停止编译; it is enough that it produces a warning for the assignment to cname[0] .它足以为cname[0]的赋值产生警告 The resulting program is not a correct program.生成的程序不是正确的程序。 The behaviour of the construct is undefined .构造的行为是undefined It may crash, or even worse, it might not crash, and might change the string literal in memory.它可能会崩溃,或者更糟糕的是,它可能不会崩溃,并且可能会更改内存中的字符串文字。

The first you can actually change if you want to, the second you can't.如果你愿意,第一个你实际上可以改变,第二个你不能。 Read up about const correctness (there's some nice guides about the difference).阅读有关const正确性的信息(有一些关于差异的很好的指南)。 There is also char const * name where you can't repoint it.还有char const * name ,你不能重新指出它。

Actually, char* name is not a pointer to a constant, but a pointer to a variable.实际上, char* name不是指向常量的指针,而是指向变量的指针。 You might be talking about this other question.您可能正在谈论另一个问题。

What is the difference between char * const and const char *? char * const 和 const char * 有什么区别?

I would add here that the latest compilers, VS 2022 for instance, do not allow char* to be initialized with a string literal.我要在这里补充一点,最新的编译器,例如 VS 2022,不允许使用字符串文字来初始化char* char* ptr = "Hello"; throws an error whilst const char* ptr = "Hello";抛出错误而const char* ptr = "Hello"; is legal.是合法的。

Just to give an extra example: 再举一个例子:

    std::cout << typeid(2.3).name() << '\n'; // -----> prints "double" simply because
    //2.3 is a double
    //But the "double" returned by typeid(2.3).name() is indeed a 
    //const char * which consists of 'd','o','u','b','l','e'and'\0'.
    //Here's a simple proof to this:
    std::cout << typeid(typeid(2.3).name()).name() << '\n'; //prints: "const char *"
    const char* charptr
    charptr = typeid(2.3).name();
    std::cout << charptr[3]; // --------->  prints: "b"

(I'm using the typeinfo library: http://www.cplusplus.com/reference/typeinfo/type_info/name ) (我正在使用typeinfo库: http ://www.cplusplus.com/reference/typeinfo/type_info/name)

    //Now let's do something more interesting:
    char* charptr2="hubble";
    strcpy(charptr, charptr2);  // --------> Oops! Sorry, this is not valid!

You can run it and see things better for yourself. 您可以运行它,并为自己找到更好的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM