Je suis actuellement en train de suivre le cours du langage C et je bute sur la fonction fgets.
J'ai bien compris qu'elle lit ligne par ligne mais le concept du paramètre tailleMaximale m'échappe.
Je vous explique :
Je compile le code suivant :
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_MAX 1000
int main(int argc, const char *argv[])
{
FILE *fichier=NULL;
char c_ligne[10]="";
// fichier = fopen("text.txt", "w"); // Ouverture pour écriture
fichier = fopen("text.txt", "r"); // Ouverture pour lecture
if(fichier!=NULL)
{
printf("Le fichier a bien ete ouvert !\n");
while(fgets(c_ligne, 10, fichier)!=NULL) // Lit ligne par ligne tout le fichier jusqu'à rencontrer un NULL qui indique la fin du fichier
{
printf("%s", c_ligne);
}
fclose(fichier);
}
else
{
printf("Le fichier ne s'est pas ouvert !\n");
}
return 0;
}
Voici le fichier text.txt :
Hello bienvenue
Salut voici un texte dans mon fichier
Ceci est la seconde ligne du fichier
C'est la dernière ligne du fichier
De ce que je comprends, il est censé ouvrir le fichier "text.txt", et lire ligne par ligne maximum 10 caractères et m'afficher la chaîne de 10 caractères à chaque fois.
Or quand je compile et exécute le code, bah il m'affiche tout le texte du fichier et pas seulement 10 caractères.
Je ne saisis pas trop l'utilité de ce paramètre, mise à part qu'il doit être identique à la taille que j'ai déclaré pour mon tableau de char.
J'ai testé en mettant une taille supérieure dans ma fonction par rapport à la taille du tableau et j'ai bien une erreur de segmentation.
J'ai testé aussi avec une taille inférieure dans ma fonction par rapport à la taille du tableau et cela m'affiche toujours tout le texte.
Ah ok, je pensais qu'on ne lisait uniquement que 10 caractères puis que la fonction passait à la prochaine ligne oubliant tout ce qui restait sur la ligne.
Attention que fgets(c_line, 10, fichier); ne lit qu'au plus 10-1 caractères, de manière à pouvoir mettre un '\0' à la fin sans faire de débordement (source <-- en anglais)
Edit: orthographe
- Edité par edgarjacobs 12 avril 2024 à 23:38:46
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
J'ai continué le cours et dans le chapitre de la saisie sécurisée de texte, la fonction est réutilisée avec stdin cette-fois-ci.
J'ai voulu tester pour voir de mettre le second paramètre "num" plus grand que la taille de mon tableau (Imaginons dans le cas où mon tableau et ce paramètre ne soient plus identiques)
Jai donc fait ça :
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *agrv[])
{
char nom[8]={0};
printf("Quel est votre nom ?\n");
fgets(nom, 15, stdin);
printf("Vous vous appelez donc %s\n", nom);
printf("%d\n", sizeof(nom));
return 0;
}
Lorsque je tape un prénom + nom de plu de 15 caractères, pas de problème, la fonction me renvoie bien 15 caractères (ligne 3 de la photo), j'affiche le tableau "nom" mais dedans il y a le contenu de stdin si j'ai bien compris.
Mais quand je regarde la taille de mon tableau, il est toujours d'une taille de 8.
Et si j'affiche l'entièreté de mon tableau, alors j'ai un texte de 15 caractères qui apparaît et pas seulement 8 (-1 caractère pour le caractère de fin de chaîne)
Ma question est : que se passe-t-il au niveau de ce tableau ? Ai-je fait un dépassement de mémoire, mon tableau a-t-il changé de taille (Normalement non) ? Pourquoi il n'enregistre et n'affiche pas seulement 8 caractères comme défini au début ?
Ton tableau a une taille de 8 qui ne changera pas.
Toi tu y écris plus de 8 caractères, ça va donc écrire les caractères suivant à la suite en dehors de ton tableau. C'est ce qu'on appelle un UB (undefined behavior). Et la tout peux ce passer, un plantage de ton programme, des comportements étranges , comme rien du tout.
Il ne faut donc jamais écrire en dehors d'un tableau !
Terence01 a écrit:
Pourquoi il n'enregistre et n'affiche pas seulement 8 caractères comme défini au début ?
Tu dis a fgets d'écrire 15 caractères (s'il y a) il en écrit 15. fgets ne connait pas la taille du tableau.
Ok merci de l'info, donc on on peut déborder si on ne fait pas attention, il faut toujours faire correspondre la taille du tableau avec la longueur qu'on récupère pour le 2nd paramètre si je comprends bien (par mesure de sécurité).
Donc le mieux serait de passer tout le temps en paramètre la taille de mon tableau avec un sizeof(nom) par exemple ?
L'erreur, c'est que str_data est un pointeur, et non un tableau de caractères. Donc le sizeof(str_data) renverra la taille d'un pointeur (4 ou 8 octets), et non le 31 espéré.
- Edité par edgarjacobs 22 avril 2024 à 19:37:22
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
[....] ou alors mettre 31 ici dans ce code sera la meilleure chose à faire ?
Il faut absolument éviter les "nombres magiques" (ceux qui sont codés en dur dans le code). Bon, moi je l'ai fait, car ce n'est qu'un code de démonstration.
Pour "contourner" le problème, il y a le bon vieux #define:
C'est propre. Et si tu veux changer la taille de la variable, pas besoin de relire tout le code, au risque d'oublier une occurence du 31 ou d'en modifier une qui n'en avait pas besoin: il suffit de modifier le #define et de recompiler. Et les #define, on peut en utiliser à foison.
Edit: edit supprimé, pas d'intérêt ici
- Edité par edgarjacobs 16 avril 2024 à 20:59:12
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Quand j'utilise des tableaux en C (de taille fixe), j'ai besoin de deux tailles :
− la taille du tableau à sa déclaration, c'est-à-dire la zone mémoire maximale utilisable : c'est un #define ;
− le nombre d'éléments utilisés dans le tableau, c'est-à-dire la zone mémoire réellement utilisée : c'est une variable.
Exemple : un tableau de notes.
/* Déclarations */
#define MAXNBNOTES 100 // nombre maxi de notes possibles
float tabnotes[MAXNBNOTES]; // le tableau
int nbnotes = 0; // nombre de notes saisies
// (sera modifié plus loin)
/* Appel à la fonction moyenne */
float moyenne = fmoyenne(tabnotes, nbnotes);
/* Fonction moyenne */
float fmoyenne(float ftableau[], int nbelem) // j'ai mis un 'f' pour me souvenir
{ // que c'est un tableau de float
for (int i = 0 ; i < nbelem ; i++)
{ /* traitement des éléments du tableau */ }
}
L'opérateur 'sizeof' fournirait la taille complète du tableau, ce n'est pas forcément celle qui nous intéresse.
Merci pour l'exemple, toujours intéressant de voir du code.
Ce que je note, c'est qu'il faudrait par exemple, vérifier que nbnotes est bien inférieur à la taille du tableau avant de le passer en paramètre, histoire de ne pas avoir de problèmes.
[....] Ce que je note, c'est qu'il faudrait par exemple, vérifier que nbnotes est bien inférieur à la taille du tableau avant de le passer en paramètre [....]
Pas à mon avis. C'est au moment du remplissage du tableau qu'il faut faire cette vérification. Dans l'exemple de @robun, on peut facilement imaginer que le tableau de notes est rempli via stdin, c'est donc à ce moment-là que la vérification doit être faite.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
De mon point de vue, je dirais qu'un tableau peut être modifié ou consulté (à chaque fois par une fonction dédiée).
− Lorsqu'il est modifié, la taille peut varier, il faut la contrôler. C'est ce qu'on fera dans la fonction de saisie des éléments, ou la fonction d'ajout/suppression d'éléments, ou de copie du tableau dans un autre, ou de concaténation de deux tableaux, etc.
− Lorsqu'il est consulté, on ne le me modifie pas, sa taille reste inchangée. Du fait de ce qui précède, le tableau est donc à la bonne taille, pas besoin de la contrôler. C'est le cas pour la fonction qui calcule la moyenne. (Du coup il faut peut-être ajouter un 'const' dans la définition ?)
- Edité par robun 19 avril 2024 à 21:17:00
Fonction fgets renvoie tout le contenu
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
En recherche d'emploi.
Le Tout est souvent plus grand que la somme de ses parties.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent