Home > database >  sprintf into char* var[1] fails with Segmentation fault
sprintf into char* var[1] fails with Segmentation fault

Time:03-21

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();
  • Related