现代C++将字符串复制到char*的方法

4

现代做法是什么?像<cstring>这样的头文件已经被弃用,而一些编码风格禁止使用"C-like"函数。我有三种方法可以完成同样的事情。哪种方法最符合现代C ++的习惯用法?

1. 使用迭代器并包含空终止符。

{
    std::string test{"hello, world!"};
    char* output = new char[test.size() + 1];
    std::copy(test.begin(), test.end(),
        output);
    output[test.size() + 1] = '\0';
    std::cout << output;
    delete output;
}

2. 使用c_str()函数,该函数包括空字符终止符。

{
    std::string test{"hello, world!"};
    char* output = new char[test.size() + 1];
    std::copy(test.c_str(), test.c_str() + std::strlen(test.c_str()),
        output);
    std::cout << output;
    delete output;
}

3. Use std::strcpy

{
    std::string test{"hello, world!"};
    char* output = new char[test.size() + 1];
    std::strcpy(output, test.c_str());
    std::cout << output;
    delete output;
}

我不想在面试官面前显得像个新手,被说成“哦,你用strcpy,你一定是C程序员。”


如果我是你,我会担心异常安全性,用try包装整个块,并捕获std::bad_alloc。另外,“像<cstring>这样的头文件已经被弃用了”-从什么时候开始?! - Daniel Kamil Kozar
2
目标数据结构是什么?它是malloc分配的以0结尾的字符串吗?还是“可访问的以0结尾的字符串”?或者实际上是那些不标准的new分配的以0结尾的字符串? - Deduplicator
1
@DanielKamilKozar 自 C++98 以来。疯狂,我知道。 - user6364501
在展示使用C语言的经验方面,没有什么真正不好的地方,因为你可能只会在创建与C兼容的层时才这样做。(C++标准通常认为将std::string转换为C字符串是被废弃的。) - Lilith Daemon
6
不,<cstring> 绝对 没有 废弃。<string.h> 废弃了,但 <cstring> 是一个普通的标准头文件。 - Baum mit Augen
显示剩余5条评论
3个回答

18

std::vector是在C++17之前获得连续缓冲区的现代安全方法。

std::string test{"hello, world!"};
std::vector<char> output(test.c_str(), test.c_str()+test.size()+1);
// use output.data() here...
自 C++17 开始,std::string 有一个非 const 的 data() 重载函数。
std::string test{"hello, world!"};
char * p = test.data();

10

正确的方法是一开始就不使用new[],而是使用std::vector

std::string temp {"Some string"};
std::vector<char> data (begin(temp), end(temp));
// If '\0' termination is required:
data.push_back('\0');

您可以使用data.data()访问data的底层缓冲区。如果您担心由于push_back导致重新分配,您可以在分配范围之前使用std::vector :: reserve 足够的空间。

如果您不需要实际可修改的char数组,则可以跳过复制并直接使用std::string :: data std::string :: c_str 返回的指针。


2

虽然其他答案提供了很好的建议,并且在几乎所有情况下都是正确的做法,但有一些真实情况下你可能被迫使用char*而不是容器。最常见的情况是如果您需要直接与C代码进行交互,并且所调用的C方法需要一个非const指针(即它将拥有内存的所有权)。

这是我如何进行转换:

#include <string>
#include <cstdlib>

char* convert(const std::string& source)
{
    const auto result = (char*) std::malloc(source.length() + 1);
    source.copy(result, source.length());
    result[source.length()] = '\0';
    return result;
}

然后你会有类似这样的内容:
int main()
{
    const std::string foo {"hello"};
    auto p = convert(foo);
    some_nasty_c_method(p); // promises to free p
    // other stuff
}

通常情况下,如果你需要删除自己,请不要这样做;而是使用容器或者std::unique_ptr


std::vector<char> v(foo.begin(), foo.end()); some_nasty_c_method(v.data());有什么问题吗? - Christian Hackl
@ChristianHackl std::vector::data 返回一个 const 指针。 - Daniel
@Daniel: 一个重载函数是这样的,但也有一个非const的重载函数。 然而,一个要在给定指针上调用free的函数需要获得通过malloc获得的指针。希望这在接口描述中有所说明,那么就没有问题了,应该使用/最好使用哪种方法,因为你必须使用malloc - Pixelchemist
1
@ChristianHackl:std::vector<char> v(foo.begin(), foo.end()); 的问题在于缺少通常由传统字符串处理 C 代码期望的空字符(如果没有大小参数,那么可以跳过 '\0')。 - Pixelchemist

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