char *和const char *之间的区别?


176

之间有什么区别

char* name

指向常量字符串文字,并且

const char* name

在C(不是C ++)中,“ 常量字符串文字” 是什么意思
gbulmer 2012年

1
... char * name可以指向常量字符串文字
Iceman 2012年

“常量字符串文字”中的常量是多余的,因为理论上所有字符串文字都是常量实体。可以使变量恒定或可变的内容。如果您尝试更改“名称”所指向字符的内容,则“ const”声明只会引发编译时错误
Cupcake

简单:“ char * name” name是指向char的指针,即,都可以在此处更改。“ const char * name”名称是指向const char的指针,即,指针可以更改,但char不能更改。
akD

从右到左阅读这些内容。
张佳鹏

Answers:


405

char*是指向可变可变指针字符/字符串。

const char*是指向不可变字符/字符串的可变指针。您不能更改此指针指向的位置的内容。此外,当您尝试这样做时,要求编译器提供错误消息。出于同样的原因,从转换为const char *char*已被弃用。

char* const是一个不变的指针(它不能指向任何其他位置),但是它所指向的位置的内容是可变的

const char* const是指向不可变字符/字符串的不可变指针。


4
通过在上述语句之后使用变量并引用该变量,可以消除混乱。
2013年

3
@ ankit.karwasra,您又错过了一个:char const *
Pacerier

我认为带有可变字符/字符串的两个选项非常危险,因为您可以进行隔离错误存储,如果您真的很聪明,则可以对计算机进行黑客攻击。这就是为什么编译器在我认为的那些实现中始终显示警告的原因
Daniel N.

1
char *运行时不会突变给细分带来错误吗?
Divyanshu Maithani

1
因此,const如果我忘记并错误地更改了数据,我是否希望编译器给出错误信息,对吧?
会计م'19

43
char *name

您可以更改name指向的字符以及指向的字符。

const char* name

您可以更改name指向的字符,但是不能修改指向的字符。
更正:您可以更改指针,但不能更改指向的字符namehttps://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx,请参见“示例” )。在这种情况下,说明const符适用于char,而不星号。

根据MSDN页面和http://en.cppreference.com/w/cpp/language/declarationsconst之前的*是decl-specifier序列的一部分,而const之后*是声明符的一部分。
声明说明符序列后面可以有多个声明符,这就是为什么const char * c1, c2声明c1as const char *c2as的原因const char

编辑:

从注释中,您的问题似乎是在询问指针指向字符串文字时两个声明之间的差异。

在这种情况下,您不应将char修改为要name指向的字符,因为这可能会导致Undefined Behavior。可以在只读存储区(定义的实现)中分配字符串文字,并且用户程序无论如何都不应对其进行修改。尝试这样做会导致未定义的行为。

因此,在这种情况下(与字符串文字一起使用)的唯一区别是第二个声明为您带来了一点优势。如果您试图在第二种情况下修改字符串文字,则编译器通常会向您发出警告。

在线示例示例:

#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;
}

输出:

cc1:警告被视为错误
prog.c:在函数'main'中:
prog.c:9:错误:传递'strcpy'的参数1会从指针目标类型中丢弃限定符

请注意,编译器会针对第二种情况发出警告,但不会针对第一种情况发出警告。


谢谢..我正在与常量字符串常量混合使用,常量常量常量定义为:char * name =“ String Literal”; 更改“字符串文字”未定义..
冰人

@ user1279782:嗯,等等!您是否在这里谈论指向字符串文字的指向?在这种情况下,无论哪种情况都不应修改name指向的字符,这可能会导致UB。
Alok Save 2012年

是的,这就是重点。因此,在那种情况下,char *名称和const char *名称的行为类似,对吗?
Iceman'3

