Langage C pointeurs, creation de liste.

Résolu/Fermé
Un Gars - 30 mars 2006 à 09:35
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 8 avril 2006 à 00:34
Bonjour a tous.

Voila, je rencontre quelaues petits preoblemes en langage C.

Le but est de creer des fiches afin de creer une listes les contenant.

Il faut ensuite afficher ce que l on a entre dans chaque fiche, puis afficher enfin le nombre de fiches composant la liste. La est mon petit probleme.

Voici mon code source :

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct Fiche
{
char nom[256];
struct Fiche* suivante;
}fiche;


fiche* CreerFiche(char texte[])
{
fiche* ptrFiche=NULL;
ptrFiche=(fiche*)malloc(sizeof(fiche));
if (ptrFiche != NULL)
{
strcpy(ptrFiche->nom,texte);
ptrFiche -> suivante = NULL;
}
else printf("Attention:plus espace memoire disponible");
return ptrFiche;
}

main()
{
int arret;
char reponse[256];
Fiche* ptrnouveau;
Fiche* ptrdebut;

arret = 1;
ptrdebut = NULL;
ptrnouveau = NULL;
do
{ printf("entrez le nom de votre fiche,\ntapez[fin]pour terminer\n\n");
gets (reponse);
printf("\n");
if (strcmp(reponse,"fin"))
{
ptrnouveau = CreerFiche(reponse);
ptrnouveau -> suivante = ptrdebut;
ptrdebut = ptrnouveau;
}
else
arret=0;
}
while(arret);
}

Voila, en somme, je pense devoir creer une fonction (par exemple, Editer() ) permettant d'editer a l'ecran la liste des fiches creees. Mais il faudrait aussi que cette fonction me donne en valeur de retour le nombre de fiches creees (celle qui composent la liste).
Et il faudrait que cette meme fonction recoive en argument le pointeur correspondant au debut de la liste.

Voila, quelqu'un pourrait-il m'aider SVP ?

En vous remerciant.

PS : desole pour les accents mais j'utilise un clavier anglophone.
A voir également:

12 réponses

mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
30 mars 2006 à 10:48
Corrections sur le programme actuel

Petite amélioration :
fiche* CreerFiche(char texte[]){
  fiche* ptrFiche=(fiche*)malloc(sizeof(fiche));
  if (ptrFiche != NULL) 
  ...
}

Ensuite pour être standard :
int main(){
  ...
  return 0;
}

Corrections indispensables :
int main(){
    int arret;
    char reponse[256];
    fiche* ptrnouveau;
    fiche* ptrdebut;
...
}

(ou struct Fiche *, comme tu préfères...)

Affichage de la structure de liste
unsigned int affiche_liste(struct Fiche * f){
  unsigned int nb_fiche;
  for(nb_fiche=0;f;++nb_fiche){
    printf("fiche %d : %s\n",f->nom);
  }
  return nb_fiche;
}


Suggestions

Bon apparemment ton insertion ton insertion est bizarre aussi, il faudrait que tu la corrige. Au passage plutôt que d'insérer en début de liste, je te conseille de faire plutôt un truc du genre :
struct Fiche{
  char nom[256];
  //... et les autres infos de la fiche
  struct Fiche * suivant;
};

struct dossier{
  struct Fiche * debut;
  struct Fiche * fin;
  //unsigned int nb_element;
};

Les insertions en fin de liste sont alors en 0(1) ainsi que les insertions en fin de liste. Mieux, tu peux généraliser les struct dossier à des listes génériques, moyennant un cast par la suite :
struct liste{
  void * debut;
  void * fin;
  //unsigned int nb_element;
};

Tu peux éventuellement stocker dans cette structure le nombre d'éléments pour le connaître en 0(1) plutôt qu'en O(n), mais ça force à le maintenir à chaque insertion ou suppression de maillon de ta liste chaînée.

