【问题标题】:save line from file to char pointer in c++, without pointing to variable在c ++中将文件中的行保存到char指针,而不指向变量
【发布时间】:2022-01-01 08:02:27
【问题描述】:

这可能是一个非常基本的 c/c++ 问题,但我现在真的很努力。

我有一个看起来像这样的结构:

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

我将数据保存在单独的文本文件中。 所以我想写一个函数,它接受一个指向结构的指针,将文本文件的每一行写入结构的相应变量。

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();
}

但是现在 char 指针指向一个不再存在的变量,即使它仍然存在,结构的每个部分都会指向同一个变量,而不是它应该是的内容。

我知道这是一个相当基本的问题,但我已经到了现在无法再用谷歌搜索什么的地步了,所以欢迎大家提供帮助。

【问题讨论】:

  • 为什么不把成员也设为std::strings 呢?
  • @Frank 因为人类是由众神创造来取悦他们的。主要是通过毫无意义的痛苦。

标签: c++ pointers char


【解决方案1】:

如果您想以一种只要结构处于活动状态就一直保留的方式存储字符串数据,那么std::string 正是这样做的。因此,理想情况下,您应该将connection_detailsconst char* 成员替换为std::string

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

方便的是,这也允许您直接将getline() 加入会员:

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.
}

然后,您可以在使用const char* 的任何地方使用.c_str()

// 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());
}

编辑:现在,如果您无法控制connection_details,那么您仍然可以使用std::string,但您只需添加一个间接层:

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;

  // ...
}

【讨论】:

  • 感谢您的详细解答!
【解决方案2】:

除了@Frank 对std::string 用法的回答,如果由于某种原因你不能在结构中使用std::string,那么你应该手动进行低级C 字符串操作。

使用strdup() 函数分配+复制一个字符串。只需将代码中的 = str.c_str() 更改为 = strdup(str.c_str()) 即可,工作解决方案!

不要忘记free()所有这些分配的指针在程序的最后,或者如果你决定将其他值strdup到这个指针中,以避免内存泄漏(如果你对一些泄漏不满意,那么你可以决定不使用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();
}

【讨论】:

  • 虽然这在技术上是正确的,但我认为跳过一两圈来使用纯粹基于 RAII 的解决方案是值得的,即使只是为了异常安全。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 2011-04-24
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多