字符串、const char*和.c_str()是什么?

19

我遇到了一个奇怪的问题,想知道它为什么会产生这样的行为。我的类中有一个成员函数返回std :: string,我想将这个string转换为const char*,于是我做了以下操作:

    const char* c;
    c = robot.pose_Str().c_str();  // is this safe??????
    udp_slave.sendData(c);

问题是在主控端我得到了一个奇怪的字符。但是,如果我按照以下方式操作

    const char* c;
    std::string data(robot.pose_Str());
    c = data.c_str();
    udp_slave.sendData(c);

我得到了我期望的结果。我的问题是前述两种方法之间有什么区别?


6
我猜pose_Str()返回一个字符串副本。当pose_Str()函数返回时,这个临时对象会被释放。所以c变成了一个野指针。 - billz
@billz,我把它视为第一个答案。谢谢。 - CroCo
5个回答

22

这涉及指向一个临时变量的问题。如果您通过值返回,但不存储字符串,则该字符串在下一个序列点(分号)之后消失。

如果您将其存储在变量中,则指针指向实际存在于udp发送期间的某些内容。

考虑以下代码:

int f() { return 2; }


int*p = &f();
现在这看起来很愚蠢,不是吗?你正在指向从 f 复制回来的值。你不知道它将存活多久。你的字符串也是一样的。

7

.c_str()按值返回char const*的地址,这意味着它获得指针的副本。但在此之后,它指向的实际字符数组被破坏了。这就是为什么你会得到垃圾值。在后一种情况下,你正在使用该字符数组创建一个新的字符串,通过从实际位置复制字符来完成此操作。在这种情况下,尽管实际字符数组被破坏,但副本仍然存在于字符串对象中。


5

您不能在std::string对象的生命周期之外使用c_str()指向的数据。有时候生命周期并不明确,比如下面的代码。解决方案也已经给出:

#include <string>
#include <cstddef>
#include <cstring>

std::string foo() { return "hello"; }

char *
make_copy(const char *s) {
    std::size_t sz = std::strlen(s);
    char *p = new char[sz];
    std::strcpy(p, s);
    return p;
}

int
main() {
    const char *p1 = foo().c_str(); // Whoops, can't use p1 after this statement.
    const char *p2 = make_copy(foo().c_str()); // Okay, but you have to delete [] when done.
}

5

c_str()

c_str()返回的指针可能会失效,原因如下:

  • 将非const引用传递给任何标准库函数;或者
  • 对字符串调用非const成员函数(除了operator[]、at()、front()、back()、begin()、rbegin()、end()和rend())。

这意味着,如果由robot.pose_Str()返回的字符串被任何非const函数销毁或更改,指向该字符串的指针将失效。由于您可能从robot.pose_Str()返回临时副本,所以在调用c_str()之后,返回值将无效。

然而,如果您返回对内部字符串的引用而不是临时副本,则可以:

  • 确保它能正常工作(如果您的udp_send函数是同步的);
  • 或者依赖于一个无效的指针,因此如果udp_send可能在修改原始字符串的内部内容后完成,则会遇到未定义的行为。

4

Q

const char* c;
c = robot.pose_Str().c_str();  // is this safe??????
udp_slave.sendData(c);

A

这可能是不安全的。它取决于robot.pose_Str()返回什么。如果返回的std::string的生命周期比c的生命周期长,那么它是安全的。否则,就不安全。

您正在存储一个地址在c中,该地址将在语句执行完成后立即失效。

std::string s = robot.pose_Str();
const char* c = s.c_str();  // This is safe
udp_slave.sendData(c);

在这里,你正在将一个地址存储在c中,该地址将在定义sc的范围之外保持有效。


3
只是对“不安全”的评论。仅凭这行代码,我们无法确定它是否安全。如果robot.pose_Str()返回对robot成员字符串字段的引用,并且robot的生命周期比c更长,则是安全的。 - Adrian Shum

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