简体   繁体   中英

How to elegantly initialize vector<char *> with string literal?

The problem comes from an exercise on C++ Primer 5th Edition:

Write a program to assign the elements from a list of char* pointers to C-style character strings to a vector of strings.

----------------Oringinal Question------------

First I try the following somewhat direct way:

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

But compiling the code I get a warning:

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

And running the ./a.out I get a

Segmentation fault (core dumped)

I think it is because I try to write to a const char. So I try another way:

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

It is OK this time. But it seems a little tedious. Is there any other elegant way to initialize a vector with string literal?

Here's one way:

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");

Just remember to:

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

Although from the wording of the question, syntactically it's the same work either way if it was a vector<const char*> as if it were a vector<char*> anyway (you're not modifying the source when you're copy, so doesn't matter if you could modify the source), so I would stick to the exercise as if you just did:

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

I think the char vs const char difference doesn matter much in this task.

For the actual copy, use a fill constructor with iterator arguments:

vector<const char*> vc = {"hello","world"};
vector<string> vs(vc.begin(), vc.end());

See a working example .

If there's a need for editable chars in the source, just use the second version you posted:

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

Supplement : The arguments of main, argc and argv , are a great example of

a list of char* pointers to C-style character strings

See how argc and argv get translated into a vector of string .

You might try something like this:

// 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM