C/C++字符指针崩溃

4

假设有一个返回固定“随机文本”字符串的函数,代码如下:

char *Function1()
{ 
return “Some text”;
}

如果程序意外尝试更改该值,则可能会导致程序崩溃。

Function1()[1]=’a’;

函数调用后面的方括号是什么意思?它们可能会导致程序崩溃吗?如果您对此熟悉,欢迎提供解释!

1
[1] 指向字符串中的第二个字符([0] 是第一个)。 - Mike Park
为什么你在标题中说C ++,但标记问题为C? - GManNickG
1
你应该将其标记为MSVC,因为gcc(至少>= 4)会警告你将char const []分配给char *已被弃用...正如你所看到的那样,这是有充分理由的。 - mmmmmmmm
7个回答

12
你在函数中返回的字符串通常存储在进程的只读部分。尝试修改它会引起访问冲突。(编辑:严格来说,这是未定义的行为,在某些系统中会引起访问违规。感谢John的指出)。
通常情况下,这种情况发生是因为该字符串与应用程序代码一起硬编码。加载时,指针被建立指向进程中保存字面字符串的只读部分。实际上,当你在C语言中写入某个字符串时,它被视为一个const char*(指向常量内存的指针)。

4
你不能说它会导致访问冲突。C++并不知道什么是访问冲突。你真正能说的是它将引起未定义行为。 - John Dibling
1
@John:你说得对。那就从哲学意义上理解吧 :) - Diego Sevilla
@John:也许“will”这个词有点过于绝对,但你有很大的机会成功 :-) - mmmmmmmm
2
@rstevens:在Windows上可能会导致GPF错误。在Linux上可能会导致段错误。在我的手机上可能会打电话给我妈妈。重点是这是未定义行为。 - John Dibling

4

那个函数的签名应该是 constchar* Function();


1
它应该实际上是 std::string,因为 OP 想要修改从函数返回的值。 - John Dibling
是的,John,在C++中 - 当然,在C中 - 那是唯一的方法。 - Nikolai Fetissov

3
您正在尝试修改一个字符串常量。根据标准,这会引发未定义的行为。另一件需要记住的事情(相关的)是字符串常量始终是const char*类型。有一个特殊的例外,可以将指向字符串常量的指针转换为char*,从而去掉const修饰符,但基础字符串仍然是常量。所以通过您正在做的事情,您正在尝试修改一个const。这也会引发未定义的行为,并类似于尝试执行以下操作:
const char* val = "hello";
char* modifyable_val = const_cast<char*>(val);
modifyable_val[1] = 'n';  // this evokes UB

不要从您的函数返回 const char*,而是通过值返回一个 string。这将根据字符串字面值构造一个新的 string,调用代码可以任意操作:

#include <string>

std::string Function1()
{ 
return “Some text”;
}

稍后:

std::string s = Function1();
s[1] = 'a';

现在,如果你想改变Function()返回的值,那么你需要做一些其他的事情。我会使用一个类:

#include <string>
class MyGizmo
{
public: 
  std::string str_;
  MyGizmo() : str_("Some text") {};
};

int main()
{
  MyGizmo gizmo;
  gizmo.str_[1] = 'n';
}

1

你可以使用静态字符串作为返回值,但你从未使用过它。这就像访问冲突错误一样。在C++标准中,它的行为没有被定义。


当然你可以使用它,但是你不能修改其内容。 - Fred Foo
哦,没错。还有一件事(就像乔布斯一样...:),正如许多其他人已经说过的那样,将常量字符字符串转换为非常量字符字符串是什么什么的...你懂的~ - Hongseok Yoon

0

问题不在于括号,而在于赋值。您的函数返回的不是简单的 char*,而是 const char*(尽管我可能说错了,但这里的内存是只读的),因此您试图更改不可更改的内存。而括号 - 它们只是让您访问数组元素。


0
请注意,您可以通过将文本放置在常规数组中来避免崩溃:
char Function1Str[] = "Some text";

char *Function1()
{
    return Function1Str;
}

0
这个问题表明您不理解字符串字面值。
想象一下这段代码。
char* pch = "Here is some text";
char* pch2 = "some text";
char* pch3 = "Here is";

现在,编译器如何为字符串分配内存完全是编译器的事情。内存可能会像这样组织:

Here is<NULL>Here is some text<NULL>

pch2指向pch字符串内存位置。

关键在于理解内存。使用标准模板库(STL)是一个好的实践,但对你来说可能会有相当陡峭的学习曲线。


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