рассмотрим код:
using std::cout; using std::cerr;
using std::endl; using std::string;
using std::vector;
// . . .
char* envp[10];
vector<string> lines;
char* c_line = nullptr;
size_t len = 0;
while ((getline(&c_line, &len, input_file)) != -1) {
string line;
lines.push_back(line.assign(c_line));
}
fclose(input_file);
free(c_line);
sprintf(envp[0], "SERVER=%s", lines[0].data());
// printing envp[0] here OK
sprintf(envp[1], "DOMAIN=%s", lines[1].data());
// printing envp[1] never happened - Segmentation fault prints in output instead
Я разработчик C#, я не использовал C пару десятков лет. Чего-то очевидного не хватает. Распределение памяти?
P.S. Я смешиваю «старый» char * для строк со стандартными строками, поскольку приложение использует стороннюю dll с символами*
Объявление РЕДАКТИРОВАТЬchar envp[10][512]; завершается ошибкой, когда я пытаюсь передать стороннее свойство somedllObj.envps = envp; с помощью cannot convert char[10][512] to char**
Вам нужно выделить память для ваших указателей с помощью new. Пример: char* c_line = nullptr; -> char* c_line = new char[100]; Или просто char c_line[100];
Я не вижу, где вы выделяете память для envp строк, прежде чем printf перейти к...
@JohnnyMopp - я скопировал это из Google. этот бит работает. возможно, вы правы, и это небрежно, но сейчас это не проблема. спасибо за ваше время в любом случае
@Aconcagua - как правильно выделить envp?
В порядке. Неправильно getline. Но мой комментарий верен для указателей в envp.
Какое тебе дело до envp? Можете ли вы изменить тип на std::vector<std::string>>?
Я не могу, потому что я должен передать его как char* [] сторонней dll
Я нет рекомендую эту дикую смесь std::string и до-струн. Считывайте все напрямую в std::string — все, что у вас есть, — это std::vector<std::string>, содержащий все ваши данные. Затем вызовите стороннюю библиотеку, создайте char* array[], но назначьте ей содержимое строк в векторе — std::string::c_str! Затем передайте этот массив в библиотеку — я предполагаю, что библиотека не будет хранить эти указатели. Если это так, то сохраните вектор в живых, пока библиотека все еще нуждается в этих строках.
Вы можете объявить char envp[10][256] ;, например: 256 символов должно быть достаточно для переменных среды... Но использование настоящего C++ вместо старого кода C должно быть лучше в любом случае.
@Wisblade: 260 - это MAX_PATH, а не 256. Диск, двоеточие и обратная косая черта, а также trainling \0 должны соответствовать
Вам не обязательно хранить данные в массивах символов, чтобы передавать их (только для чтения) функциям в стиле C. std::string имеет член c_str(), который возвращает const char*, если это работает.
Не связанный с рассматриваемым вопросом - вы можете сделать эту задачу намного сложнее, чем нужно, смешивая код C и C++. Этот код почти полностью написан на языке C с использованием концепций, которые не рекомендуются для любого кода на C++, за исключением символа vector, который, как я полагаю, на самом деле является std::vector. Вы также описываете его как код C, помечая его как C++. Когда этот код не работает, вам нужно будет поговорить с людьми, имеющими опыт работы как с C, так и с C++ (см. предыдущий комментарий, в котором предполагалось, что C++ std::getline, а вы использовали C getline)
Что делает dll со строками, на которые указывают указатели в envp? Он просто читает их или модифицирует?
@ThomasWeller в некоторых версиях Windows, но вопрос помечен как linux, даже если это был новый код Windows, следует предполагать, что путь может вести к совсем немного дальше, а linux имеет максимальную длину дорожка 4096 и длину имени файла 255
@ThomasWeller Это в Linux, так что это 16384, если я хорошо помню - так что это большой буфер - и два примера, которые дал OP, - это просто некоторые базовые назначения переменных (его первый sprintf даже работал ...). Правильным решением должно быть использование std::string и правильное форматирование через std::stringstream, ИЛИ, по крайней мере, использование snprintf и malloc, но для такой простой задачи это может быть излишним.
хорошо, я думал, что для этого есть однострочное решение. Я не ожидал такой путаницы. Вместо этого я попытаюсь использовать совет @Wisblade и отформатировать std::string.
@Mgetz: да, NTFS также поддерживает длинные имена файлов, начиная с Windows 10 1607 (по крайней мере, 5 лет назад) и настраивается через реестр MSDN





Не рекомендую так дико смешивать std::string и старые до-струны. Вместо этого я бы как можно дольше полагался на классы С++:
std::ifstream inputFile("path to file");
if (!inputFile)
{
// error handling
}
std::vector<std::string> lines;
std::string tmp;
while(std::getline(inputFile, tmp))
{
lines.emplace_back(std::move(tmp)); // since C++11, not copying the strings...
}
if (!inputFile.eof())
{
// not the entire file read
// -> error handling!
}
// TODO: size check; what, if not sufficient lines in file?
lines[0] = std::string("SERVER = ") + lines[0];
lines[1] = std::string("DOMAIN = ") + lines[1];
std::vector<char*> envp;
envp.reserve(lines.size());
for(auto& l : lines) // C++11: range based for loop...
{
// note that this ABSOLUTELY requires the library not
// modifying the strings, otherwise undefined behaviour!
envp.emplace_back(const_cast<char*>(l.c_str()));
// UPDATE: this works as well:
envp.emplace_back(l.data());
// the string is allowed to be modified, too – apart from
// the terminating null character (undefined behaviour!)
}
// so far, pure C++...
// now we just get the pointers out of the vector:
libraryFunction(envp.size(), envp.data());
Бонус: вообще никакого ручного управления памятью...
(Примечание: предполагается, что строки нет изменены в библиотеке!)
Мне нужно передать переменную в библиотеку следующим образом: somedllObj.envps = envp; где envps есть char **
это работает envp.emplace_back(l.data()); предложенный l.c_str не работает - ошибка времени компиляции
@BoppityBop Моя вина, const_cast пропала...
что это за чай! :)
@Aconcagua lines[0] = std::string("SERVER=%s") + lines[0]; должно быть lines[0] = std::string("SERVER = ") + lines[0]; или lines[0].insert(0, "SERVER = ");, и то же самое для lines[1].
@BoppityBop "Мне нужно передать переменную в библиотеку следующим образом: somedllObj.envps = envp;" - для этого вы можете использовать somedllObj.envps = envp.data();. Указатель data() в std::vector<char*> является указателем char**.
@RemyLebeau Ошибка копирования-вставки ... Спасибо за подсказку.
Предполагая, что серверы и домены находятся во входном файле, в них нет пробелов, поэтому getline не нужен.
vector<string> lines;
std::ifstream input_file("path to file");
std::copy(std::istream_iterator<std::string>(input_file),
std::istream_iterator<std::string>(),
std::back_inserter(lines));
lines[0] = "SERVER = "s + lines[0];
lines[1] = "DOMAIN = "s + lines[1];
std::vector<char*> envp;
for(auto& line : lines)
envp.emplace_back(line.data());
envp.emplace_back(nullptr); // Usually env arrays end with nullptr, thus +1 to array size
somedllObj.envps = envp.data();
вы не инициализировали элементы
envp