在将其存储到 char* 之前,控制台会在同一代码上显示问号

console display question marks on same code before storing it to char*

tnis 是一个长函数,但关键问题在 char* 变量中。 **在我将其转换为存储数据而不是打印到控制台之前,该功能运行良好。

我曾尝试使用 char[] 而不是 char* 那是我遇到一些缓冲区溢出错误的时候,所以现在当它被分配时,它显示 ???整个控制台。 在 puts();

上连接和使用 char* 的正确方法是什么
MySystemInfo Msi;
puts(Msi.getOsInfo());

char* MySystemInfo::getOsInfo()
{
    OSVERSIONINFOEX osver;
    BOOL bOsVersionInfoEx;
    HKEY hKey;
    LONG lRet;
    char* RtTmpOsInfo= (char *) malloc(sizeof(char)*70);
    char* s1=(char *) malloc(sizeof(char)*20);
    char* s2=(char *) malloc(sizeof(char)*50);


    // Try calling GetVersionEx() using the OSVERSIONINFOEX structure.
    // If that fails, try using the OSVERSIONINFO structure.
    ZeroMemory(&osver, sizeof(OSVERSIONINFOEX));
    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    if(!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osver)))
    {
        osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
        if(!GetVersionEx((OSVERSIONINFO *) &osver))
            return "";
    }


    switch (osver.dwPlatformId)
    {
        //Test for the Windows NT product family.
        case VER_PLATFORM_WIN32_NT:

            if(osver.dwMajorVersion <4> BUFSIZE) return "";
            sprintf( s1,"v%d.%d "+ osver.dwMajorVersion, osver.dwMinorVersion);
            // Test for the specific product family.
            if(osver.dwMinorVersion==0){
                if(osver.dwMajorVersion == 5) sprintf(s2,"Microsoft Windows 2000\n");
                else if(osver.dwMajorVersion == 6) sprintf(s2,"Microsoft Windows Vista\n");
            }

            else if(osver.dwMinorVersion==1){
                if(osver.dwMajorVersion == 5) sprintf(s2,"Microsoft Windows XP\n");
                else if(osver.dwMajorVersion == 6) sprintf(s2,"Microsoft Windows 7\n");
            }
            else if(osver.dwMinorVersion==2){
                if(osver.dwMajorVersion == 5) sprintf(s2,"Microsoft Windows Server 2003 family\n");
            }
            else sprintf(s2,"unknown OS\n");
        break;

    }
    strcat(RtTmpOsInfo,s1);     
    strcat(RtTmpOsInfo,s2);

    //lRet/* = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Hotfix\Q246009", 0, KEY_QUERY_VALUE, &hKey);
    //  printf("Service Pack 1 (Build %d)\n", osver.dwBuildNumber & 0xFFFF);*/

    return RtTmpOsInfo;
}

std::strcat 在目标缓冲区中查找空字节。但是,RtTmpOsInfo 指向的缓冲区未初始化,因此对其调用 std::strcat 会导致未定义的行为。

而不是第一个 std::strcat 调用,只使用

strcpy(RtTmpOsInfo,s1);

或者,如果您不确定 s1 是否真的有一个空字节,

strncpy(RtTmpOsInfo, s1, SOME_CONSTANT);

其中 SOME_CONSTANT 是写入 RtTmpOsInfo 的最大字节数。

由于您将此问题标记为 [c++] 而不是 [c],我建议您放弃使用难以 read/use/maintain 原始 C 类字符串缓冲区(以及相关的不安全字符串函数,如 strcat),而是使用 方便的 C++ 字符串 class.

例如,您可以使用 std::string 并且可以 return 一个 std::string 实例而不是原始 char* 实例(所有问题都与一个 char* 原始指针!)。

您可以使用 std::string 的重载 operator++= 连接子字符串,以一种非常直观自然的方式。

或者您可以使用 std::ostringstream class,并使用流语义构建整个字符串,operator<<.

在这种情况下,一旦你的整个字符串组成,你可以调用 ostringstream::str() 方法来获得一个 std::string 实例 return发送给来电者。

这样,你的代码会更简单、更清晰、更不容易出错。