当程序从该函数调谐器时,指向在函数中声明和定义的某些 C 字符串的指针不再有效.为什么?

the pointers to some c-strings, declared and defined in a function, are no longer valid when the program retunrs from that function. Why?

本文关键字:函数 定义 字符串 指针 为什么 有效 不再 声明 调谐器 程序      更新时间:2023-10-16

我想用一些配置数据初始化一个程序。它通过 argv[] 将它们作为 url 编码的 json 接收,对它们进行解码和反序列化,并将它们交给类内的方法,该方法应该将相关变量设置为提交的值。

变量的类型为 c-string,因此我先进行转换,然后再将值分配给在方法外部声明的变量。 如果从指针中读出那些新设置的值,只要我留在此方法中,一切都很好。离开它后,从手动配置数据设置值的变量仅包含垃圾,而从字符串文字填充的变量完全没问题。

我打印了有关变量类型(typeid().name()的信息。虽然它们不一定是人类可读的,但比较显示,它们都是它们应该的类型。接下来比较方法内外指针的值 - 它们是相同的。

/* Config.cpp */
using json = nlohmann::json;
const char *Config::DB_HOST;
const char *Config::DB_USER;
const char *Config::DB_PASSWORD;
const char *Config::DB_NAME;
const char *Config::DB_SOCK;
Config::Config() {}
void Config::initDB(json dbConfig) {
string host = dbConfig["host"];
DB_HOST = host.c_str();
string user = dbConfig["user"];
DB_USER = user.c_str();
string pass = dbConfig["pass"];
DB_PASSWORD = pass.c_str();
string name = dbConfig["name"];
DB_NAME = name.c_str();
DB_SOCK = "/var/run/mysqld/mysqld.sock";
}

我对变量设置的值与字符串文字设置的值之间的差异感到特别困惑。前者失败,后者有效。它们之间有什么区别?在论坛上阅读了一些内容后,我了解到c_str()应该返回与文字完全相同的数据类型(指向数据的以null结尾的指针)。

感谢您的提示!

当你这样做string host = dbConfig["host"];你创建一个函数本地std::string,其中包含dbConfig["host"]返回的内容的副本。 然后,使用c_str()获取指向该本地字符串数据的指针。 在函数结束时,本地字符串被销毁,所以现在你有一个指向垃圾的指针。

另一方面,DB_SOCK = "/var/run/mysqld/mysqld.sock";是不同的。"/var/run/mysqld/mysqld.sock"是一个字符串文字,它具有静态存储持续时间,这意味着它将一直存在到程序结束。 这就是为什么该字段在函数结束后仍然有效的原因。

规则是,除非static函数本地对象,否则不能引用或指向函数本地对象的指针。 如果没有,它会被销毁,留下一个悬空的指针/引用。


如果dbConfig["host"]返回对std::string的稳定引用,则可以使用DB_HOST = dbConfig["host"].c_str();。 如果没有,那么我建议将变量更改为std::string的,以便它们正确复制。

使用以下命令将局部变量存储在成员内部:

string host = dbConfig["host"];
DB_HOST = host.c_str();

所以一旦host超出范围,你就会有悬空的指针。

文字 C 字符串具有静态持续时间,因此您可以将其存储在全局中,而不会出现生存期问题。

您可以将成员从const char*更改为std::string以避免该问题:

std::string Config::DB_HOST;