C ++代码在尝试连续两次打印相同的字符串数组时脱口而出两个截然不同的输出

C++ code blurts out two very different outputs while trying to print the same array of strings twice in a row

我正在尝试制作一个简单的控制台 pacman 游戏,但我遇到了来自以下源代码的模糊打印输出:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
int main(){
    std::ifstream map_file;
    int map_width, map_height;
    try{
        map_file.open("map.txt");
    }
    catch(int e){
        std::cout << "An exception occured." << std::endl;
    }
    map_file >> map_width;
    map_file >> map_height;
    char* map[map_height];
    for(int i = 0; i < map_height; i++){
        std::string temp_line;
        getline(map_file, temp_line);
        map[i] = (char*)temp_line.c_str();
        std::cout << map[i] << std::endl;

    }
    system("pause");
    for(int i = 0; i < map_height; i++){
        std::cout << map[i] << std::endl;

    }
    return 0;   
}

我将再次从该代码复制调用 std::cout 的两个 运行,并附上控制台输出内容的屏幕截图:

    for(int i = 0; i < map_height; i++){
        std::string temp_line;
        getline(map_file, temp_line);
        map[i] = (char*)temp_line.c_str();
        std::cout << map[i] << std::endl;

    }

其他打印运行:

    system("pause");
    for(int i = 0; i < map_height; i++){
        std::cout << map[i] << std::endl;

    }

截图如下:系统("pause")之前的文本块是输入map.txt文件的内容,显示的是它在map.txt中的写法,但是第二次打印 运行 完全出乎意料。

我的问题只是可能导致此问题的原因。

编辑:我意识到

map[i] = (char*)temp_line.c_str();

执行浅拷贝,而不是深拷贝,因此我通过动态分配

解决了这个问题
char[map_width + 1]

map[i]

和表演

strcpy(map[i], temp_line.c_str());

我还是很感兴趣,原来的程序怎么可能写出来

ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe
ystem32\cmd.exe

那是因为您的字符串 temp 超出了范围,与之相关的指针 (c_str) 也超出了范围。所以你的 map[i] 指向垃圾数据。您需要使用 strcpy 之类的内容来深度复制内容。请参阅 strcpy 了解如何为此使用 strcpy。 (提示,您需要实际为源字符串和空终止符分配内存)

这也是 UB(未定义行为)。 (尝试打印丢失后的指针,即)

for(int i = 0; i < map_height; i++){
    std::string temp_line;
    getline(map_file, temp_line);
    map[i] = (char*)temp_line.c_str();
    std::cout << map[i] << std::endl;

}

您正在存储 temp_line 变量的内部 c 字符串,但是 temp_line 变量在上述循环的每次迭代后都被销毁。所以基本上,您的 char* 变量数组指向随机垃圾。

std::string map[map_height];
for(int i = 0; i < map_height; i++){
    getline(map_file, map[i]);
    std::cout << map[i] << std::endl;

}
system("pause");
for(int i = 0; i < map_height; i++){
    std::cout << map[i] << std::endl;

}

未定义的行为。您正在存储不再有效的指针:

map[i] = (char*)temp_line.c_str();

如果您的 map 存储了 std::string 值而不是指针,那么这样做就可以了:

map[i] = temp_line;

我还注意到您使用的是可变长度数组。不。请改用 std::vector。初学者最简单的方法是这样做:

std::vector<std::string> map( map_height );
for( int i = 0; i < map_height; i++ )
{
    getline( map_file, map[i] );
}

您可能会怀疑,您看到的 "random garbage" 并不是真正随机的。是的,这是未定义行为的结果,你不应该真正考虑它,但为什么是那些特定的字符序列?

我怀疑这恰好是argv[0]的内容。当 OS 调用应用程序时,它会调用 main 并提供两个参数:argc(参数数量)和 argv(包含命令行参数的数组)。 argv[0] 是您的应用程序的名称。 C:\Windows\System32\cmd.exe 是命令提示符,通常是应用程序的父进程,所以我可以想象 OS 将该字符串写入应用程序的前几块内存中。

因为您的代码使用 int main() 定义而不是 int main(int argc, char* argv[]) 定义,所以您的代码并非旨在访问该内存块,但(并非如此)随机访问指向您的其中一个字符串到堆栈上和程序内存寄存器早期的内存位置。