【问题标题】:Difference between char* and const char*?char* 和 const char* 的区别?
【发布时间】:2012-04-07 17:02:30
【问题描述】:

有什么区别

char* name

指向一个常量字符串字面量,而

const char* name

【问题讨论】:

  • C(非 C++)中的“常量字符串文字”是什么意思
  • ... char *name 可以指向一个常量字符串字面量
  • “常量字符串文字”中的常量是多余的,因为理论上所有的字符串文字都是常量实体。变量的内容既可以是常量,也可以是可变的。如果您尝试更改“name”指向的字符的内容,“const”声明只会引发编译时错误
  • 简单:"char *name" name 是指向 char 的指针,即两者都可以在此处更改。 "const char *name" name 是指向 const char 的指针,即指针可以改变但不能改变 char。
  • 从右到左阅读这些内容。

标签: c pointers constants


【解决方案1】:

char* 是一个mutable 指针,指向一个mutable 字符/字符串。

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

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

const char* const 是一个不可变指针,指向一个不可变字符/字符串。

【讨论】:

  • 可以通过在上述语句之后使用变量并引用该变量来消除混淆。
  • @ankit.karwasra,你又错过了一个:char const *
  • 在运行时不会变异char * 给出分段错误?
  • 所以我使用const 如果我希望编译器在我忘记并错误更改数据时给出错误,对吧?
  • @DivyanshuMaithani 这取决于char * 的创建位置。例如:char *s = "A string""A string" 放入二进制文件的代码部分(RO 内存)。写入此内存段错误。但是char *s = malloc(sizeof(char) * 10) 在堆上分配内存,并且此内存部分是可写的,因此不会在写入时出现段错误。
【解决方案2】:
char *name

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

const char* name

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

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

编辑:

从 cmets 来看,您的问题似乎是在询问指针指向字符串文字时两个声明之间的区别。

在这种情况下,您不应修改name 指向的字符,因为这可能导致未定义行为。 字符串文字可以分配在只读内存区域(实现定义)中,用户程序无论如何都不应该修改它。任何这样做的尝试都会导致未定义的行为。

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

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

输出:

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

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

【讨论】:

  • 谢谢..我正在与常量字符串文字混合,其定义为: char* name = "String Literal";更改“字符串文字”未定义..
  • @user1279782:错误,等等!您是在谈论指向字符串文字的指针吗?在这种情况下,您不应该修改name在任何一种情况下指向的字符。这可能导致UB。
  • 是的,这就是重点。所以在这种情况下 char* name 和 const char* name 表现相似,对吧?
  • 这个答案要么非常模棱两可,要么完全错误。我会解释“您不能更改名称指向的字符,但您可以修改它指向的字符。”由于不能修改指针本身,但能够修改它指向的内存位置,这是不正确的:ideone.com/6lUY9s 或者纯 C:ideone.com/x3PcTP
  • @shroudednight:你需要了解更多关于未定义行为的知识,并且需要区分:允许和不应该做。 :)
【解决方案3】:
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

【讨论】:

  • 根据问题,您的指针都没有指向“常量字符串文字”。
  • 值得注意的是,更改 char * 值会导致分段错误,因为我们正在尝试修改字符串文字(存在于只读内存中)
【解决方案4】:

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

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

【讨论】:

  • "在这两种情况下,你都不能修改字符串文字,无论 ... [it] 是声明为 char * 还是 const char *" 我同意程序员不应该尝试,但你是说每个平台上的每个 C 编译器都会拒绝代码,安排代码在运行时失败,还是其他什么?我相信,一个文件可能有定义和初始化,另一个文件可能包含extern ... name*name = 'X';。在“正确的操作系统”上,这可能会失败,但在嵌入式系统上,我希望它能够做一些特定于平台/编译器的事情。
  • @gbulmer:您不能在正确的 C 程序中修改字符串文字。不正确的 C 程序尝试可能导致的结果既不存在也不存在。
  • @gbulmer:一个有用的定义是一个不破坏 C 语言标准规定的任何约束的程序。换句话说,修改字符串文字的程序是不正确的,就像取消引用空指针或执行除以 0 的程序是不正确的一样。
  • caf - 我想这可能就是你的意思。然后“在任何情况下 can 你都可以修改字符串文字”似乎已经过分说明它了。准确地说“在这两种情况下,C 语言标准规定的约束都被打破了,无论如何……编译器或运行时系统不可能在所有情况下都识别出违反标准的情况。”我假设标准的立场是效果未定义?
  • 当一个标准不能以任何一种方式断言任何东西时,我认为将行为定义为“未定义”似乎是正确的边界并且很有帮助。断言“正确的 C 程序”“不能取消引用空指针”的关系听起来等同于证明停止问题。但我不介意。我不会这样做,并希望“免费”摆脱它:-)
【解决方案5】:

案例 1:

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

上面设置str指向文字值“Hello”,它在程序的二进制图像中被硬编码,在内存中被标记为只读,这意味着这个字符串文字的任何更改都是非法的,并且会抛出分段错误。

案例 2:

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

案例 3:

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

【讨论】:

    【解决方案6】:

    问题是有什么区别

    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 类型的左值,它们是modifiable lvalues。如果target of the assignment is not a modifiable lvalue,则需要符合标准的编译器来生成诊断消息;它不需要对分配给char 类型的左值产生任何警告:

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

    无论哪种情况,编译器都不需要停止编译;它为cname[0] 的分配产生一个警告就足够了。结果程序不是正确程序。构造的行为是未定义。它可能会崩溃,甚至更糟的是,它可能不会崩溃,并且可能会更改内存中的字符串文字。

    【讨论】:

      【解决方案7】:

      第一个您可以根据需要实际更改,第二个您不能。阅读有关const 正确性的信息(有一些关于差异的很好的指南)。还有char const * name不能转帖。

      【讨论】:

      • 究竟可以改变什么?
      【解决方案8】:

      其实char* name不是指向常量的指针,而是指向变量的指针。您可能正在谈论这个其他问题。

      What is the difference between char * const and const char *?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-05
        • 1970-01-01
        • 2010-10-27
        • 2013-04-23
        • 2011-02-25
        相关资源
        最近更新 更多