首页 > 解决方案 > 两次调用函数会产生段错误(与 char* 到字符串的转换有关)

问题描述

我想"%LOCALAPPDATA%/test.txt"用 Windows 环境路径扩展一个字符串 ( )。以下函数原则上可以完成这项工作,但是使用相同的输出字符串再次调用它(或在调用函数之前为输出字符串分配一些值)会产生段错误。

char*显然,通过转换为,我犯了一些(可能非常糟糕)错误std::string,但我真的不明白这里发生了什么(除了一些内存地址稍后不可用的事实之外)。

#include "processenv.h"

void expandWindowsString(const std::string &input, std::string &output)
{
    const char* in = input.c_str();
    char* out;
    ExpandEnvironmentStrings(in, out, 1024);
    output = out;
}

int main(int argc, char *argv[])
{
    std::string path;
    expandWindowsString("%LOCALAPPDATA%/test.txt", path);
    std::cout << "path is " << path << std::endl;
    //works fine so far, but if I execute the function again (with 'path') or initialising path beforehand with std::string path = "", a segfault occurs.
    expandWindowsString("%LOCALAPPDATA%/test.txt", path); // commenting out this line, makes the code work.
    std::cout << "path is " << path << "\n";
}

标签: c++stringwinapisegmentation-faultchar

解决方案


正如文档所解释的:

lpDst

一个指向缓冲区的指针,它接收在lpSrc缓冲区中展开环境变量字符串的结果。

缓冲区需要由调用者提供,而代码只是传递一个未初始化的指针,同时诱使系统相信它指向大小为 1024 字节的内存。

一个简单的解决方法是:

void expandWindowsString(const std::string &input, std::string &output)
{
    const char* in = input.c_str();
    char out[1024];
    ExpandEnvironmentStrings(in, out, 1024);
    output = out;
}

有很大的改进空间,例如

  • 使用Unicode 版本
  • 处理错误(如文档中所述)
  • 重复增长输出缓冲区以防 API 调用返回的值大于提供的缓冲区长度
  • std::string使用指针和长度构造 a
  • 返回一个值而不是使用 out 参数

至于为什么第二次调用失败:这是一个毫无意义的问题。代码通过写入未初始化的指针表现出未定义的行为。这样,任何结果都是可能的,包括看起来像预期工作的代码。


推荐阅读