2013-02-19 5 views
1

Я пытаюсь преобразовать строку в const*char*, чтобы иметь возможность вызвать библиотечную функцию. Мой код выглядит следующим образом:constructing char * const * from string

// myVec is simply a vector<string> 

vector<string> myVec; 
/* stuff added to myVec 
* it is a vector of words that were seperated by whitespace 
* for example myVec[0]=="Hey"; myVec[1]=="Buck"; myVec[2]=="Rogers"; etc... 
*/ 

char*const* myT = new char*[500]; //I believe my problem stems from here 

for(int z=0; z<myVec.size(); z++) { 
    string temp=myVec[z]+=" "; 
    myT[z]=temp.c_str(); 
} 
//execv call here 

Я построение это для второго параметра execv().

Компилятор всегда выдает различные ошибки, и когда я исправляю друг друга, появляется всплывающее окно (кажется довольно круговым из решений/google-fu, которые я использовал).

+1

Это выиграл» Это хорошая идея, поскольку переменная 'temp' - это то, что вы назвали ее, временным. Это означает, что указатель, возвращаемый 'c_str', также является временным. –

+0

temp в порядке, поскольку вызов exec будет сразу после этого кода; Я не знаю, почему я оставил новый там, для myT, я только что напугал голову, пытаясь заставить это работать. –

+1

Не совсем так, поскольку время жизни переменной temp происходит только внутри текущей итерации циклов. После того, как вы продолжите следующую итерацию или покинете цикл, эта память стека (и будет) будет исправлена ​​компилятором. –

ответ

6

Сигнатура execv ожидает, что массив аргументов, чтобы указать на modifyable строки в стиле C , Таким образом, вопреки тому, что предлагают другие ответы, c_str() не такая хорошая идея.

Хотя в C++ 03 не гарантируется, что все реализации std::string, которые я знаю, хранят данные в непрерывном блоке памяти с завершающим NULL (это гарантировано в C++ 11), поэтому вы можете использовать это в свою пользу: Создайте вектор указателей на изменяемые массивы символов, инициализировать значения с упорами для строк в вашем входном векторе и передать адрес этого блока данных execv:

std::vector<char*> args; 
args.reserve(myVec.size()+1); 
for (std::vector<std::string>::iterator it=myVec.begin(); it != myVec.end(); ++it) { 
    args.push_back(&((*it)[0]); 
} 
args.push_back(0); // remember the null termination: 

execv("prog", &args[0]); 
+0

Ouch. Действительно ли «execv» действительно хочет изменить данные на месте? Зачем? Или это просто случай, когда кто-то забыл 'const', и мы можем безопасно обойти его с помощью' const_cast'? (LOgically, 'execv' не может изменить ни один из символов, присутствующих в строках, и не может добавлять символы, так как он не гарантирует, что пространство там, поэтому я не вижу, как он может изменять данные.) –

+0

@ JamesKanze: Я не знаю никакой веской причины, но в документации утверждается, что второй аргумент имеет тип 'char * const *'. Тот факт, что там есть 'const', указывает, что это не просто старый API, который не знал о' const', поэтому я не буду предполагать, что он не калечит данные ... –

+0

Я подозреваю (но У меня нет внутренней информации относительно Posix), что они просто скопировали подпись, которая передается в 'main'. И в 'main', вы _do_ имеете право изменять строки (но не массив указателей), что объясняет несколько странную подпись. В любом случае, играя в безопасности, вы правы; вы должны использовать '& ((* it) [0])' вместо 'it-> c_str()'. (Но вы все равно можете это сделать с помощью 'std :: transform'.) –

2

Существуют две основные проблемы, требующие адресации. Сначала - ошибка компилятора: указатели в массиве, указывающие на на myT, - const, поэтому вы не можете их назначать. Make myT char const** myT;. Вторая проблема заключается в том, что то, что вы назначаете им , является указателем на локальную переменную, которая будет разрушена, когда она выйдет за пределы области действия, поэтому указатели будут болтаться.

Действительно ли функция, которую вы вызываете, нуждается в дополнительном белом месте в конце? (Вы упомянули execv где-то, я думаю, Если это функция, дополнительные пробелы будут делать больше вреда , чем пользы.). Если нет, то все, что вам нужно сделать, это:

std::vector<char const*> myT(myVec.size() + 1); 
std::transform(myVec.begin(), myVec.end(), myT.begin(), 
       [](std::string const& arg) { return arg.c_str(); }); 
execv(programPath, &myT[0]); 

Если вы не можете рассчитывать на C++ 11 (как это обычно бывает) вы можете сделать что-то подобное с boost::bind; в противном случае, просто напишите цикл самостоятельно.

Если вам нужно преобразовать строки в myVec в некотором роде, лучшее решение по-прежнему, чтобы скопировать их во вторую std::vector<std::string>, с преобразованием, и использовать это.

(BTW: действительно ли вы хотите изменить содержимое myVec, по использованием += по каждому элементу в контуре)

+0

Вы можете использовать функцию, отличную от члена, чтобы получить 'c_str' из строки. –

+0

@PeterWood Функция не-член или функциональный объект, но в обоих случаях вам нужно будет написать что-то особенное вне текущей функции. –

Смежные вопросы