【问题标题】:When to use const char * and when to use const char []何时使用 const char * 以及何时使用 const char []
【发布时间】:2011-12-15 18:08:38
【问题描述】:

我知道它们是不同的,我知道它们有何不同,并且我阅读了所有我能找到的关于 char*char[] 的问题

但所有这些答案都无法说明何时应该使用它们。

所以我的问题是:

什么时候使用

const char *text = "text";

你什么时候使用

const char text[] = "text";

有什么指导方针或规则吗?

举个例子,哪个更好:

void withPointer()
{
    const char *sz = "hello";
    std::cout << sz << std::endl;
}

void withArray()
{
    const char sz[] = "hello";
    std::cout << sz << std::endl;
}

(我知道std::string 也是一个选项,但我特别想了解char 指针/数组)

【问题讨论】:

标签: c++ c


【解决方案1】:

两者明显不同,首先:

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

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

数组版本:

char text[] = "text"; 

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


指针版本:

char *text  = "text"; 

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

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

const char*text = "text";

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


哪个版本更好?

取决于用途。

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

编辑:我刚刚注意到(在 cmets 中)OP 寻求以下区别:

const char text[]const char* text

除了关于修改字符串文字的那一点之外,上述不同点仍然适用。使用const 限定符,数组test 现在是一个包含const char 类型元素的数组,这意味着它们不能被修改。

鉴于此,我会选择数组版本而不是指针版本,因为指针可以(错误地)轻松地重新定位到另一个指针,并且可以通过另一个指针修改字符串,从而导致 UB。

【讨论】:

  • 我想补充一点,除非它是 char *constchar const *const,否则指针可以重置为指向不同的缓冲区,因此在受限意义上 text 可以更改.
  • @Als:faenel 在他/她的回答中提到的 static const char[] 怎么样?
  • @rve:我的昵称拼写为Fanael。也就是说,faenel 吸引了我的一部分 :)
  • @rve:通过类型转换修改 const 的变量,否则会导致未定义的行为,我认为它不会经常被忽视。顺便说一句,澄清您的评论:@987654342 @ 和 const char * 不相同,它们仍然具有我上面的回答指出的完全相同的差异。static 的使用无论如何都不会使字符串文字可修改。
  • 如果不需要修改数据,使用const char text[]可以减少目标文件中的重定位次数,并且需要更少的机器码指令访问。
【解决方案2】:

可能最大的区别是你不能使用 sizeof 操作符和指针来获取缓冲区的大小开始指向,而与 const char[] 版本一样,你可以在数组变量上使用 sizeof以字节为单位获取数组的内存占用大小。所以这真的取决于你想用指针或缓冲区做什么,以及你想如何使用它。

例如,做:

void withPointer()
{
    const char *sz = "hello";
    std::cout << sizeof(sz) << std::endl;
}

void withArray()
{
    const char sz[] = "hello";
    std::cout << sizeof(sz) << std::endl;
}

会给你截然不同的答案。

【讨论】:

  • 我想借此机会指出 sizeof 不是函数。
  • @unwind:从技术上讲,但是在解析std::cout &lt;&lt; sizeof sz &lt;&lt; std::endl; 时我的眼睛会感到困惑,因为连续的两个标识符通常表示一个类型声明。 sizeof(sz) 我的大脑解析为另一个函数。
【解决方案3】:

通常要回答这些类型的问题,使用最明确的问题

在这种情况下,const char[] 获胜,因为它包含有关其中数据的更详细信息——即缓冲区的大小。

【讨论】:

    【解决方案4】:

    请注意:

    我会做到static const char sz[] = "hello";。这样声明的好处是,通过写入只读内存来更改该常量字符串会使程序崩溃。如果没有static,抛弃常量然后更改内容可能会被忽视。

    另外,static 让数组简单地位于常量数据部分,而不是在每次调用函数时在堆栈上创建并复制从常量数据部分

    【讨论】:

    • 我认为抛弃 const 并不会经常被忽视
    • 有时会。这只是对墨菲的保护。
    • @Fanael:所以 static const char[] 的行为几乎与 const char* 相同?初始化时只有一份副本,没有开销?
    • 是的,您仍然可以在其上使用sizeof 并获取数组的实际大小,因为它仍然是一个数组。 static 是与类型无关的存储说明符。
    • 我还发现了这个:stackoverflow.com/questions/2096448/…。它指出,如果它们相等,则指针版本可能指向同一个字符串,但数组版本将始终是唯一的,即使字符串相等。
    【解决方案5】:

    如果使用数组,则数据会在运行时初始化。如果使用指针,则运行时开销(可能)更少,因为只需要初始化指针。 (如果数据小于指针的大小,则数据的运行时初始化小于指针的初始化。)因此,如果您有足够的数据,它很重要并且您关心运行时初始化成本,您应该使用指针。你几乎不应该关心这些细节。

    【讨论】:

    • 编译器可能会将两个版本优化为相同的代码。运行时不需要数组初始化。
    • @DavidHeffernan:我认为编译器无法生成相同的代码。使用 const 数组,允许用户抛弃 const 性,然后应该能够写入数组 - 因此需要将数组放置在可写内存中。
    【解决方案6】:

    几年前,Ulrich Drepper 的博客文章帮助了我很多:

    so close but no cigarmore array fun

    博客的要点是const char[] 应该是首选,但只能作为全局或静态变量。

    使用指针const char* 有一些缺点:

    1. 附加变量
    2. 指针可写
    3. 额外的间接方式
    4. 通过指针访问字符串需要 2 次内存加载

    【讨论】:

      【解决方案7】:

      只提一个小问题:

      const char chararr[4] = {'t', 'e', 'x', 't'};
      

      是另一种使用 4 个字符初始化数组的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-09
        • 1970-01-01
        • 2021-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多