15

我知道 example"hello"是 type const char*。所以我的问题是:

  1. 我们如何将像这样的文字字符串分配给"hello"const char*像这样的:

    char* s = "hello";  // "hello" is type of const char* and s is char*
                        // and we know that conversion from const char* to
                        // char* is invalid
    
  2. 是像"hello",它将在我的所有程序中占用内存的文字字符串,还是就像在语句结束时将被销毁的临时变量?

4

5 回答 5

24

其实"hello"是类型char const[6]

但问题的要点仍然是正确的——为什么 C++ 允许我们将只读内存位置分配给非const类型?

唯一的原因是向后兼容旧的 C 代码,它不知道const. 如果 C++ 在这里很严格,它会破坏很多现有的代码。

也就是说,大多数编译器都可以配置为警告此类代码已弃用,甚至默认情况下这样做。此外,C++11 完全不允许这样做,但编译器可能还没有强制执行。


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

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

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

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

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

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

于 2012-04-22T14:19:20.810 回答
2

像“hello”这样的文字字符串会在我的所有程序中占用内存,这就像一个临时变量,在语句结束时会被销毁。

它保存在程序数据中,因此在程序的生命周期内可以使用。您可以从当前范围返回指向此数据的指针和引用。

被强制转换为的唯一原因const char*char*与 c 的兼容性,例如 winapi 系统调用。与任何其他 const 强制转换不同,这种强制转换是不明确的。

于 2012-04-22T14:27:13.010 回答
1

只需使用string

std::string s("hello");

那将是 C++ 方式。如果您真的必须使用char,则需要创建一个数组并在其上复制内容。

于 2012-04-22T14:19:31.277 回答
1

第二个问题的答案是该变量s作为指向字符的类型指针存储在 RAM 中。如果它是全局的或静态的,它会在堆上分配并在运行程序的整个生命周期内保持在那里。如果它是本地(“自动”)变量,它会在堆栈上分配并一直保留到当前函数返回。在任何一种情况下,它都会占用保存指针所需的内存量。

字符串"Hello"是一个常量,它与所有其他常量和初始化程序一起存储为程序本身的一部分。如果您构建程序以在设备上运行,则该字符串将存储在 ROM 中。

请注意,因为字符串是常量并且s是指针,所以不需要复制。指针s只是指向存储字符串的位置。

于 2012-04-22T14:37:09.617 回答
-3

在您的示例中,您不是在分配,而是在构建。例如,std::string 确实有一个std::string(const char *)构造函数(实际上它更复杂,但没关系)。而且,类似地,char *(如果它是一个类型而不是一个指向类型的指针)可以有一个 const char * 构造函数,它正在复制内存。

我实际上并不知道编译器是如何在这里真正工作的,但我认为它可能与我上面描述的类似:"Hello"在堆栈中构造一个副本,并s使用该副本的地址进行初始化。

于 2012-04-22T14:28:42.950 回答