Home > Software design >  save line from file to char pointer in c , without pointing to variable
save line from file to char pointer in c , without pointing to variable

Time:11-23

This might be a very basic c/c question, but I am really struggeling at it right now.

I have a struct that looks something like this:

struct connection_details {
    const char *server, *user, *password, *database, *mysql_port, *ssh_port;
};

And I have the data in a seperate text file. So I would like to write a function, that takes a pointer to the struct, to write each line of the text file to the corresponding variable of the struct.

void get_config(const std::string &config_path, connection_details *mysql) {
    ifstream file(config_path);
    string str;

    getline(file, str);
    mysql->user = str.c_str();
    getline(file, str);
    mysql->server = str.c_str();
    getline(file, str);
    mysql->database = str.c_str();
    //...
    file.close();
}

But now the char pointer points to a variable that no longer exists, and even if it still existed, every part of the struct would point to the same variabe, not the content it was supposed to be.

I know this is a rather basic question, but I came to the point where I don't now what to google anymore, so every help is welcome.

CodePudding user response:

If you want to store string data in a way that is kept around as long as the struct is alive, then std::string does exactly that. So, ideally, you should replace the const char* members of connection_details with std::string:

struct connection_details {
    std::string server, user, password, database, mysql_port, ssh_port;
}; 

Conveniently, this also allows you to just getline() directly into the members:

void get_config(const std::string &config_path, connection_details *mysql) {
    ifstream file(config_path);

    getline(file, mysql->user);
    getline(file, mysql->server);
    getline(file, mysql->database);
    // ...
    // No need to .close(), it's implicit.
}

Then, you can use .c_str() wherever you would have used the const char*

// Assuming you can't change this...
void some_function(const char* str);

int main() {
  connection_details details;

  get_config("path/to_config.txt", &details);

  // before:
  //some_function(details.server);

  // after:
  some_function(details.server.c_str());
}

Edit: Now, if you have no control over connection_details, then you can still use std::string, but you just have to add a layer of indirection:

struct connection_details {
    const char* server, user, password, database, mysql_port, ssh_port;
}; 

struct connection_details_data {
  std::string server, user, password, database, mysql_port, ssh_port;

  // Make it convertible into connection_details
  operator connection_details() const {
    return {
      server.c_str(), user.c_str(), password.c_str(),
      database.c_str(), mysql_port.c_str(), ssh_port.c_str()
    };
  }
}; 

void get_config(const std::string &config_path, connection_details *mysql) {
  // ...
}


int main() {
  connection_details_data details_data;
  get_config("path/to_config.txt", &details_data);

  // Make sure details_data outlives details!
  connection_details details = details_data;

  // ...
}

CodePudding user response:

Additionally to @Frank's answer with std::string usage, if you can't for some reason use std::string inside structure, then you should do manual low-level C string operations.

Use strdup() function to allocate copy a string. Just change = str.c_str() in your code to = strdup(str.c_str()) and that's it, working solution!

Don't forget to free() all these allocated pointers at the very end of the program, or if you decide strdup other values into this pointers, to avoid memory leaks (if you're not alright with some leaks, then you may decide not to use free()).

#include <cstring>

void get_config(const std::string &config_path, connection_details *mysql) {
    ifstream file(config_path);
    string str;

    getline(file, str);
    mysql->user = strdup(str.c_str());
    getline(file, str);
    mysql->server = strdup(str.c_str());
    getline(file, str);
    mysql->database = strdup(str.c_str());
    //...
    file.close();
}
  • Related