4
这个答案要么是非常模棱两可的,要么是完全错误的。我将解释为“您不能更改名称所指向的字符,但可以修改其所指向的字符”。由于不能够修改指针本身,而是能够修改所述存储器位置它指向,这是不正确的:ideone.com/6lUY9s备选地为纯C:ideone.com/x3PcTP
shroudednight

1
@shroudednight:您需要了解有关未定义行为的更多信息,并且需要区分:允许和不应该做。:)
Alok保存

16
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

1
根据问题,您的指针都没有指向“常量字符串文字”。
caf 2012年

值得注意的是,更改char *值会导致分段错误,因为我们正在尝试修改字符串文字(只读内存中存在)
Divyanshu Maithani

10

无论哪种情况,都不能修改字符串文字,无论指向该字符串文字的指针是声明为char *还是const char *

但是,不同之处在于,如果指针是指针,const char *则如果您尝试修改指向的值,则编译器必须给出诊断,而如果指针是指针,则编译器必须给出诊断char *


1
“无论在哪种情况下都不能修改字符串文字,无论... [it]是声明为char *还是const char *”,我同意程序员不应该尝试,但是您是说每个C编译器在每个平台会拒绝代码,安排代码在运行时失败还是其他原因?我相信,一个文件可能具有定义和初始化,而另一个文件可能包含extern ... name并且具有*name = 'X';。在“适当的操作系统”上,这可能会失败,但是在嵌入式系统上,我希望它能够执行特定于平台/编译器的操作。
gbulmer 2012年

@gbulmer:您不能在正确的C程序中修改字符串文字。尝试的不正确的C程序可能导致的结果不在这里或那里。
caf 2012年

@gbulmer:一个有用的定义是程序,它不会破坏C语言标准指定的任何约束。换句话说,修改字符串文字的程序与引用空指针或执行0除法的程序是不正确的。
caf 2012年

咖啡馆-我认为这可能就是您的意思。然后,“在任何情况下不能修改字符串文字”似乎过于夸大了。准确地说:“在两种情况下,C语言标准所指定的约束都已被破坏,无论如何……。编译器或运行时系统不可能在所有情况下都识别出违反标准的情况。” 我认为标准的作用是不确定的?
gbulmer 2012年

1
当标准无法以任何方式断言任何事情时,我认为将行为定义为“未定义”似乎恰好是正确的界限,并且很有帮助。断言关系的“正确的C计划”“ 无法提领一空指针”的声音等同于证明停机问题。但是我不介意。我不会这样做,并希望摆脱它的“无斯科特” :-)
gbulmer 2012年

4

情况1:

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

上面的设置str指向文本值“ Hello”,该值在程序的二进制映像中进行了硬编码,并在内存中标记为只读,这意味着对该String文本进行的任何更改都是非法的,并且会引发分段错误。

情况2:

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

情况3:

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

2

如果需要,您可以实际更改第一个,而第二个则不能。阅读有关const正确性的信息(有一些关于差异的不错的指南)。还有一些char const * name您无法重新指定的地方。


究竟可以改变什么?
安蒂·哈帕拉

2

问题是,两者之间有什么区别

char *name

指向常量字符串文字,并且

const char *cname

即给出

char *name = "foo";

const char *cname = "foo";

两者之间没有太大差异,两者都可以视为正确。由于C代码的悠久历史,字符串文字的类型为char[],而不是,即使不修改参数,const char[]很多旧代码也可以接受char *代替const char *

一般而言,2的主要区别是*cnamecname[n]将求值为类型的左值const char,而*namename[n]会求值为类型的左值char,它们是可修改的左值。如果分配的目标不是可修改的左值,则需要合格的编译器产生诊断消息; 它不需要在对类型为lvalue的赋值时产生任何警告char

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

在两种情况下都不需要编译器停止编译。产生一个警告,足以警告分配给cname[0]。生成的程序不是正确的程序。构造的行为是不确定的。它可能崩溃,甚至更糟,它可能不会崩溃,并且可能会更改内存中的字符串文字。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.