Enfin il faudrait que tu écrives une fonction qui libère la mémoire (ça consiste en gros dans la fonction d'affichage à changer le printf par un free :p)

Bonne chance
2
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
31 mars 2006 à 09:31
Mmmh j'ai l'impression que tu n'as pas compris le code que je t'ai passé l'autre fois :-( Zut, ça veut dire que je n'ai pas été pédagogique :-/ L'idée c'est une opération basique relative aux listes implique une fonction. Parmi elles :
- obtenir le permier élément
- obtenir le dernier élément
- creer une liste vide
- insérer un nouveau maillon

Ze problem

Donc là ça fait 4 fonctions. Or toi tu as tout mis dans la même et ça n'a plus de sens, d'où erreur du compilateur. Je m'explique : tu écris

//ici tu devrais commencer la fonction begin()

   //Obtenir le premier element
    maillon * debut(struct Liste * l); // tu déclares un prototype de fonction !!
    return l.debut;

//et ici la finir


au lieu de déclarer et implémenter la fonction debut() ! Normalement pour être cohérent avec ce que je t'ai donné tu aurais dû écrire :
maillon * debut(struct Liste l){
    return l.debut;
}

ou à la rigueur :
maillon * debut(struct Liste * l){
    return l->debut; //equivalent à (*l).debut
}

Du coup tu te retrouves avec des morceaux de codes dans CreerListe qui n'ont rien à voir !! Appuies-toi sur le code que je t'ai passé l'autre fois. Par la suite tu te retrouves même avec un main à l'intérieur de la fonction CreerListe !! (apparemment tu as oublié une accolade !)

Comprendre les messages du compilateur

Maintenant je pense que tu comprends pourquoi le compilateur est perdu. Examinons ce qu'il te dit :
plop.c:31: erreur: syntax error before ‘*’ token
plop.c: In function ‘CreerFiche’:
plop.c:35: erreur: ‘l’ undeclared (first use in this function)
plop.c:35: erreur: (Chaque identificateur non déclaré est rapporté une seule fois
plop.c:35: erreur: pour chaque fonction dans laquelle il apparaît.)
plop.c:44: attention : ‘struct liste’ declared inside parameter list
plop.c:44: attention : visible uniquement depuis cette définition ou déclaration, ce qui n'est probablement pas ce que vous désirez
plop.c: In function ‘add’:
plop.c:45: erreur: déréférencement d'un pointeur de type incomplet
plop.c:47: erreur: déréférencement d'un pointeur de type incomplet
plop.c:48: erreur: déréférencement d'un pointeur de type incomplet
plop.c: In function ‘CreerFiche’:
plop.c:53: erreur: déréférencement d'un pointeur de type incomplet
plop.c: In function ‘main’:
plop.c:78: attention : assignment from incompatible pointer type
plop.c: In function ‘CreerFiche’:
plop.c:90: erreur: syntax error at end of input

Bon en C on se prends toujours plein d'erreur en cascade, donc il faut traiter les erreurs dans l'ordre (partir de la première qu'écrit le compilateur). Ici :
plop.c:31: erreur: syntax error before ‘*’ token

Alors pourquoi cette erreur ?
typedef struct Fiche{
    char Nom[256];
    struct Fiche * Suivante;
}fiche;
...
Fiche *CreerFiche(char Texte[] )

Alors en C la casse (minuscule/majuscule) est importante !! En d'autres termes, soit tu parles d'une struct Fiche, soit d'une fiche, mais Fiche seule n'a pas de sens. J'ai eu le même problème que toi au début en C, car les prof mettent tout de suite la ligne de typedef avec la déclaration de struct. En réalité c'est :
//Déclaration de struct Fiche
struct Fiche{
    char Nom[256];
    struct Fiche * Suivante;
};

//Déclaration de fiche=struct Fiche
typedef struct Fiche fiche;

Petits conseils :
- évite les majuscules en C (sauf pour les #define), en général on écrit tout en minuscule avec des _, les majuscules c'est plutôt des notations java. Même si rien ne t'empêche de les utiliser ;-) C'est juste une convention.
- évite de coller les * comme tu le fais dans : "fiche*CreerFiche(char Texte[] )", ça ne coûte rien d'aérer :-)
- il ne faut pas se sentir obligé de faire un typedef. Un typedef sert just à alléger le code à la lecture.
fiche * CreerFiche(char Texte[] )


Ok donc là il suffit juste de mettre :
fiche *CreerFiche(char Texte[] )

ou :
struct Fiche *CreerFiche(char Texte[] )

Ok, maintenant l'erreur l31 est traité, on recompile, mais l'erreur l35 est toujours là.
plop.c:35: erreur: ‘l’ undeclared (first use in this function

Allons ligne 35.
...
fiche *CreerFiche(char Texte[] )
{
    //Obtenir le premier element
    maillon * debut(struct Liste * l);
    return l.debut;
...

Donc là ça rejoint ce que je t'ai dit en début de post. Tu déclares un prototype de fonction dans une fonction (ce qui est TRES mal), et tu as mis le code de cette fonction dans CreerFiche. Ca n'a donc pas de sens, il faut bien faire :
...
//1ere fonction
struct Maillon * debut(struct Liste l){
    return l.debut;
}
/*
//ou la rigueur
struct Maillon * debut(struct Liste * l){
    return l->debut;
}
*/

//2e fonction
struct Fiche *CreerFiche(char Texte[] )
{
...
}

Idem ensuite avec la fonction fin().
Bon ensuite la section de code que je t'ai donné
struct maillon *m_it;
struct maillon *m_fin=fin(l); // je me suis trompée ici l'autre fois.. habitude du C++ ;-)
for(m_it=debut(l) ; m_it!=m_fin ; m_it=m_it->Suivante) //idem
{
    //traiter le struct maillon courant (*m_it)
}

c'est un squelette de code à incorporer dans une fonction devant parcourir la liste. Par exemple pour afficher la liste tu dois en parcourir chaque maillon donc tu peux utiliser ce genre de boucles.

Exemple :
void show_fiches(struct Liste l){
  struct Maillon *m_it;
  struct Maillon *m_fin=fin(l);
  for(m_it=debut(l) ; m_it!=m_fin ; m_it=m_it->suite)
  {
    struct Fiche *f=(struct Fiche *) m_it->data; //f contient l'adresse de la fiche
    printf("%s\n",f->Nom);
  }
}

Même erreur sur les majuscules de fiche pour la fonction add.

Par ailleurs les fiches n'ont pas de raison de stocker un pointeur sur la fiche suivante, c'est le rôle du maillon. Normalement tu as juste le char[256] dans ta fiche, mais si par la suite tu as besoin de stocker l'âge tu pourras facilement rajouter un unsigned int... Tes structures sont donc :
typedef struct Fiche{
    char Nom[256];
   //unsigned int age;
}fiche;

typedef struct Maillon{
    void * data;
    struct Maillon * suite;
}maillon;

typedef struct Liste{
    maillon * debut;
    maillon * fin;
}liste;

Une fois toutes ces corrections apportées ont essayé de voir si on a rien oublié en mettant plein de warning :
(mando@H101-b) (~) $ gcc -W -Wall plop.c
plop.c: In function ‘CreerFiche’:
plop.c:41: attention : unused variable ‘ptrfiche’
plop.c:42: attention : control reaches end of non-void function
plop.c: Hors de toute fonction :
plop.c:39: attention : unused parameter ‘Texte’
plop.c: In function ‘main’:
plop.c:99: attention : control reaches end of non-void function
/tmp/cc0uzfiF.o: dans la fonction « main »:
plop.c:(.text+0x132): AVERTISSEMENT: the `gets' function is dangerous and should not be use

Allons voir ce qui s'y passe. Ah oui en effet il faut corriger CreerFiche (cf code final). Ensuite il faut supprimer la ligne faisant intervenir Suivant dans le main qui n'a plus de sens puisqu'on a retiré ce champ de Fiche, et rajouter à la fin du main un return 0 (qui spécifie au système que le programme s'est bien déroulé.)

On obtient donc le code :
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LGTXT 256



typedef struct Fiche{
    char Nom[256];
}fiche;

typedef struct Maillon{
    void * data;
    struct Maillon * suite;
}maillon;

typedef struct Liste{
    maillon * debut;
    maillon * fin;
}liste;

//Creer une nouvelle liste
struct Liste nliste(){
    struct Liste l;
    l.debut=NULL;
    l.fin=NULL;
    return l;
}
//Obtenir le premier element
struct Maillon * debut(struct Liste l){
    return l.debut;
}

//Obtenir le dernier element
struct Maillon * fin(struct Liste l){
    return l.fin;
}

fiche *CreerFiche(char Texte[] )
{
    fiche* ptrfiche=(fiche*)malloc(sizeof(fiche));
    strcpy(ptrfiche->Nom,Texte);
    return ptrfiche;
}
//Inserer un élément en fin de liste
void add(struct Liste * l,maillon * x){
    maillon *m=l->fin;
    if (m!=NULL) m->suite=x;
    else l->debut=x;
    l->fin=x;
}

void show_fiches(struct Liste l){
  struct Maillon *m_it;
  struct Maillon *m_fin=fin(l);
  for(m_it=debut(l) ; m_it!=m_fin ; m_it=m_it->suite)
  {
    struct Fiche *f=(struct Fiche *) m_it->data; //f contient l'adresse de la fiche
    printf("%s\n",f->Nom);
  }
}

int main()
{
    int arret;
    char reponse[256];
    fiche* ptrnouveau;
    fiche* ptrdebut;
    int nombre;

    arret = 1;
    ptrdebut = NULL;
    ptrnouveau = NULL;
    nombre = 0;

    do{
        printf("Entrer le nom de la fiche.\n\nEntrer ''Fin'' pour terminer le programme.
\n\n");
        gets (reponse);
        printf("\n\n\n");
        if (strcmp(reponse,"Fin"))
        {
/*            ptrnouveau = CreerFiche(reponse);
            ptrdebut = ptrnouveau;
            nombre++; */
//utilise ici les fonctions que l'on a défini, notamment la fonction add
        }
        else arret=0;
    }while(arret);

    if(nombre>1) printf("Vous avez cree %d fiches.",nombre);
    else printf("Vous avez cree %d fiche.",nombre);

    getchar();
    return 0;
}

Bonne chance
1
Gnié !!!

Je ne sais plus quoi dire là ... à part que j'ai encore un problème :D

Non mais franchement, je tiens à vous remercier de vos réponses de plus en plus précises et de plus en plus structurées, et donc du temps que vous passez à les écrire !

J'ai compris mes erreurs, et ai réussi à toutes les corriger pour faire en sorte que ça marche (enfin, vous m'avier très largement ouvert la voie, voire corrigé directement :) ). Ca m'a pris une heure et demie, mais je pense que tout s'est un peu éclairé dans ma tête :)

Après avoir corrigé mes erreurs, je me suis retrouvé avec exactement le même programme que vous avez écrit à la fin, sauf que j'avais mis le créer une nouvelle liste en dessous de la première et de la dernière liste :D

Ensuite, me reste encore (et oui, désolé :) ), un problème.

Avec tout ça, mon programme ne fait rien de plus que ce qu'il faisait avant :)

Mais je sais pourquoi (enfin je crois :D), car bien qu'on ait fait tout cela, peut-être que le nom des fiches est enregistré quelque part (ou même pas encore je pense), mais l'on ne fait pas en sorte de de les faire apparaître à l'écran.

En fait, je pense que c'est là où vous avez mis :

//utilise ici les fonctions que l'on a défini, notamment la fonction add


Ce que je pense avoir compris :

Je pense qu'à chaque fois qu'on créé une fiche, on n'enregistre pas son nom, et il faudrait le faire avec add. Cependant, je ne vois pas comment faire (désolé :) ). J'ai essayé de faire des choses du genre add Nom, etc ... un peu comme quand je me sert d'un compteur que j'incrémente à chaque fois, mais visiblement, ça ne fonctionne pas du tout de la même manière, ce qui fait que mes tentatives ne marchent pas .

Donc je ne vois pas comment faire ça (à moins que ce soit déjà fait un peu plus haut, alors je n'aurais pas tout compris ^:p ).

Une autre chose aussi, c'est que je pense, qu'après avoir fait en sorte que chaque nom soit enregistré, il faudrait les afficher à la fin du programme dans l'ordre, après l'indication sur le nombre de fiches créées. Je pense donc qu'il faudrait mettre un printf quelque chose, peut-être "%s", add ou quelque chose dans le genre ?



Voilà voilà, j'espère ne pas avoir raconté n'importe quoi dans la partie "Ce que je pense :", mais j'ai essayé de raisonner avec le peu de bases que j'ai acquises ;)

Encore merci de votre aide ;)
1
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
8 avril 2006 à 00:34
fflush, les fichiers et les flux

fflush() sert à rafraichir un flux. En général on le fait sur stdout (je ne vois pas trop à quoi ça sert sur stdin) pour garantir qu'un texte est bien écrit. En effet, ton programme peut passer par un printf et planter juste après sans pour autant que le texte se soit afficher (notamment s'il n'est pas terminé par un \n). C'est la que fflush intervient :

http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man3/fflush.3.html

fflsuh intervient donc sur les flux. Les flux sont en fait des FILE *, c'est à dire un pointeur sur une position d'un fichier. Il faut bien comprendre qu'en fait
- l'entrée standard (stdin) se comporte comme un fichier ouvert en lecture, permettant de lire ce que saisit un utilisateur au clavier
- la sortie standard (stdout) et d'erreur se comportent comme deux fichiers ouverts en écriture. En général les deux s'affichent sur une console, mais il est possible de rediriger ces deux flux vers des fichiers différents

Plus généralement, tout les "devices" au sens linux dont stdin, stdout, stderr font parties, se comportent comme des fichiers, mais sous linux il y a aussi le fichier /dev/dsp pour la carte son, /dev/cdrom pour le cdrom etc... La notion de fichier peut donc être beaucoup plus générale que ce que pourrait laisser penser windows ;-)

Ainsi dans un programme sous linux il est tout à fait possible de faire :
#include <stdio.h>

int main(){
  FILE *fp=fopen("/dev/dsp","w");
  fprintf(fp,"nvzupnvzpnvvzvada");
  fclose(fp);
  return(0);
}

Ce sera pas super musical mais bon :p En réalité, un player multimédia ne fait donc qu'écrire un son sur /dev/dsp !

Et free ?

free libère un espace alloué à une adresse donnée (le pointeur passé en paramètre). Si tu programmes proprement à tout malloc/calloc doit correspondre un free. Ces notions d'allocations et libérations mémoires sont en fait gérées dans les langages objets (java, c++) par le biais d'un constructeur et d'un destructeur (cf cours ultérieurs :p).

Concrètement, free s'occupe donc de libérer ta RAM, ce qui n'a donc rien à voir avec stdin ;)

Pour les exercices supplémentaires

Etant donné que la question initiale est résolue, lorsque tu feras les exercices de bonus, si tu rencontres des difficultés, je t'invite ouvrir un nouveau post.

Bonne chance
1

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Ouaaa !! Merci pour ce message très détaillé et structuré !

Donc en fait, entre temps, j'ai un peu avancé de mon côté, et j'ai juste réussi, à ma manière, à afficher le nombre de fiches que j'ai créées :)



#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LGTXT 256



typedef struct Fiche
{
char Nom[256];
struct Fiche * Suivante;
}fiche;

typedef struct Dossier{
struct Fiche * debut;
struct Fiche * fin;
}dossier;

typedef struct Liste{
void * debut;
void * fin;
}liste;



Fiche*CreerFiche(char Texte[] )
{
fiche* ptrfiche=(fiche*)malloc(sizeof(fiche));
if(ptrfiche!=NULL)
{
strcpy(ptrfiche->Nom,Texte);
ptrfiche->Suivante=NULL;
}
else
{
printf("Memoire pleine");
}
return ptrfiche ;
}



int main()
{
int arret;
char reponse[256];
fiche* ptrnouveau;
fiche* ptrdebut;
int nombre;

arret = 1;
ptrdebut = NULL;
ptrnouveau = NULL;
nombre = 0;

do{
printf("Entrer le nom de la fiche.\n\nEntrer ''Fin'' pour terminer le programme.\n\n");
gets (reponse);
printf("\n\n\n");
if (strcmp(reponse,"Fin"))
{
ptrnouveau = CreerFiche(reponse);
ptrnouveau->Suivante = ptrdebut;
ptrdebut = ptrnouveau;
nombre++;
}
else arret=0;
}while(arret);

if(nombre>1) printf("Vous avez cree %d fiches.",nombre);
else printf("Vous avez cree %d fiche.",nombre);

getchar();
}



Voilà, par contre, je n'ai pas réussi à faire en sorte que le programme m'affiche ce que j'ai entré.

En fait, je vais donner un exemple de ce que je voudrais :)

J'entre le nom de la première fiche : aaa

J'entre le nom de la deuxième fiche : bbb

...

J'entre le nom de la n-ième fiche : xxx

J'entre "Fin"

Le programme m'affiche alors :

Vous avez entré n fiches.

Nom de la fiche 1 : aaa

Nom de la fiche 2 : bbb

...

Nom de la fiche n : xxx



Voilà voilà :)

Par ailleurs, j'ai étudié votre réponse, à savoir :



unsigned int affiche_liste(struct Fiche * f){
unsigned int nb_fiche;
for(nb_fiche=0;f;++nb_fiche){
printf("fiche %d : %s\n",f->nom);
}
return nb_fiche;
}



Mais je n'ai malheureusement absolument rien compris :)

Enfin voilà, finalement, il ne me reste plus qu'à afficher le nom de toutes les fiches que j'ai entrées.

Merci de votre aide ;)
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
30 mars 2006 à 14:09
Bon déjà vu que tu insères tes maillons en début de liste, lorsque tu vas parcourir ta liste tu vas afficher les fiches dans l'ordre inverse des fiches. Il faut donc soit insérer les maillons en fin de liste, soit faire un chaînage dans l'autre sens. Voici ce que je ferais :
struct maillon{
  // void * = adresse générique
  // mais tu mets en fait ce que tu veux. Par exemple pour une 
  // liste d'entier tu mets int data
  void * data; 
  struct maillon * next;
  //struct maillon * prev; //chaînage dans l'autre sens
};

struct list{
  struct maillon * begin;
  struct maillon * end;
};

//Creer une liste
struct list new_list(){
  struct list l;
  l.begin=NULL;
  l.end=NULL;
  return l;
}

//Obtenir le premier element
struct maillon * begin(struct list * l){
  return l.begin;
}

//Obtenir le dernier element
struct maillon * end(struct list * l){
  return l.end;
}

//Inserer un élément en fin de liste
void add(struct list * l,struct maillon * x){
  struct maillon *m=l->end();
  if (m!=NULL) m->next=x;
  else l->begin=x;
  l->end=x;
}

Je n'ai pas pris le temps de débugger ce code c'est juste pour te donner l'idée. Ca ressemble assez à ce qui se fait en C++ en fait (le struct maillon * m que j'utilise serait remplacé par iterator). L'objectif est ici :
- de faire pointer l.begin sur le premier élément
- de faire pointer l.end sur le dernier élément
- de maintenir le chaînage

Par la suite pour parcourir la liste il suffit de faire :
  struct maillon *m_it;
  struct maillon *m_end=l->end();
  for(m_it=l->begin() ; m_it!=m_end ; m_it=m_it->suivant){
    //traiter le struct maillon courant (*m_it)
  }

Exemple :
void show_list(struct list * l){
  struct maillon *m_it;
  struct maillon *m_end=l->end();
  unsigned int i=0;
  for(m_it=l->begin() ; m_it!=m_end ; m_it=m_it->suivant){
    printf("l[%d] = %d\n",i,m_it->data); //si data est de type int
    ++i;
  }
}


Bonne chance
0
Euh, encore merci :)

Par contre, ça commence à m'agacer, car ça fait une heure que je travaille sur ce que vous m'avez écrit, et je n'arrive pas à faire fonctionner mon programme (bon, j'avais changer les "debut" en "begin", etc ... pour que ça concorde avec ce que vous avez écrit).

Mais à chaque fois, il me trouve des problèmes, et ne veut pas complier ... peut-être ne les mets-je pas au bon endroit dans mon programme, mais en tous cas, j'ai tout essayé, rien à faire :(

Au fait, je tiens à dire que je suis débutant (très débutant), c'est sûrement la raison pour laquelle je n'arrive pas à faire fonctionner le programme :p

Enfin voilà, je n'y arrive toujours pas :(

Merci encore de votre aide.
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
30 mars 2006 à 15:33
Pas de problème, donne les erreurs de compilation, ton code actuel, et on va essayer de voir.

A travers mes derniers posts, je cherche surtout à te faire comprendre comment t'y prendre en C et comment ça marche afin que tu sois autonome.

C'est pourquoi je te corrige des fautes, et te donne les grandes lignes mais que je ne te donne pas un code "tout prêt"... d'une part car ce n'est pas formateur, et d'autre part... pace que je n'ai pas le temps ;-)

Bonne chance
0
Oui, vous avez raison :D

Donc voilà ce que j'ai fait (enfin j'avais fait autre choses en essayant de déclarer des fonctions etc ... mais il s'est effacé) :



#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LGTXT 256



typedef struct Fiche{
char Nom[256];
struct Fiche * Suivante;
}fiche;

typedef struct Maillon{
void * data;
struct Maillon * suite;
}maillon;

typedef struct Liste{
maillon * debut;
maillon * fin;
}liste;

//Creer une nouvelle liste
struct Liste nliste(){
struct Liste l;
l.debut=NULL;
l.fin=NULL;
return l;
}

Fiche*CreerFiche(char Texte[] )
{
//Obtenir le premier element
maillon * debut(struct Liste * l);
return l.debut;

//Obtenir le dernier element
maillon * fin(struct Liste * l);
return l.fin;

fiche* ptrfiche=(fiche*)malloc(sizeof(fiche));

//Inserer un élément en fin de liste
void add(struct liste * l,maillon * x){
maillon *m=l->fin();
if (m!=NULL) m->suite=x;
else l->debut=x;
l->fin=x;
}

struct maillon *m_it;
struct maillon *m_fin=l->fin();
for(m_it=l->debut() ; m_it!=m_fin ; m_it=m_it->Suivante)
{
//traiter le struct maillon courant (*m_it)
}


int main()
{
int arret;
char reponse[256];
fiche* ptrnouveau;
fiche* ptrdebut;
int nombre;

arret = 1;
ptrdebut = NULL;
ptrnouveau = NULL;
nombre = 0;

do{
printf("Entrer le nom de la fiche.\n\nEntrer ''Fin'' pour terminer le programme.\n\n");
gets (reponse);
printf("\n\n\n");
if (strcmp(reponse,"Fin"))
{
ptrnouveau = CreerFiche(reponse);
ptrnouveau->Suivante = ptrdebut;
ptrdebut = ptrnouveau;
nombre++;
}
else arret=0;
}while(arret);

if(nombre>1) printf("Vous avez cree %d fiches.",nombre);
else printf("Vous avez cree %d fiche.",nombre);

getchar();
}



return l.debut;


"l" undeclared identifier
left of '.debut' must have class/struct/union type




return l.fin;


left of '.fin' must have class/struct/union type
"l" identifier not found, even with argument-dependant lookup




void add(struct liste * l,maillon * x){
'add' : local function definitions are illegal




struct maillon *m_fin=l->fin();

left of'->fin' must point to class/struct/union type is "unknown-type"
"l" identifier not found, even with argument-dependant lookup




for(m_it=l->debut() ; m_it!=m_fin ; m_it=m_it->Suivante)

left of'->debut' must point to class/struct/union type is "unknown-type"
"l" identifier not found, even with argument-dependant lookup
use of undefined type '*(char[])CreerFiche::maillon'
left of'->Suivante' must point to class/struct/union




int main()
{

'main' : local function definitions are illegal




#include<stdio.h>

end of file found before the left brace '{' at bla bla bla




Voilà, j'ai sûrement dû mettre vos écrits un peu n'importe où, mais j'ai cherché où les mettre et pense que c'est ainsi qu'il faut faire ^^

Voilà, merci de votre aide ;)
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
2 avril 2006 à 21:17
Ok, bon déjà ça me fait plaisir que mes réponses t'aident ;-)

Quelques rappels théoriques

En fait les pointeurs c'est vraiment très simple comme notion. Un pointeur de type plop * est une adresse sur un objet plop. Les différents pointeurs ne se distinguent que sur la notion de type (ie à la compilation) mais c'est vraiment juste une adresse complètement indépendant de l'objet qu'elle pointe. L'adresse la plus générique étant un void *. Ainsi tu pourrais (mais ce ne serait pas très lisible) utiliser uniquement des pointeurs de type void *.

Cependant, si un pointeur n'est pas initialisé, l'adresse qu'il contient ne veut rien dire, ce qui conduit au fameux "segmentation fault". Les fonctions calloc et malloc servent donc à reserver un espace mémoire de la bonne taille, et retourne l'adresse de cet espace. Cet espace étant libéré à l'aide d'un free ;-)

Erratum

Je viens de m'apercevoir que j'avais fait une petite erreur sur les boucles avec les parcours de liste, c'est que la boucle for s'arrête avant de traiter le dernier élément. Ce qui donne après correction :
void show_fiches(struct Liste l){
  struct Maillon *m_it;
  struct Maillon *m_fin=fin(l);
  for(m_it=debut(l) ; ; m_it=m_it->suite)
  {
    struct Fiche *f=(struct Fiche *) m_it->data; 
    printf("%s\n",f->Nom);
    if (m_it==m_fin) break;
  }
}

unsigned int size_list(struct Liste l){
  struct Maillon *m_it;
  struct Maillon *m_fin=fin(l);
  unsigned int taille=0;
  for(m_it=debut(l) ; ; m_it=m_it->suite)
  {
    ++taille;
    if (m_it==m_fin) break;
  }
  return taille;
}

Corrigé du main

Bon ensuite il suffit de corriger le main pour faire appel à tout le bazar :
int main()
{
    int arret;
    char reponse[256];
    int nombre;

    arret = 1;
    nombre = 0;
    struct Liste l=nliste();

    do{
        printf("Entrer le nom de la fiche.\n\nEntrer ''Fin'' pour terminer le programme.\n\n");
        gets (reponse);
        printf("\n\n\n");
        if (strcmp(reponse,"Fin"))
        {
            struct Fiche * pf=CreerFiche(reponse);
            struct Maillon *m=(struct Maillon *)malloc(sizeof(struct Maillon));
            m->data=pf;
            add(&l,m);
            ++nombre;
        }
        else arret=0;
    }while(arret);

    if(nombre>1){
        printf("Vous avez cree %d fiches.\n",nombre);
        printf("Mon dossier contient les %d fiches suivantes :\n",size_list(l));
        show_fiches(l);
    }
    else printf("Vous avez cree %d fiche.\n",nombre);

    getchar();
    return 0;
}

Exercices

Voilà, et tout marche ;-) Quelques petits exercices pour t'entraîner :
- afficher la nième fiche. Vérifier au préalable que cette fiche existe.
- creer une fonction qui libère la mémoire occupée par la liste et chacun de ses maillons, à l'aide de la fonction free
- supprimer la nième fiche.
- rechercher l'index d'une fiche à partir du nom qu'elle contient.
- en stockant l'ensemble des fiches dans un tableau (struct Fiche *) et en utilisant la fonction qsort, trier les fiches par ordre alphabétique
- rajouter un champ age dans une fiche. Corriger CreerFiche en conséquence ainsi que la saisie d'une fiche
- proposer la correction de la ième fiche (Nom+Age)

Après ça tu seras un pro du C ;-)

Signé une fille ^^
0
Drayell / Ank[58]f1x : Webmaster, Coder(C/C++, Asm), Designer
2 avril 2006 à 21:27
Differents programmes sont téléchargeables gratuitement sur ce site internet et sont tous sous licence GPL sur http://website.bluesourcesproject.info/

Site créé par quelques amateurs. Avoir !
0
Oui, effectivement, vos explications sont très explicites, et même un débutant comme moi les comprend (alors que les explications données par les professeurs ... ce n'est pas trop ça ^^ pour eux, c'est tellement évident ... qu'il nous disent "alors tu fais comme ci, comme ça, bla bla bla ... et ... bah voilà, c'est tellement évident" ... au final, je ressort du cours encore plus embrouillé qu'avant, alors je m'en vais faire des maths ou de la physique pour me changer les idées :D

Sinon, je travaillerais à nouveau cet exercice avec vos corrections dès que j'aurais le temps, car je suis en pleine semaine de partiel, et c'est snifant :(

Et j'essayerais aussi de faires vos petits exercices bonus que vous m'avez donnés à faire (*studieux* :D).

Ah oui, une question, l'on doit libérer la mémoire avec la fonction free, mais lorsque l'on utilise fflush(stdin);, ça vide le buffer : ma question : ces fonctions n'ont-elles pas justement la même fonction ? fflush ne libère t-elle pas la mémoire temporaire utilisée durant tout le programme ?

Voilà :)

Merci encore ;)
0