Mon programme s'arrête sans erreur à l'appel d'une fonction

Résolu/Fermé
Flayme - Modifié le 24 févr. 2023 à 13:39
 Flayme - 24 févr. 2023 à 00:33

Bonjour,

J'ai créé un programme que voici :

main.cpp:

#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include "sha256.h"

void split_(std::string str, char l, std::vector<std::string>&);

int main()
{
	//get login from user
	
	std::string username, password;
	
	std::cout << "Enter your username: ";
	std::getline(std::cin, username);
	std::cout << "Enter your password: ";
	std::getline(std::cin, password);
	
	//read info from file
	
	std::string data, buffer;
	std::ifstream file("code.txt");
	while (std::getline(file, buffer))
	{
	    data += (buffer +"\n");
	}
	data.pop_back();
	//put info in a map

	std::map<std::string, std::string> map;
	std::vector<std::string> dataSplit;
	std::cout << "HERE 1\n";
	split_(data, '\n', dataSplit);

	for (int i = 0; i < dataSplit.size(); i+=2)
	{
	    map[dataSplit[i]] = dataSplit[i+1];
	}
	
	//verify if username in map and if code match
	
	for (std::map<std::string, std::string>::iterator iter = map.begin(); iter != map.end(); iter++)
	{
		if (iter->first == username){
			if (iter->second == sha256(password)) 
			{
				std::cout << "Successfully login !!"; 
				return 0;
			}
			else
			{
				std::cout << "Wrong password !!";
				return -1;
			}
		}
	}
	
	//register if username didn't exist
	std::cout << "Success fully registered!!\n";
	std::ofstream file_out("code.txt", std::ios_base::app);
	std::cout << ("\n" + username + "\n" + sha256(password));
	file_out << ("\n" + username + "\n" + sha256(password));

	return 0;
}

void split_(const std::string str, const char l, std::vector<std::string>& vect) 
{
	std::cout << "HERE 2\n";
    std::string actual;
    for (char letter: str)
    {
        if (letter == l)
        {
            vect.push_back(actual);
            actual = "";
        }
        else
        {
            actual += letter;
        }
    }
    vect.push_back(actual);
}

sha256.h, sha256.cpp: Voir http://zedwood.com/article/cpp-sha256-function

Le programme s'arrête alors qu'il n'y a pas d'erreur. Le programme n'affiche pas non plus "HERE 2" (ce qui est impossible sans erreur). Je pense que c'est la fonction split_ qui bug.

Selon mes recherches c'est un stack overflow mais ma fonction ne s'appelle pas toute seule.

Ce bug mes déjà arrivé avec un programme avec #include <ws2tcpip.h>

Je suis nouveau en C++ (mais pas en programmation). Pouvez-vous m'aider pour mon problème ?

Merci de votre aide,

Flayme

A voir également:

3 réponses

Dalfab Messages postés 706 Date d'inscription dimanche 7 février 2016 Statut Membre Dernière intervention 2 novembre 2023 101
19 févr. 2023 à 01:08

Si le fichier est vide, on n'arrive pas jusqu'à la fonction split(), auparavant la fonction data.pop_back(); est un "undefined behavior" qui tente de supprimer un caractère d'une chaine vide.

1

merci,

je suis (presque) sur que c'est ça, mon fichier est vide quand j'ai fait le test!

merci à vous tous de m'avoir aider.

0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
20 févr. 2023 à 19:20

Bonjour,

Le problème est à mon avis que tu ne fermes pas tes descripteurs fichiers et que du point de vue du C++ tu tentes d'écrire dans un fichier qui est en cours de lecture.

Voici une réécriture (avec quelques ajustements de ton programme). J'ai supposé ici que chaque ligne contenait le login et le mot de passe séparés par un espace. Le programme suppose qu'il n'y a pas d'espace autre que celui qui sépare un login et un mot de passe. On pourrait (sachant qu'un login ne peut comporter d'espace) plutôt chercher le premier espace (voir std::string::find) et splitter ainsi.

#include <iostream>
#include <fstream>
#include <map>
#include <vector>
//#include "sha256.h"

