Probleme de liste chainée en C

Fermé
Bastien - 20 oct. 2005 à 15:46
mamiemando
Messages postés
31301
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
10 août 2022
- 20 oct. 2005 à 23:55
Bonjour à tous!

Voila mon problème:
je cherche à récupérer, depuis un fichier, des données (entiers) que je veux placer dans une structure "voisinage"; le système fonctionne suivant une chaine de "voisinage", chaque "voisinage" comportant un pointeur de "voisinage" indiquant le "voisinage" suivant... (voir programme ci-après).

Voici la tête de mon fichier de données (appelé dans mon programme "Fvsng.txt" pour "famille de voisinage"):
1
1 0 0 1 1 0 0 0 0
1 1 1 1 1 1 1 1 1

Le premier entier sera affecté au champ "ordre" de la structure "voisinage". Puis, chaque ligne correspond au tableau d'entier v de la structure "voisinage".
Par exemple ici, j'aurai un ordre de 1 pour le 1° voisinage, la première ligne correspond au champ v du 1° voisinage, puis pointeur sur NULL; je rattache le tout à un 2° voisinage, ordre égal à 1, la deuxième ligne affectée au champ v du 2° voisinage, puis pointeur sur le 1° voisinage.

Voici mon programme:
#include <stdio.h>
#include <stdlib.h>

typedef struct voisinage {
int ordre;
int *v;
struct voisinage *suiv;
}voisinage;

voisinage vois;

int CreerFVoisinage(char *nom,voisinage *vsng)
{ int o,i;
voisinage *p;
FILE *f;
vsng=(voisinage *) malloc(sizeof(voisinage));
vsng=NULL;
/* Ouverture du fichier */
f = fopen (nom, "r");
if (f == NULL)
{
printf ("ERREUR fopen(%s)\n", nom);
return -1;
}
fscanf(f,"%d",&o);
while (!feof(f))
{
p=(voisinage *) malloc(sizeof(voisinage));
p->v=(int *) malloc(sizeof(int)*(2*o+1)*(2*o+1));
p->ordre=o;
for(i=0;i<(2*o+1)*(2*o+1);i++)
fscanf(f,"%d ",&(p->v[i]));
p->suiv=vsng;
vsng=p;
}
fclose(f);
return 0;
}

void afficheVoisinage(voisinage *vsng)
{
int i;
voisinage *p;
p=vsng;
while (p!=NULL)
{ printf("--------------------\n");
for(i=0;i<(2*p->ordre+1)*(2*p->ordre+1);i++)
printf("%d\n",p->v[i]);
p=p->suiv;
}
}

int main(int argc,char **argv)
{
CreerFVoisinage("Fvsng.txt",&vois);
afficheVoisinage(&vois);
return 0;
}

Ce qui est curieux, c'est que si je demande entre le fclose(f); et le return 0; de la fonction CreerFVoisinage la visualisation des données de ma chaine de "voisinage", tout semble avoir été affecté correctement, alors qu'à l'extérieur (dans le main avec la fonction afficheVoisinage) rien ne semble avoir été "mémorisé"...

Voila,
j'espère avoir été clair :-)
J'ajouterai que la compilation ne retourne aucune erreur ni aucun "warning" :-)
Je remercie d'avance tout ceux qui pourront m'aider sur ce petit problème de langage C, en tout cas tout ceux qui auront pris le temps de lire ce sujet jusqu'à la fin.
Cordialement,
Bastien.

2 réponses

mamiemando
Messages postés
31301
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
10 août 2022
7 394
20 oct. 2005 à 21:04
Quand tu poste du code, mets le entre des balises de mise en forme "code" histoire que ce soit lisible ;-)

Je te propose un code mais je ne peux pas le compiler et te dire s'il marche... Mais à mon avis on n'est pas loin du vrai ;-)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct voisinage {
   int ordre;
   int *v;
   struct voisinage *suiv;
}voisinage; 

voisinage *new_voisinage(){
   voisinage *vois=(voisinage *)calloc(1,sizeof(voisinage));
   return vois;
}

void del_voisinage(voisinage *vois){
   free(vois.v);
   free(vois);
}

void del_chaine(voisinage *debut){
    voisinage *vois=debut;
    voisinage *vois_suivant;
    while(vois){
         vois_suivant=vois->suivant;
         del_voisinage(vois);
         vois=vois_suivant;
    }
}

//-------------------------------------------------

int *lire_ligne(char *str){
    //1er passage : déterminer le nombre d'entiers :
    unsigned int nb_elts,i;
    int plop;
    int *tab;
    for(nb_elts=0;sscanf(buffer," %d ",&plop)==1;++nb_elts);
    printf("La ligne [%s] contient %d element(s)\n",buffer,nb_ets);

    //2e passage : remplir le tableau
    tab=(int *)malloc(nb_elts*sizeof(int));
    for(i=0;i<nb_elts;++i){
       sscanf(buffer," %d ",&tab[i]);
    }
    return tab;
}

