如何优雅地使用字符串字面量初始化vector<char*>?

10

这个问题源于《C++ Primer第五版》上的一道练习:

编写一个程序,将指向char*指针列表的元素分配给C风格的字符字符串,然后将它们存储在一个string类型的向量中。

----------------原始问题------------

首先我尝试了以下比较直接的方法:

vector<char *> vec = {"Hello", "World"};
vec[0][0] = 'h';

但编译代码时我收到了一个警告:

temp.cpp:11:43: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
     vector<char *> vec = {"Hello", "World"};
                                           ^ 

当我运行./a.out时,我得到一个

Segmentation fault (core dumped)

我认为是因为我试图写入 const char。所以我尝试另一种方式:

char s1[] = "Hello", s2[] = "World";
vector<char *> vec = {s1, s2};
vec[0][0] = 'h';

这次没有问题。但是似乎有点繁琐。有没有其他更优雅的方式用字符串字面量初始化一个向量?


4
不能更改字符串字面值的内容。请使用std::vector<std::string>(可以从字符串字面值构造std::string)。演示链接 - Borgleader
3
字符串字面值是由 n 个 const char 组成的数组,你可以在这里找到更多细节(链接为 https://dev59.com/m2Ei5IYBdhLWcg3wMZ3a)。在 C 中,字符串字面值可以被转换,但在 C++ 中则不允许,因为尝试修改它们会导致未定义行为。 - Shafik Yaghmour
@Warbean std::vector<std::string> vec(argv, argv + argc); 只需要传入一些命令行参数 ;) - Borgleader
@Wolf 谢谢你的建议。 - Warbean
谢谢,现在是一个好问题。 - Wolf
显示剩余11条评论
3个回答

6
我认为在这个任务中,charconst char之间的区别并不重要。
对于实际的复制操作,请使用带有迭代器参数的填充构造函数:
vector<const char*> vc = {"hello","world"};
vector<string> vs(vc.begin(), vc.end());

查看工作示例

如果源码需要可编辑字符,只需使用你发布的第二个版本:

char s1[] = "Hello", s2[] = "World";
vector<char *> vec = {s1, s2};

补充:main函数的参数argcargv是一个非常好的例子,它们是指向C风格字符串的char*指针列表。

请参见如何将argc和argv转换为字符串向量


为什么源数组中要有“editable”?这似乎在任务描述中没有明确说明,我猜它侧重于在C++的新世界中传输C-字符串? - Wolf
我认为它的使用可能更加普遍。也许我需要像你说的那样专注于传输。 - Warbean
@Warbean 我“发现”了一个免费获取char*指针列表的方法 :-) - Wolf

5
这里有一种方法:
template <size_t N>
void append_literal(std::vector<char*>& v, const char (&str)[N]) {
    char* p = new char[N];
    memcpy(p, str, N);
    v.push_back(p);
}

std::vector<char*> v;
append_literal(v, "Hello");
append_literal(v, "World");

请记住以下几点:

void clear(std::vector<char*>& v) {
    for (auto p : v) delete[] p;
}

虽然从问题的措辞来看,如果是vector<const char*>或者是vector<char*>都一样(在复制时不会修改源),所以我建议按照练习要求进行处理:

std::vector<const char*> v{"Hello", "World!"};

哦,这比我预期的要繁琐得多。但是非常值得思考。谢谢。 - Warbean

0
您可以尝试像这样做:
// utility function to create char*'s
template<std::size_t Size>
char* make_rptr(const char (&s)[Size])
{
    char* rptr = new char[Size];
    std::strcpy(rptr, s);
    return rptr;
}

int main()
{
    // initialize vector
    std::vector<char*> v {make_rptr("hello"), make_rptr("world")};

    // use vector
    for(auto&& s: v)
        std::cout << s << '\n';

    // ...

    // remember to dealloacte
    for(auto&& s: v)
        delete[] s;
}

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