Код C ++ стирает два очень разных вывода при попытке напечатать один и тот же массив строк дважды подряд

Я пытаюсь сделать простую консольную игру 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;

}

Вот снимок экрана: блок текста перед системой («пауза») является содержимым входного файла 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

1

Решение

Неопределенное поведение. Вы храните указатели, которые больше не действительны:

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] );
}
4

Другие решения

Это потому, что ваша строка temp выходит из области видимости и вместе с ним указатель (c_str) связанный с этим идет также. Так что ваши map[i] указывает на мусорные данные. Вам нужно глубоко копировать содержимое с чем-то вроде strcpy, Увидеть зЬгсру о том, как вы можете использовать strcpy для этого. (Подсказка, вам нужно фактически выделить память для исходной строки, а также для нулевого терминатора)

Это также UB (неопределенное поведение). (Пытаясь напечатать указатели после потери, то есть)

3

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;

}

Вы сохраняете внутреннюю строку c переменной temp_line, но переменная 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;

}
2

Как вы, вероятно, подозреваете, «случайный мусор», который вы видите, на самом деле не случайный. Да, это следствие неопределенного поведения, и вы не должны это учитывать, но почему именно эта конкретная последовательность символов?

Я подозреваю, что это происходит из-за содержания argv[0], Когда ОС вызывает приложение, оно вызывает main и дает два параметра: argc (количество аргументов) и argv (массив, содержащий аргументы командной строки). argv[0] это название вашей заявки. C: \ Windows \ System32 \ cmd.exe является командной строкой и часто является родительским процессом приложения, поэтому я мог представить, что ОС записала эту строку в первые несколько частей памяти приложения.

Потому что ваш код использует int main() определение вместо int main(int argc, char* argv[]) По определению, ваш код не предназначен для доступа к этому блоку памяти, но (не так) произвольный доступ указал одну из ваших строк на то место памяти, которое находится в стеке и в начале регистра памяти программы.

1
По вопросам рекламы [email protected]