consider code:
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
I am C# dev I havent used C for couple decades. Something obvious is missing. Mem allocation?
P.S. I am mixing "old" char * for strings with std strings as the app uses 3rd party dll with chars*
EDIT declaring char envp[10][512];
fails down the line when I try to assing to the 3rd party property somedllObj.envps = envp;
with cannot convert char[10][512] to char**
CodePudding user response:
I do not recommend mixing std::string
and old C-strings in such a wild manner. Instead I'd rely on C classes as long as possible:
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=%s") lines[0];
lines[1] = std::string("DOMAIN=%s") 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()));
}
// so far, pure C ...
// now we just get the pointers out of the vector:
libraryFunction(envp.size(), envp.data());
Bonus: No manual memory management at all...
(Note: Assuming the strings are not modified in the library!)
CodePudding user response:
Assuming servers and domains are in the input file, they do not have whitespaces, thus getline is not necessary.
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();