J'aimerai lire le contenu de ./fichier, qui contient des entiers organisé en tableau, et faire correspondre chacun de ces entiers à une case dans une matrice de type int grille[5][5]
J'ai donc le code suivant :
machin.c
int main(int argc, char *argv[])
{
int caractereActuel, grille[11][11],i,j;
for (i=0;i<=10;i++) //Remise à zéro de la grille
{
for (j=0;j<=10;j++)
{
grille[i][j]=0;
}
}
FILE* fichier = NULL;
fichier = fopen("fichieraouvrir", "r+");
if (fichier != NULL)
{
do
{
for(i=1;i<=5;i++)
{
for(j=1;j<=5;j++)
{
caractereActuel= fgetc(fichier); // On lit le caractère
printf("%c ", caractereActuel);
grille[i][j]=caractereActuel;
}
}
} while (caractereActuel != EOF); // On continue tant que fgetc n'a pas retourné EOF (fin de fichier)
fclose(fichier); // On ferme le fichier qui a été ouvert
}
else
{
// On affiche un message d'erreur si on veut
printf("Impossible d'ouvrir le fichier test.txt");
}
printf("\nAffichage de la matrice ... \n");
for (i=0;i<=5;i++)
{
for (j=0;j<=5;j++)
{
printf("%d ",grille[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}
fichier :
00200
01000
00000
10030
00050
Evidemment, ca ne marche pas ....
en console ca me donne :
gcc machin.c && ./a.out
0 0 2 0 0
0 1 0 0 0
0 0 0 0 0
1 0 0 3 0
0 0 0 5 0
� � � � � �
Affichage de la matrice ...
48 48 50 48 48 10
48 49 48 48 48 10
48 48 48 48 48 10
49 48 48 51 48 10
48 48 48 53 48 10
-1 -1 -1 -1 -1 -1
Donc je voudrais savoir qu'est ce qui va pas :D Un probleme de pointeur, ou de type de donnée, ou une mauvaise utilisation de fgetc ? fscanf est-elle plus appropriée ici ?
C'est dans le cadre d'un petit projet pour ma premiere année d'IUT, donc j'ai pas forcement toutes les notions necessaires ... ca doit donc etre un peu crade comme code ?
Merci d'avance :)
# Nombre d'itérations trop important
Posté par teddyredm3cl . Évalué à 3.
En fait ton problème vient du fait que dans tes boucles for tu teste inférieur ou égal, ce qui signifie que tu va boucler pour i = 0,1,2,3,4 et 5, soit 6 itérations.
En l'occurrence cela fonctionne car dans ton fichier texte, les 5 premiers champs sont tes nombres, et le sixième champs correspondant à i=5 est le saut de ligne, d'où son affichage comme 10 quand tu demande son passage en entier (10 est le nombre associé à \n en ascii, cf man ascii)
Quand à la sixième ligne composée de -1, je suppose qu'il s'agit de la conversion de NULL vers entier.
Essaye ton code en remplaçant ton inférieur ou égal par un inférieur strict, cela devrait régler le problème.
[^] # Re: Nombre d'itérations trop important
Posté par Calve . Évalué à 2.
J'ai donc remplacé mes 'inferieurs ou égal' par des 'strict inferieur' dans mes doubles boucle ... hélas, ca ne fait qu'empirer :
Affichage de la matrice ...
48 48 53 48 10
-1 -1 -1 -1 -1
-1 -1 -1 -1 -1
-1 -1 -1 -1 -1
-1 -1 -1 -1 -1
Je suppose aussi que les 48, 53 est autres correspondent aux valeurs ASCII de 0,1,2 ...
Comment je peux avoir directement 0,1 plutot que leur valeurs ASCII ? Ma variable caractereActuel est pourtant bien un int, je comprend pas quelle change de valeur entre
printf(%c , caractereActuel); (qui me donne bien le nombre contenu dans le fichier)
et
grille[i][j]=caractereActuel;
[^] # Re: Nombre d'itérations trop important
Posté par teddyredm3cl . Évalué à 4.
Par ailleurs, comme indiqué plus bas, attention à la différence entre un chiffre affiché par ton terminal, et la valeur du code qui le représente en mémoire. Le C est très permissif, donc si tu demande quelque chose de bizarre (afficher un entier comme un caractère par exemple), il te fait confiance. Un grand pouvoir implique de grandes responsabilités de lire pas mal de documentation.
Je te conseille de te renseigner sur les options de gcc, il est capable de générer des avertissements sur les erreurs courantes. Au minimum -Wall qui active tous les warnings.
# confusion entre cast et conversions
Posté par BuZZ . Évalué à 4.
Je rajouterais que si tu t'attends à retrouver la valeur des entiers de ton fichier dans ta matrice, il faut convertir tes données lues (des char) en entier (int) et pas faire un simple cast (comme c'est fait implicitement dans ton code).
Pour rappel (si on veut vraiment revenir à la racine), en ASCII :
valeur d'un chiffre entier = codes ASCII du caractère représentant le chiffre - '0'
Si tu débutes, je te laisse chercher les détails sur le net, c'est comme ça que tu apprendras vraiment (enfin c'est mon avis, surtout pour des trucs de bases comme ça, la doc foisonne)
# Code bon :)
Posté par Calve . Évalué à 5.
int main(int argc, char *argv[])
{
int grille[11][11],i=0,j=0,m=0;
char caractereActuel;
for (i=0;i<=10;i++)
{
for (j=0;j<=10;j++)
{
grille[i][j]=0;
}
}
FILE* fichier = NULL;
//Réinitialisation des variables
i=0;
j=0;
fichier = fopen("fichieraouvrir", "r+");
if (fichier != NULL)
{
do
{
for(j=0;j<=5;j++)
{
caractereActuel= fgetc(fichier); // On lit le caractère
m=caractereActuel-'0';
printf("i = %d, j = %d, m = %d \n",i,j,m);
//sprintf(intermediaire,"%c",caractereActuel);
if (m==-38) //Si l'entier est un retour à la ligne, on change de ligne
{
i++;
}
else //Si non, on l'écrit a sa place dans la matrice
{
grille[i][j]=m;
}
}
} while (caractereActuel != EOF); // On continue tant que fgetc n'a pas retourné EOF (fin de fichier)
fclose(fichier); // On ferme le fichier qui a été ouvert
}
else
{
// On affiche un message d'erreur si on veut
printf("Impossible d'ouvrir le fichier test.txt");
}
printf("\nAffichage de la matrice ... \n");
for (i=0;i<5;i++)
{
for (j=0;j<5;j++)
{
printf("%d ",grille[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}
Qui fontionne bien comme il faut :) Je me suis pris la tete avec atoi(), mais je n'en ai visiblement pas besoin :)
Aussi, je n'avais pas réaliser que je liser les caracteres colones par colones, et non ligne par ligne. Je règle ce problème en bouclant sur j, et non sur i.
Est ce que ce code est potable, ou alors je peut l'améliorer ? Je pense notamment au changement de ligne ... vous auriez fait comme moi ? ou autrement ?
Merci de votre aide en tout cas :)
[^] # Re: Code bon :)
Posté par totof2000 . Évalué à 7.
- tu ne viens pas en nous demandant de faire ton travail : tu as déjà commencé à travailler et tu nous indiques précisément ce qui te gène.
- tu as exploré les pistes que les intervenants t'ont données pour corriger ton code
- et sutout tu as diffusé le résultat (pour les curieux) et remercié les gens qui t'ont aidés.
Ca devient de plus en plus rare les gens comme toi ;)
[^] # Re: Code bon :)
Posté par benoar . Évalué à 2.
- atoi() aurait pu servir, si tu avais des nombres qui tiennent sur plus d'un caractère (en fait, ce ne seraient plus des "chiffres"), mais comme il travaille sur des chaînes C, il aurait fallu lui fournir soit des chaînes terminées par \0. Bref, dans ton cas, c'est cool ça marche bien avec l'astuce c-'0'.
- Pour les boucles, avec l'expérience, j'ai appris à toujours commencer par 0 et à utiliser quasi uniquement des strictement inférieur. Pour moi c'est beaucoup plus lisible.
- fgetc() est un peu "bancal" dans le signalement d'EOF, et une utilisation correcte voudrait que tu récupères d'abord un int, le teste voir si ce n'est pas un EOF, et _après_ tu cast vers un _unsigned_ char, qui est la manière la plus "naturelle" de bosser sur des caractères ASCII (ton -38 pour le retour à la ligne je trouve ça moche par rapport à un '\n' ... d'ailleurs pourquoi -38 ? ça a l'air de correspondre à rien de très logique ...) et te permettera surtout de différencier un caractère 0xff dans ton fichier par rapport à la vraie fin du fichier.
- D'un autre coté, si tu sais que tu auras _exactement_ 6 caractères sur une ligne (5 chiffres + un LF), t'as pas besoin de faire de test du tout, juste un getc() dans le vide.
- Mais bon, on voit bien que t'essayes de te soucier un peu des cas d'erreurs possibles, mais il reste encore plein de "failles" si tu voulais faire un truc robuste. D'un côté, ce n'est peut-être pas ton objectif ...
[^] # Re: Code bon :)
Posté par Calve . Évalué à 2.
Justement, maintenant j'ai des entiers de plus de deux caractères :D
Du coup, j'attend que fgetc me renvoit 32 pour changer la colone où écrire ...
J'ai suivi ton conseil sur le -38 et le '\n' aussi, je n'avais pas pensé à ca. C'est effectivement plus lisible et compréhensible.
En revanche, j'ai un peu de mal a saisir la récupération de l'int, le test et après le cast ...
le code parlera peut etre plus :) (j'ai enlevé le "pas necessaire")
#include <stdio.h> /* Librairie d'entrée sortie */
#include <stdlib.h> /* Librairie de fonctions standard */
#define SP 32
int main(int argc, char *argv[])
{
int grille[11][11],i=0,j=0,entier=0,findefichier=0;
char caractereActuel;
//Réinitialisation de la matrice
//Réinitialisation des variables
i=0;
j=0;
fichier = fopen("fichieraouvrir", "r");
if (fichier != NULL)
{
while (findefichier==0)
{
caractereActuel= fgetc(fichier);
if (caractereActuel != EOF)
{
entier=caractereActuel-'0';
printf("i = %d, j = %d, m = %d \n",i,j,entier);
//sprintf(intermediaire,"%c",caractereActuel);
if (caractereActuel=='\n') //Si l'entier est un retour à la ligne, on change de ligne
{
i++;
j=0;
}
else if (caractereActuel == SP) //Si l'entier est un espace, on change de colone
{
j++;
}
else //Si non, on l'écrit a sa place dans la matrice
{
grille[i][j]=(10*grille[i][j])+entier;
}
}
else if (caractereActuel == EOF)
{
fclose(fichier); // On ferme le fichier qui a été ouvert
findefichier=1;
}
}
}
else
{
// On affiche un message d'erreur si on veut
printf("Impossible d'ouvrir le fichier test.txt");
}
//Affichage de la matrice
return 0;
Ainsi, pour le fichier
0 0 2 0 0
0 1 0 0 0
0 0 25 0 0
1 0 0 3 0
0 0 0 5 0
ca me donne bien
bash-3.2$ gcc manipulationfichier.c && ./a.out
Affichage de la matrice ...
0 0 2 0 0
0 1 0 0 0
0 0 25 0 0
1 0 0 3 0
0 0 0 5 0
Mais en effet, le but n'est pas de faire un truc "super robuste", il s'agit d'un petit projet de pacman dans le cadre des cours, et ce bout de code est pour le chargement du niveau, qui est contenu dans un fichier ...
Bonne soirée
[^] # Re: Code bon :)
Posté par benoar . Évalué à 2.
- Tu peux écrire la plupart des caractères de manière "lisible", pas besoin de mettre directement leur code ASCII : pour espace par exemple, met
if (caractereActuel == ' ')
- Pour l'histoire du fgetc() et de l'int : dans le man de fgetc, tu vois que son type de retour est 'int'. Quand tu lis un peu plus loin, il est dit que cette fonction renvoie soit "un unsigned char transformé en int", soit "EOF". C'est parce qu'un caractère peut prendre la valeur 0 à 255 (ou -128 à 127 pour un non signé, mais c'est pareil), et que là tu n'as pas la "place" de caser une valeur pour EOF. Donc, fgetc() renvoit un int, qui vaudra soit -1 (pour EOF, mais t'es pas censé le savoir ; oublie le, mais en pratique ça dépanne des fois) soit de 0 à 255 (pour un caractère normal). Dans ton code, tu cast directement vers un char, donc tu ne "verras" pas la différence entre le caractère 0xff (ou 255)(ou -1) et EOF. Bon, tu vas me dire, au final, tu t'en fous, tu ne gère pas ce caractère. Mais pour une prochaine fois où tu liras des flux "binaires", fais-y attention. Dans ton code, il suffirait à priori de changer la déclaration de caractereActuel en int.
- Enfin, dans ta gestion de fin de fichier, je bouclerais simplement sur un
while (caractereActuel != EOF)
et je fermerait le fichier après. Bon, ça c'est vraiment pour le style, genre j'ai envie de raccourcir le code ; ton code reste tout à fait fonctionnel (juste que l'alternative à ton test sur EOF qui reteste sur != de EOF, ça fait un peu "moche").Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.