2015-01-23 2 views
7

Проблема возникает из упражнений на C++ Primer 5th Edition:Как элегантно инициализировать вектор <char *> со строковым литералом?

Написать программу для назначения элементов из списка полукокса * указатели для символьных строк C-типа на вектор строк.

---------------- Oringinal Вопрос ------------

Сначала я стараюсь следующий несколько прямой путь:

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' можно построить из строкового литерала) [live example] (http://coliru.stacked-crooked.com/a/e0a7821f557b64b8) – Borgleader

+3

Строковые литералы' массив n const char', вы можете найти более подробную информацию [здесь] (http://stackoverflow.com/q/21529194/1708801). Преобразование было нормально в C, но не разрешено в C++, именно из-за проблемы с попыткой изменить их, что является неопределенным поведением. –

+0

@Borgleader Я знаю, что лучше использовать вектор , но упражнение на C++-праймере просит меня преобразовать вектор в вектор . Поэтому мне интересно, как его инициализировать. – Warbean

ответ

4

Вот один из способов:

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*>, как если бы это было a vector<char*> в любом случае (вы не изменяете источник, когда копируете, так что неважно, если вы можете изменить источник), поэтому я буду придерживаться упражнения, как если бы вы только что сделали:

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

О, это гораздо более утомительно, чем я ожидал. Но размышление. Спасибо. – Warbean

5

Я думаю, что разница в char против const char Безразлично дело много в этой задаче.

Для фактической копии, используйте конструктор заливки с аргументами итераторов:

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

См working example.

Если есть нужно для редактирования символов в источнике, просто использовать вторую версию вы размещенную:

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

Дополнение: Аргументы главного, argc и argv, являются отличный пример от

список указателей char * для символов символов C-стиля

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

+0

Но я хочу, чтобы вектор сохранял редактируемые массивы символов. – Warbean

+0

Почему * редактируемый * в исходном массиве?Это явно не рассматривается в описании задачи, я полагаю, что он фокусируется на передаче C-строк в новом мире C++? – Wolf

+0

Я думал, что его использование может быть более общим. Возможно, мне нужно сосредоточиться на передаче, как вы говорите. – 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; 
} 
Смежные вопросы