2016-11-15 1 views
1

J'essaie de faire un simple jeu de console pacman et j'éprouve cette sortie d'impression obscure provenant du code source suivant:Le code C++ libère deux sorties très différentes en essayant d'imprimer le même tableau de chaînes deux fois de suite

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

je copier les deux séries d'appeler std :: cout de ce code ici encore et joindre une capture d'écran de ce qui était sortie dans la 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; 

    } 

Autre tirage d'impression:

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

    } 

Voici la capture d'écran: bloc de texte avant le système ("pause") est le contenu du fichier map.txt en entrée et est affiché exactement comment il est écrit dans map.txt, mais la deuxième impression est totalement inattendu.

obscure printout screenshot

Ma question est tout simplement ce qui pourrait être la cause.

EDIT: J'ai réalisé

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

effectue une faible profondeur, et non une copie profonde, donc je fixe la question en lieu allouer dynamiquement une

char[map_width + 1] 

à

map[i] 

et exécutant

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

Je suis toujours intéressé par la façon dont pourrait avoir le programme original peut-être écrit

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 
+0

Pour votre modification, assurez-vous d'économiser suffisamment d'espace pour le terminateur null (par exemple, temp.length() + 1 espace). Si cela ne fonctionne pas, fournissez votre code le plus à jour. – SenselessCoder

+0

Fait, merci! – tgudelj

+0

Pour référence future, l'utilisation de la suggestion de paddy est préférable car la question est étiquetée avec C++, et l'utilisation de ces méthodes vous aiderait à gérer ces problèmes plus facilement. – SenselessCoder

Répondre

4

Comportement non défini.Vous stockez des pointeurs qui ne sont plus valides:

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

Si vos map stockées std::string valeurs au lieu de pointeurs, il serait bien de le faire:

map[i] = temp_line; 

Je remarque également que vous utilisez la variable - tableaux de longueur. Ne pas. Utilisez plutôt un std::vector. serait de le faire comme le moyen le plus facile pour un débutant ceci:

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

C'est parce que votre chaîne temp va hors de portée et avec elle, le pointeur (c_str) associé va aussi bien. Donc, votre map[i] points aux données de déchets. Vous devez copier en profondeur le contenu avec quelque chose comme strcpy. Voir strcpy pour savoir comment utiliser strcpy pour cela. (Astuce, vous devez réellement allouer de la mémoire pour la chaîne source ainsi que le terminateur null)

C'est aussi UB (comportement indéfini). (Essayez d'imprimer les pointeurs après la perte, qui est)

+0

'strcpy' ne copie pas en profondeur le contenu. – paddy

+0

@paddy Si vous parlez de "par lui-même", eh bien, il vient avec le contrat que vous fournissez suffisamment d'espace dans votre chaîne de destination. Donc, je suppose que ce n'est pas le cas, mais je dirais quand même que cela vous permet de copier en profondeur. – SenselessCoder

+0

Si vous utilisez le terme "copie profonde" en référence aux chaînes, vous indiquez que les allocations de mémoire nécessaires sont également effectuées. Vous avez recommandé de remplacer UB sous la forme de _reads_ illégal avec UB qui effectue à la place des _writes_ illégaux. – paddy

2
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; 

} 

Vous stockez la chaîne interne c de la variable temp_line, mais la variable temp_line est détruit après chaque itération de la boucle au-dessus. Donc, fondamentalement, votre tableau de variables char * pointent vers des ordures aléatoires.

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; 

} 
1

Comme vous pensez probablement, le « hasard ordures » que vous voyez est pas vraiment aléatoire. Oui, c'est la conséquence d'un comportement indéfini et vous ne devriez pas vraiment le considérer, mais pourquoi cette séquence spécifique de caractères? Je soupçonne qu'il s'agit du contenu de argv[0]. Lorsque le système d'exploitation appelle une application, il appelle main et donne deux paramètres: argc (nombre d'arguments) et argv (tableau contenant des arguments de ligne de commande). argv[0] est le nom de votre application. C: \ Windows \ System32 \ cmd.exe est l'invite de commande et est souvent le processus parent d'une application, donc je pourrais imaginer que l'OS a écrit cette chaîne dans les premiers morceaux de la mémoire de l'application. Parce que votre code utilise la définition int main() au lieu de la définition int main(int argc, char* argv[]), votre code n'est pas conçu pour accéder à ce bloc de mémoire, mais (pas si) l'accès aléatoire a pointé l'une de vos chaînes vers cet emplacement de la mémoire qui est sur la pile et au début du registre de la mémoire du programme.