Pour moi, tu va chercher beaucoup de difficulté là où il n'y aurait pas lieu d'en trouver.
Et il y a, en outre, pas mal de place pour le progrès
Je vais donc commencer par faire quelques remarque, je t'indiquerai la manière de les prendre en compte juste après .
La première remarque est qu'il est toujours préférable d'utiliser les possibilités issues du C++ plutôt que l'équivalent "C style"...
Cela signifie que, de manière générale, tu auras toujours intérêt à utiliser la std::string plutôt qu'un tableau de caractères char* ou char[taille], et que tu aura sans doute largement intérêt à utiliser un std::vector<int> plutôt qu'un int* (ou un int**)
En ce qui concerne les chaines de caractères, s'il se fait que tu dois récupérer une chaine "C style" (pour l'ouverture d'un fichier, par exemple), ce n'est pas une raison pour préférer le char[], car tu peux la récupérer grace à la méthode c_str()
La deuxième remarque est qu'il est souvent préférable de travailler en respectant le principe du RAII (Ressource Aquisition Is Initialisation, ou, si tu préfères en français, l'acquisition de ressources sert d'initialisation).
C'est particulièrement vrai pour les flux de fichier.
Ainsi, plutôt que de travailler en deux temps sous la forme de
1 2
| std::ifstream file;
file.open(filename.c_str()); |
il est souvent préférable de donner directement le nom du fichier à ouvrir dans le constructeur, et de se contenter d'un "simple"
std::ifstream file(filename.c_str());
Si tu as un doute sur l'existence du fichier à ouvrir, le plus facile est sans doute de lancer une exception si la variable est invalide, sous une forme proche de
1 2 3
|
if(!file)
throw l_exception_choisie; |
Evidemment, cela signifie que, l'appel de la fonction qui risque de lancer une exception devrait se trouver dans un bloc try... catch, soit parce que la fonction appelante peut gérer l'exception, soit pour la faire remonter la pile d'appel
Ensuite, comme je l'ai indiqué plus haut, il devient rapidement ingérable de devoir gérer une matrice dans la représentation "classique" que l'on peut en avoir (à savoir un tableau composé de "lignes" et de "colonnes").
Si, pour chaque ligne, il y a systématiquement le même nombre de colonnes, le mieux est de gérer cette matrice sous la forme d'un tableau dont le nombre d'élément est (nombre_de_lignes * nombre_de_colones) et d'utiliser la formule (nombre_de_colonnes*index_ligne_recherchée + index_colonne_rechercée) pour accéder à un élément particulier.
Cette approche présente l'énorme avantage de... rendre l'utlisation d'un "simple" vecteur d'entier tout à fait naturelle et de lui donner une facilité extrême
Visiblement, tu envisage de travailler de manière systématique avec des matrices carrées (vu que tu n'indiques qu'un seul nombre, qui sert à la fois de nombre de lignes et de nombre de colonnes)...
Quoi qu'il en soit, du fait que le nombre de lignes et de colonnes est disponible dans le fichier, il semble "naturel" de prévoir une gestion "dynamique" (même si elle est prise en charge par une classe particulière) du nombre d'éléments qui composent la matrice.
Si tu dois commencer à jouer avec des new[] et des delete[], tu va perdre un maximum de temps et courir un maximum de risques pour, seulement, arriver à gérer correctement la mémoire, ce qui plaide, une fois encore, pour l'utilisation de la classe vector
Par contre, le fait que tu récupère le nombre de lignes et de colonnes dont est composée ta matrice fait qu'il deviendra finalement plus logique de travailler avec deux boucles imbriquées (la première gardant le nombre de lignes lues et la seconde s'occupant de compter le nombre de colonnes lue dans la ligne) pour la lecture du fichier que de travailler sur une boucle réagissant sur... une erreur de lecture (eof, en l'occurence), et ce, d'autant plus que, lorsque eof est activé, c'est... que tu as déjà une lecture qui n'a pas pu s'effectuer
Tout cela pour dire qu'il y a vraiment moyen de simplifier énormément la fonction de lecture, sous une forme finalement fort proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| /** fonction de lecture de la matrice dans un fichier
* @ in-out: un vecteur contenant les éléments de la matrice
* un entier représentant le nombre de lignes et de colonnes
* @ in : le nom du fichier à lire
* @ throw: std::invalid_argument si le fichier n'existe pas
* std::runtime_error si une erreur survient lors de la lecture
* du fichier
*/
void readFile(std::vector<int>& matrix, int& size, const std::string& filename)
{
/* ouvrons le fichier en lecture */
std::ifstream file(filename.c_str());
/* si le fichier n'est pas ouvert, c'est pas bon :-P */
if(!file)
throw invalid_argument("nom de fichier incorrect");
/* nous voulons récupérer la première ligne comme "titre" */
std::string titre;
std::getline(file,titre);
/* affichons la pour nous rassurer */
std::cout<<titre<<std::endl;
/* récupérons le nombre de lignes et de colonnes */
file>>size;
/* et affichons le */
std::cout<<size<<" lignes et "<<size<<" colonnes seront lues"<<std::endl;
/* utilisons une boucle incrémentale pour compter les lignes
*/
for(int lignes=0;lignes<size;++lignes)
{
/* qui contient une boucle pour chaque colonne de la ligne */
for(int colonnes=0;colonnes<size;++colonnes)
{
/* qui lit l'élément, lance une exception si la lecture échoue
* et insère l'élément dans la matrice
*/
int elem;
if(!file>>elem)
throw std::runtime_error("erreur de lecture de l'element");
matrix.push_back(elem);
}
}
/* voilà, c'est fini :D */
} |
En outre, il faut savoir que la fonction main() renvoie d'office une valeur de type int au système d'exploitation.
Il existe normalement trois valeurs possibles, mais seule les deux premières sont utilisées sous windows:
- 0 l'application s'est correctement terminée
- 1 l'application s'est terminée sur une erreur
- 2 l'application s'est terminée sur un avertissement (unixoides uniquement)
Il n'est en outre pas nécessaire de préciser le type void dans la liste d'arguments si la fonction n'en nécessite aucun (une autre signature "classique" étant int main(int argc, char *argv[]) )
L'appel de cette fonction pourrait se faire sous une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int main()
{
/* le vector qui contiendra les éléments de la matrice*/
std::vector<int> matrix;
/* le nombre de lignes et de colonnes (nous considérons une matrice
* carrée
*/
int size;
/* indiquons le fichier à lire "en dur" (il est facile de modifier cela
* pour laisser le choix à l'utilisateur ;)
*/
try
{
readFile(matrix, size,"ficier.txt");
}
catch(std::exception& e)
{
std::cout<<e.what();
return 1;
}
return 0;
} |
Partager