代码之家  ›  专栏  ›  技术社区  ›  Jamison Dance

我能从C++字符串中得到一个非const C字符串吗?

  •  22
  • Jamison Dance  · 技术社区  · 15 年前

    C++中的const正确性仍然让我头疼。在使用一些旧的C代码时,我发现需要将一个C++字符串对象分配给一个C字符串,并将其赋值给变量。但是,变量是 char * c_str() 返回A const char [] . 有没有一个好的方法可以在不需要滚动我自己的函数的情况下解决这个问题?

    编辑: 我也尽量避免打电话给新的。我很乐意用稍微复杂一点的代码来减少内存泄漏。

    12 回复  |  直到 15 年前
        1
  •  11
  •   dmckee --- ex-moderator kitten    15 年前

    我想总有 strcpy .

    或使用 char* 在C++代码的部分中必须与旧的东西连接的字符串。

    或重构现有代码,用C++编译器编译,然后使用 std:string .

        2
  •  22
  •   sbi    14 年前

    因为对我来说,没有人能像我现在这样回答这个问题,而且由于其他问题现在也没有针对这个问题的答案,我会在这里加上这个问题,即使来的太晚了一年也意味着它会挂在最底层……


    用C++ 03, std::string 不能保证将其字符存储在连续的内存中,并且 c_str() 不需要指向字符串的内部缓冲区,因此保证工作的唯一方法是:

    std::vector<char> buffer(s.begin(), s.end());
    foo(&buffer[0], buffer.size());
    s.assign(buffer.begin(), buffer.end());
    

    因为没有已知的实现实际使用非连续内存,并且 标准::字符串 被许多人使用,好像这是保证,规则将为即将到来的标准而改变,现在保证其字符的连续内存。因此,在C++ 1x中,这应该起作用:

    foo(&s[0], s.size());
    

    然而 这需要注意:结果 &s[0] (由于 s.c_str() ,btw)仅保证在调用可能更改字符串的任何成员函数之前有效。所以 您不应该存储结果 任何地方的这些行动。最安全的是在完整表达式的末尾使用它们,就像我的例子一样。

        3
  •  12
  •   Joe Mabel    15 年前

    在这里你需要做一个重要的区别:是 char* 你想把这个“道德常数”指定给哪个?也就是说,正在抛弃 const -只是一个技术性的问题,你还是会把绳子当作 康斯特 ?在这种情况下,可以使用c-或c++风格的c++样式。 const_cast . 只要你(以及任何维护过这个代码的人)有纪律来对待它 字符* 作为一个 const char* ,你会没事的,但是编译器不会再监视你了,所以如果你把它当作非- 康斯特 您可能正在修改代码中的其他内容所依赖的缓冲区。

    如果你 烧焦* 将被视为非- 康斯特 你打算修改它所指向的,你 必须 复制返回的字符串,而不是丢弃其 康斯特 -尼斯。

        4
  •  8
  •   mch    15 年前

    总有警察……

    std::string s("hello world");
    char *p = const_cast<char *>(s.c_str());
    

    当然,这基本上颠覆了类型系统,但有时在与旧代码集成时是必要的。

        5
  •  5
  •   Juan    15 年前

    你可以使用 copy 方法:

    len = myStr.copy(cStr, myStr.length());
    cStr[len] = '\0';
    

    在哪里? myStr 是你的C++字符串和 cStr char * 至少有 myStr.length() + 1号。也, len 属于类型 size_t 需要,因为复制不为空终止 CSTR公司 .

        6
  •  4
  •   Dmitry    15 年前

    如果你能负担额外的分配,而不是推荐 strcpy 我会考虑使用 std::vector<char> 这样地:

    // suppose you have your string:
    std::string some_string("hello world");
    // you can make a vector from it like this:
    std::vector<char> some_buffer(some_string.begin(), some_string.end());
    // suppose your C function is declared like this:
    // some_c_function(char *buffer);
    // you can just pass this vector to it like this:
    some_c_function(&some_buffer[0]);
    // if that function wants a buffer size as well,
    // just give it some_buffer.size()
    

    对我来说,这有点像C++的方式。 拷贝字符串 . 看看迈耶斯的有效STL项目16,得到比我所能提供的更好的解释。

        7
  •  2
  •   Scheff's Cat    6 年前

    只使用 const_cast<char*>(str.data())

    不要为此感到难过或奇怪,这样做是完美的风格。

    它保证在C++ 11中工作。事实上,它是完全合格的,可以说是原来标准的一个错误;在C++ 03中,它是可能实现的。 string 作为一个不连续的记忆列表,但从来没有人做过。地球上没有一个编译器实现 一串 除了连续的记忆块之外,其他任何东西,所以请完全自信地对待它。

        8
  •  1
  •   Matt Davis    15 年前

    如果你知道 std::string 不会改变的,C风格的演员会有用的。

    std::string s("hello");
    char *p = (char *)s.c_str();
    

    当然, p 指向由 STD::字符串 . 如果 STD::字符串 超出范围或缓冲区被更改(即写入到), P 可能是无效的。

    如果重构代码是不可能的,那么最安全的做法就是复制字符串。

        9
  •  1
  •   Franci Penov    15 年前

    如果 c_str() 正在返回字符串对象内部缓冲区的副本,您只需使用 const_cast<> .

    然而,如果 CX-序列() 直接访问字符串对象内部缓冲区,进行显式复制,而不是删除常量。

        10
  •  1
  •   WarrenB    15 年前

    因为c_str()提供了对数据结构的直接const访问,所以您可能不应该强制转换它。不必预先分配缓冲区的最简单方法是只使用strdup。

    char* tmpptr;
    tmpptr = strdup(myStringVar.c_str();
    oldfunction(tmpptr);
    free tmpptr;
    

    它快速、简单、正确。

        11
  •  1
  •   CodeAngry    11 年前
    std::string vString;
    vString.resize(256); // allocate some space, up to you
    char* vStringPtr(&vString.front());
    // assign the value to the string (by using a function that copies the value).
    // don't exceed vString.size() here!
    // now make sure you erase the extra capacity after the first encountered \0.
    vString.erase(std::find(vString.begin(), vString.end(), 0), vString.end());
    // and here you have the C++ string with the proper value and bounds.
    

    这就是如何将C++字符串转换成C字符串的方法。 但是要确保你知道你在做什么,因为使用原始字符串函数很容易越界。有时这是必要的。

        12
  •  -3
  •   Chris Lutz    15 年前

    做自己真的那么难吗?

    #include <string>
    #include <cstring>
    
    char *convert(std::string str)
    {
        size_t len = str.length();
        char *buf = new char[len + 1];
        memcpy(buf, str.data(), len);
        buf[len] = '\0';
        return buf;
    }
    
    char *convert(std::string str, char *buf, size_t len)
    {
        memcpy(buf, str.data(), len - 1);
        buf[len - 1] = '\0';
        return buf;
    }
    
    // A crazy template solution to avoid passing in the array length
    // but loses the ability to pass in a dynamically allocated buffer
    template <size_t len>
    char *convert(std::string str, char (&buf)[len])
    {
        memcpy(buf, str.data(), len - 1);
        buf[len - 1] = '\0';
        return buf;
    }
    

    用途:

    std::string str = "Hello";
    // Use buffer we've allocated
    char buf[10];
    convert(str, buf);
    // Use buffer allocated for us
    char *buf = convert(str);
    delete [] buf;
    // Use dynamic buffer of known length
    buf = new char[10];
    convert(str, buf, 10);
    delete [] buf;