|
|
|
|
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.
Corrections sur le programme actuel
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 |
Ouaaa !! Merci pour ce message très détaillé et structuré !
|
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 |
Euh, encore merci :)
|
Pas de problème, donne les erreurs de compilation, ton code actuel, et on va essayer de voir.
|
Oui, vous avez raison :D
|
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 :
//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 |
Gnié !!!
|
Ok, bon déjà ça me fait plaisir que mes réponses t'aident ;-)
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 ^^ |
Differents programmes sont téléchargeables gratuitement sur ce site internet et sont tous sous licence GPL sur http://website.bluesourcesproject.info/
|
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
|
fflush, les fichiers et les flux
#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 |