在C++中,char*到底代表什么意思?

4

我的理解是它应该包含一个字符变量的内存地址,但现在我看到它也可以用来创建字符串?例如:

char* ptr = "string";

当ptr本应该保存一个内存地址时,它如何被赋予一个字符串?我认为需要使用解引用运算符来更改所指向的值,难道不是吗?

可能有一个很好的重复问题,但我回答了,因为这段代码实际上不是标准的C++,而且那里的重复问题可能并没有指出这一点。 - Bathsheba
1
试图更改该值是未定义行为。对于“字符串”,它是一个const char []左值。事实上,ISO C++禁止像char * ptr =“string”这样的代码。 - con ko
@JohnDing 只有自 C++11 开始才支持。(最后一句话。) - walnut
@walnut 自从 ISO C++ 出现后,它就已经被废弃了,但是我的陈述显然不够精确。 - con ko
这个回答解决了您的问题吗?字符串指针的使用 - Daemon
@Daemon:这个问题属于C标签,尽管其中的大部分内容确实适用于C ++ ,所以在这方面它是有帮助的,也是一个好的发现。存在一个微妙的区别,在C中字符串会衰变为非const指针类型,但是尝试通过指针修改字符串时的行为是未定义的。而在C++中,字符串会衰变为const指针类型。 - Bathsheba
2个回答

11
""string"是一个const char[7]类型的字面量。C++允许您使用兔子耳朵来简化语言。为您添加了0终止符,这就是为什么有7个元素而不是6个。

在各种情况下,数组类型会衰减为指针类型,指针设置为数组的第一个元素。赋值是其中之一。这就是这里发生的事情。

从C++11开始,严格来说,您的C++编译器不应编译该语句。它应该是

"
const char* ptr = "string";

如果你真的想知道发生了什么,这篇关于内存段的文章是一个不错的阅读材料。https://en.wikipedia.org/wiki/Data_segment - jiveturkey

7
您的理解是正确的;char*确实指向单个char
技巧在于,数组在内存中连续排列,因此给定一个指向数组第一个元素的指针,可以通过简单地将偏移量添加到指针来访问其他元素。在您的示例中,逻辑上看起来像这样:
+-----+
| ptr |
+--+--+
   |
   v
 +-+-+---+---+---+---+---+----+
 | s | t | r | i | n | g | \0 |
 +---+---+---+---+---+---+----+

ptr指向"string"开头的's'字符。通过将1添加到ptr,您可以找到't'等字符。这就是内置的[]运算符所做的事情。ptr[2]被定义为相当于*(ptr + 2): 将指针偏移2个位置,然后获取结果所指向的值。

'\0'字符用于标记字符串的结尾,以便使用该字符串的代码知道停止查找更多字符。


这种数组/指针的二元性在C++中适用于所有其他指针声明(例如,int *pInt; float *pFloat),因为它向后兼容C语言。通常(但不总是)指针可以与数组互换,因为如果您有一个指向数组第一个元素的指针,C/C++允许您轻松访问数组的后续元素。不能访问数组末尾之外的元素,并且(在字符数组的情况下)要为最后一个空字符分配额外的字符。在C++中,使用std::string、std::array等类可以缓解这些问题... - Siegfried
所以,“string”是字符数组,ptr指向该数组的第一个元素,即s...现在很有意义。如果我输出ptr,cout << ptr;和cout << ptr;之间有什么区别?一个给出整个数组,另一个只给出s,我不确定为什么。我本来认为ptr包含第一个元素的内存地址,而ptr包含那里的值(“s”)。 - papercut
@papercut 标准库有一个重载的 operator<<(std::ostream&, const char*),当 cout << ptr 调用它时,会打印整个字符串。而 cout << *ptr 则调用了 operator<<(std::ostream&, char),打印单个字符。如果你想打印 ptr 中包含的地址,请使用 cout << static_cast<void*>(str) - Miles Budnek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接