Listes chaînées

Fermé
axelvdk - 12 févr. 2013 à 18:49
mamiemando Messages postés 33334 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 novembre 2024 - 14 févr. 2013 à 02:04
Bonjour,

Je dois faire un travail dans lequel j'utilise des listes chaînées pour écrire dans des fichiers. Malheureusement, ça marche pas toujours...

L'objectif, c'est d'écrire l'id, le nom et le prénom d'une personne dans un fichier.

Je passe le code juste après une explication, il y a 2 problèmes.
Soit j'utilise scanf() pour récupérer les données entrées par l'utilisateur, ça ne convient pas si j'ai un espace dans ce que donne l'utilisateur (problème mineur), mais parfois (je ne sais pas pourquoi pas toujours), il écrit 2 fois une données dans le fichier (le prénom).

Soit j'utilise gets(), j'ai plus le problèmes des noms avec espaces mais là, il envoie en console : "encodez l'id". il prend seulement le prénom, il saute l'étape du gets() pour l'id.
"encodez le prénom".
Pareil pour le cas 2 si je combine les scanf() et les gets()...

Voici les fonctions du fichier h :
struct test{char id[2]; char pre[10];char nom[15];struct test *svt;} *crt,*tet;
FILE *f;

void init()
{
    puts("passe par init");
    tet=(struct test*)malloc(sizeof(struct test));
    tet->svt=NULL;
    crt=tet;
}
void ajout()
{
    puts("ajout");
    while(crt->svt!=NULL) {crt=crt->svt;}
    puts("encoder l'id");
    scanf("%s",&crt->id);
    puts("encoder le prenom");
    gets(crt->pre);
    puts("encoder le nom");
    gets(crt->nom);
    fprintf(f,crt->id);
    fprintf(f,crt->pre);
    fprintf(f,crt->nom);
    fprintf(f,"\n");
    crt->svt = (struct test*)malloc(sizeof(struct test));
    crt=crt->svt;
    crt->svt=NULL;
    puts("allocation mémoire faite");
    crt=tet;
}


Et là je vous envoie le main :
 
    f=fopen("test.txt","a+");
    init();
    if(f==NULL)
        {
            puts("fichier pas créé");
        }
        else
        {
            while (cpt!=0)
            {
                ajout();
                puts("voulez vous encore ajouter un éléments, 1 si oui, 0 sinon");
                scanf("%d",&cpt);
             }
        }
    libMem();
    fclose(f);


Y a plus ou moins tout, j'ai pas mis la libération de la mémoire mais elle fonctionne.
Un grand merci en tout cas si vous avez pris la peine de me lire, et n'hésitez pas à m'aiguiller si l'envie vous en dit.


Bien à vous,

Axel








A voir également:

1 réponse

mamiemando Messages postés 33334 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 4 novembre 2024 7 801
14 févr. 2013 à 02:04
En fait le problème c'est que je pense que gets va s'arrêter au premier espace rencontré. L'autre problème c'est que si ton prénom ou ton nom font plus de 10/15 caractères ils vont débordés de leur zone mémoire et écraser d'autres zones mémoire.

Par exemple suppose que dans ta structure le prénom soit stocké sur 10 octets, suivi du prénom sur 15 octets.
- Supposons que ce soit "Toto" (donc 'T' 'o' 't' 'o' '\0'.).
- La libc lit du texte jusqu'à rencontrer le caractère '\0'.
- Jusque là tout va bien, si j'écris le nom de famille, je vais bien écrire "Toto".

Maintenant supposons que je mémorise le prénom, et que, pas de chance, ce prénom soit long, par exemple "Jean-Philippe", le 10 octets correspond au 2e "i" de "Philippe" donc je vais écrire "ppe" par dessus "Toto". Ainsi, quand je vais écrire
- le nom, ça va écrire "ppeo" (vu que "Tot" s'est fait écraser)
- le prénom, ça va écrire "Jean-Philippeo"

Bref, tout ça pour dire que quand tu lis une chaîne de caractère, il faut prévoir un gros buffer (mettons 200 chars), regarder la longueur de la chaîne avec strnlen, et ainsi tu seras exactement comment allouer tes deux char * dans ton maillon de liste. Par exemple si ton prénom fait n lettres :

char *prenom = malloc((n + 1) * sizeof(char)); // n lettres + '\0'

Il ne restera plus qu'à les copier (avec strncpy) de ton buffer vers ton maillon de liste.
https://linux.die.net/man/3/strnlen
https://linux.die.net/man/3/strcpy

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
   
#define BUF_SIZE 200
   
struct test {
    char *prenom;
    char *nom;
}; 
   
struct test * test_init(const char * prenom, const char * nom) {
    size_t n;
    struct test * t = malloc(sizeof(struct test));
   
    n = strnlen(prenom, BUF_SIZE);
    t->prenom = malloc((n + 1) * sizeof(char));
    strcpy(t->prenom, prenom);
   
    n = strnlen(nom, BUF_SIZE);
    t->nom = malloc((n + 1) * sizeof(char));
    strcpy(t->nom, nom);

    return t;
}  
   
void test_print(const struct test * t) {
    printf("prenom = %s nom = %s\n", t->prenom, t->nom);
}  
   
int main() {
    char prenom[BUF_SIZE];
    char nom[BUF_SIZE];
   
    printf("prenom ?\n");
    scanf("%s", prenom);
    printf("nom ?\n");
    scanf("%s", nom);
   
    struct test * t = test_init(prenom, nom);
    test_print(t);
    return 0;
}


Ce qui donne :

prenom ?
Jean-Philippe
nom ?
Plop
prenom = Jean-Philippe nom = Plop 


Bonne chance
0