Search code examples
c++arraysstringcoutpacman

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


I am trying to make a simple console pacman game and I'm experiencing this obscure print output coming from the following source code:

#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;   
}

I will copy the two runs of calling std::cout from that code here again and attach a screenshot of what was output in the console:

    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;

    }

Other printing run:

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

    }

Here comes the screenshot: block of text before the system("pause") is the content of the input map.txt file and is displayed exactly how it is written in map.txt, but the second printing run is totally unexpected.

obscure printout screenshot

My question is simply what could be causing this.

EDIT: I realized

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

performs a shallow, and not a deep copy, thus I fixed the issue by instead dynamically allocating a

char[map_width + 1]

at

map[i]

and performing

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

I am still interested as how could have the original program possibly written

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

Solution

  • Undefined behaviour. You are storing pointers that are no longer valid:

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

    If your map stored std::string values instead of pointers, it would be fine to do this:

    map[i] = temp_line;
    

    I also notice you're using variable-length arrays. Don't. Use a std::vector instead. The easiest way for a beginner would be to do it like this:

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