int lire_fichier(fp){
     unsigned int ordre_lu;
     voisinage *vois_suivant;
     voisinage *vois_courant;
     char buffer[255];

     //1ere ligne
     fscanf("%d\n",&ordre_lu);
     vois_courant=new_voisinage(ordre_lu);
     
     //Lignes suivantes
     while(!feof(fp)){
        fscanf("%s\n",&buffer);
        printf("Lit %s\n",buffer);
        vois_courant->v=lire_ligne(buffer);
        vois_suivant=new_voisinage(vois_courant->ordre+1);
        vois_courant->suivant=vois_suivant;
        vois_courant=vois_suivant;
    }
    return 0;
}

int main(int argc, char **argv){
  FILE *fp;
  voisinage *vois;
  if (argc!=1){
     fprintf(stderr,"usage : %s filename\n",argv[0]);
     return 1;
  }
  if( (fp=fopen(argv[1])==NULL){
     fprintf(stderr,"Fichier %s invalide\n",argv[1]);
     return 1;
  }
  vois=lire_fichier(fp);
  del_chaine(vois);
  return 0;
}


Bonne chance
0
crabs
Messages postés
908
Date d'inscription
lundi 18 avril 2005
Statut
Membre
Dernière intervention
3 août 2008
506
20 oct. 2005 à 21:07
je m'ai fait griller....
0
mamiemando
Messages postés
31301
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
10 août 2022
7 394 > crabs
Messages postés
908
Date d'inscription
lundi 18 avril 2005
Statut
Membre
Dernière intervention
3 août 2008

20 oct. 2005 à 23:55
Désolé ;-)
0
crabs
Messages postés
908
Date d'inscription
lundi 18 avril 2005
Statut
Membre
Dernière intervention
3 août 2008
506
20 oct. 2005 à 21:04
Salut,
Vu ton code tu fais de graves erreurs sur la gestion des compteurs ;-)
Déja au niveau de la fonction ( je rajoute quelques commentaires)
int CreerFVoisinage(char *nom,voisinage *vsng)
{ int o,i;
voisinage *p;
FILE *f;
vsng=(voisinage *) malloc(sizeof(voisinage)); /* allocation d'une cellule voisinage */
vsng=NULL;  /* mise à null du pointeur */
/* la cellule précédement alloué est perdue, elle est alloué mais on sait plus
où elle est */

Si dans le code d'entrée de ta fonction, la liste voisinage doit être vide, pas
la peine de la passer en argument, ou alors comme argument de sortie.
Mais avant de continuer sur ce point regardons de plus près le codage
du passage d'arguement
/* en global */
voisinage vois; 
/* la fonction */
int CreerFVoisinage(char *nom,voisinage *vsng) 
    {
    }
/* la fonction main() */
int main(int argc,char **argv)
    {
    CreerFVoisinage("Fvsng.txt",&vois);
    afficheVoisinage(&vois);
    return 0;
    }

La déclaration globale réserve dans l'espace de données de ton programme
une cellule voisinage.
L'appel dans ton main avec &vois, passe à la fonction l'adresse de cette
cellule à la fonction (c'est valide vis à vis du compilateur).
Le programme entre dans la fonction CreerFVoisinage, il met dans la variable
vsng la copie de cette adresse (copie que tu modifie via un malloc qui sert
à rien, puis une remise à null).
La fonction revient dans le main() et là surprise l'adresse de 'vois' n'a pas
changé, donc ta fonction affiche...() ne connait pas la valeur correcte qu'a
pu élaborer Creer...().
Y a plusieurs solution pour résoudre ça, je te présente celle qui me semble
la plus simple.
Le prototype de la fonction Creer...() devient :
voisinage* CreerFVoisinage(char *nom) 
    {
    voisinage* vsng = null ;
    /* le reste de ton code, retourne null en cas d'erreur système à l'open */
    ....
    /* à la fin tu retourne l'ancre de ta liste */
    return vsng ;
    }

Et là le code de ton main devient, après suppression de la déclaration de
la variable globale vois
int main(int argc,char **argv)
    {
    voisinage* vois ;
    vois = CreerFVoisinage("Fvsng.txt");
    afficheVoisinage(vois);
    /* ne pas oubllier de faire une fonction qui libère la mémoire allouée */
    return 0;
   }

Ca devrait être plus correct au niveau de la gestion de tes pointeurs et des
fonctions. Je ne présume pas que le traitement soit OK.
Sinon si tu veux absolument passer l'ancre de ta liste chainée en argument,
il faut utiliser un pointeur sur un pointeur de voisinage (voisinage **pt dans
le prototype de la fonction, voisinage*vois dans la déclaration pour le main,
&vois lors de l'appel, et utiliser *vois dans la fonction).

A+, bon courage, crabs
0