using namespace std;

inline string sha256(const string & s) {
    return s;
}

void split_(const string & str, char l, vector<string>& vect) {
    string actual;
    for (char letter: str) {
        if (letter == l) {
            vect.push_back(actual);
            actual = "";
        } else {
            actual += letter;
        }
    }
    vect.push_back(actual);
}

int main() {
    // Get login from user
    string username, password;
    cout << "Enter your username: ";
    getline(cin, username);
    cout << "Enter your password: ";
    getline(cin, password);

    // Read map from file
    string filename = "code.txt";
    ifstream file("code.txt");
    map<string, string> my_map;
    if (file) {
        string line;
        vector<string> data_split;
        while (getline(file, line))
        {
            split_(line, ' ', data_split);
            my_map[data_split[0]] = data_split[1];
        }
        file.close();
    } else {
        cerr << "Can't read " << filename << endl;
        return 1;
    }

    if (my_map.find(username) != my_map.end()) {
        // Verify if username in map and if code match
        if (my_map[username] == password) {
            cout << "Successfully logged!!";
            return 0;
        } else {
            cout << "Wrong password!!";
            return -1;
        }
    } else {
        // Register if username didn't exist
        cout << "Success fully registered!!\n";
        ofstream file_out("code.txt", ios_base::app);
        if (file_out) {
            cout << username << ' ' << sha256(password) << endl;
            file_out << username << ' ' << sha256(password);
            file_out.close();
        }
    }

    return 0;
}

Quelques éléments d'explications :

  • Il est important de fermer un descripteur fichier après utilisation, uniquement si celui-ci a été ouvert avec succès.
  • J'ai utilisé using namespace std pour éviter d'avoir partout std::. Certains sont contre mais dans un c++ ça n'a pas vraiment d'importance. Par contre il ne faut jamais l'utiliser dans un hpp.
  • J'ai délibérément remplacé ta fonction sha256 par la fonction identité, car elle n'est à mon avis pas liée au problème posé et permet à tout un chacun de reproduire plus facilement ton problème.
  • Il est inutile de passer un paramètre en const si tu le passe par recopie (par exemple c'est le cas de ton char l). Ce qualificatif n'a d'intérêt pratique que si tu veux (dans ce que tu as écrit) valider qu'on ne modifie pas la recopie (donc l'intérêt est limité). Il est généralement utilisé lors d'un passage par pointeur ou par référence (voir const string & str dans le code que je propose) pour s'assurer que la fonction ne modifie pas la donnée passée en paramètre.
  • J'ai distingué le cas où la clé (l'utilisateur) est déjà présente ou non dans la map (contrôle ou ajout d'une clé).
  • J'ai changé le contrôle du login/mot de passe (ton test est en O(n) alors qu'une recherche dans une std::map se fait en O(log(n)).

Bonne chance

1

merci

0
Utilisateur anonyme
18 févr. 2023 à 23:30

Il est possible que le programme se bloque dans la fonction split_ si jamais la variable actual n'est jamais vidée après la dernière ligne de la chaîne str. Cela peut arriver si la chaîne str ne se termine pas par le caractère l spécifié dans la fonction split_. Pour résoudre ce problème, vous pouvez ajouter la ligne vect.push_back(actual) après la boucle for pour ajouter le contenu de actual à vect.

Voici la fonction split_ modifiée pour éviter ce problème :

void split_(const std::string str, const char l, std::vector<std::string>& vect) 
{
    std::string actual;
    for (char letter: str)
    {
        if (letter == l)
        {
            vect.push_back(actual);
            actual = "";
        }
        else
        {
            actual += letter;
        }
    }
    vect.push_back(actual);
}

Si cela ne résout pas votre problème, il est possible que le programme ait une autre erreur ailleurs dans le code. Vous pouvez ajouter des instructions std::cout supplémentaires pour identifier où le programme bloque et pour afficher les variables à chaque étape de l'exécution.


0

merci d'avoir essayé de m'aider mais la seule différence entre ma fonction et la votre est que vous avez enleveé std::cout << "HERE 2\n";

0