Problème d'affichage en programmation en C

Fermé
Hamster18 - Modifié le 2 janv. 2019 à 09:29
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 - 4 janv. 2019 à 16:45
Bonjour,
J'ai réaliser un programme qui à pour but d'afficher un client, une commande, et une liste de commande en attente. J'ai réaliser une fonction affichage pour les commandes et les clients cependant cet affichage à des bug (numéro apparaissant par " magie" , des tabulation au mauvais endroits) ... Pouvez-vous m'aider ??
De plus losque j'essaye d'ajouter à ma fonction un affichage pour la liste de commande en attente un message d'erreur d'invalid operand sort, cependant je ne voit pas comment la rectifier. Je vous prit de regarder mon code laissé si dessous qui accompagne ce post.
Merci d'avance Cordialement.

tp.h


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

typedef struct
{
char idArticle[6];
char denomination[30];
float prixU;
int quantEnStock;
}Article;



typedef struct
{
char idClient[6];
char civilite[4];
char nom[25];
char prenom[25];
int codePostal;
char ville[30];
}Client;

typedef struct
{
char idCommande[5];
char idArticle[5];
char idClient[5];
int quantNonLiv;
}Commande;

typedef struct maillon
{
Commande com;
struct maillon * suiv;
} Maillon,* Liste;

Article lireArt(FILE *fe);
Client lireClient(FILE *fe);
int chargementArt(FILE *fe,Article *tArt[], int max);
Client *chargementCli(FILE *fe,int *tmax, int *nb);

void afficherArt(Article a);
void afficherTArt(Article *tArt[],int max);
void afficherCli(Client c);
void afficheTabCli(Client tabC[], int tmax);

Liste listeVide(void);
Liste ajouterEnTete(Liste l,Commande c);
Liste ajouter(Liste l,Commande c);
void afficheCommande(Commande c);
void afficher(Liste l);


tp.c

#include "tp.h"

Article lireArt(FILE *fe)
{
Article a;
fgets(a.idArticle,7,fe);
a.idArticle[strlen(a.idArticle)-1]='\0';
fgets(a.denomination,30,fe);
a.denomination[strlen(a.denomination)-1]='\0';
fscanf(fe,"%f%*c%d%*c",&a.prixU,&a.quantEnStock);
return a;
}


Client lireClient(FILE *fe)
{
Client c;
fgets(c.idClient,7,fe);
c.idClient[strlen(c.idClient)-1]='\0';
fscanf(fe,"%s%*c",c.civilite);
fgets(c.nom,25,fe);
c.nom[strlen(c.nom)-1]='\0';
fgets(c.prenom,25,fe);
c.prenom[strlen(c.prenom)-1]='\0';
fscanf(fe,"%d%*c",&c.codePostal);
fgets(c.ville,30,fe);
c.ville[strlen(c.ville)-1]='\0';
return c;
}

int chargementArt(FILE *fe,Article *tArt[], int max)
{
Article a;
int i=0;
a=lireArt(fe);
while(!feof(fe))
{
if(i==max)
{
printf("tableau plein\n");
return -2;
}
tArt[i]=(Article*) malloc (sizeof(Article));
if(tArt[i]==NULL)
{ printf("Problème de malloc \n");
return -1;
}


*tArt[i]=a;i=i+1;a=lireArt(fe);}return i;}Client *chargementCli(FILE *fe,int *tmax, int *nb){int i=0;Client *tabC,*aux;*tmax=5;Client c;tabC=(Client*)malloc(*tmax*sizeof(Client));if(tabC==NULL){printf("Pb malloc\n");return NULL;}c=lireClient(fe);while(!feof(fe)){if(i==*tmax){*tmax=*tmax+5;aux=(Client*)realloc(tabC,*tmax*sizeof(Client));if(aux==NULL){printf("Pb realloc\n");return NULL;}tabC=aux;}tabC[i]=c;i=i+1;c=lireClient(fe);}*nb=i;return tabC;}void afficherArt(Article a){printf("%s\t%s\t%.2f\t%d\n", a.idArticle,a.denomination,a.prixU,a.quantEnStock);}void afficherTArt(Article *tArt[],int max){int i;for(i=0;i<max;i++)afficherArt(*tArt[i]);}void afficherCli(Client c){printf("%s\t%s\t%s\t%s\t%d\t%s\n",c.idClient,c.civilite,c.nom,c.prenom,c.ville,c.ville);}void afficheTabCli(Client tabC[], int tmax){int i;for(i=0;i<tmax;i++)afficherCli(tabC[i]);}Liste listeVide(void){return NULL;}Liste ajouterEnTete(Liste l,Commande c){Maillon *m;m=(Maillon*)malloc(sizeof(Maillon));if(m==NULL){printf("problème malloc\n");exit (1);}m->com=c;m->suiv=l;return m;}Liste ajouter(Liste l,Commande c){if(l==NULL)return ajouterEnTete(l,c);if(c==l->com)return l;l->suiv=ajouter(l->suiv,c);return l;}void afficheCommande(Commande c){printf("%s\t%s\t%s\t%d\n",c.idCommande,c.idArticle,c.idClient,c.quantNonLiv);}void afficher(Liste l){ Commande c;if(listeVide){ printf("opération impossible !\n");return;}afficheCommande(c);afficher(l);}


testtp.c

        #include "tp.h"

        void test(void)
        {
        FILE *fe;
        Article *tArt[200], a;
        Client *tabC;
        Commande c;
        int nbArt, tmax, nb;
        char nomfich[20];
        Liste l;
        printf("donnez le nom du fichier : ");
        scanf("%s",nomfich);
        fe=fopen(nomfich,"r");
        if(fe==NULL)
        {
        printf("Probleme d'ouverture du fichier en lecture\n");
        return;
        }
        if(strcmp(nomfich,"articles.txt")==0)
        { nbArt=chargementArt(fe,tArt, 200);
        afficherTArt(tArt,nbArt);
        }
        if(strcmp(nomfich,"clients.txt")==0)
        { tabC=chargementCli(fe,&tmax,&nb);
        afficheTabCli(tabC, nb);
        }
        if(strcmp(nomfich,"lignesCommandesEncours.txt")==0)
        { l=ajouter(l,c);
        afficher(l);
        }
        fclose(fe);
        }


        int main(){
        test();
        return 0;
        } 

EDIT : Ajout des balises de code (la coloration syntaxique).
Explications disponibles ici : ICI

Merci d'y penser dans tes prochains messages.
A voir également:

2 réponses

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 2 janv. 2019 à 13:21
Salut Hamster18,

Il y a certainement un problème de copier-coller dans l'affichage de ton code pour tp.c où toute la fin du fichier apparaît sur une seule ligne sur ce qui est posté sur le forum.

Sinon, chez moi, ton code ne compile pas en raison de l'erreur produite par
if(c==l->com)
dans la fonction
Liste ajouter(Liste l,Commande c)
. En effet, si le C permet d'affecter le contenu d'une struct à une autre de même type sans avoir à affecter chaque membre individuellement, tu n'as pas la même possibilité pour les comparaisons.

Donc, tu ne peux pas comparer 2 struct comme cela en C. Tu dois comparer individuellement les membres des deux structs.

Pour le reste je n'ai pas analysé ton code, ni pu l'exécuter, et on ne peut, de toutes façons, pas reproduire les problèmes d'affichage que tu indiques sans disposer des 3 fichiers de données utilisés par le programme.

S'il s'agit seulement d'un problème d'affichage, plutôt que de poster la totalité de ton code avec les fichiers de données utilisés, pourquoi ne crées-tu pas un court programme de quelques lignes avec des données de test limitées intégrées en dur et illustrant le problème constaté ?

Pour poster ton code sous forme lisible sur le forum de CCM, suit les indications de ce lien.

Dal
0
Hamster18 Messages postés 178 Date d'inscription mercredi 2 janvier 2019 Statut Membre Dernière intervention 22 janvier 2024
Modifié le 2 janv. 2019 à 17:43
Merci pour ces conseilles Dal,
J'ai simplifier les différentes fonctions cependant le problème persiste en ce qui concerne l'affichage. Je me suis concentrer à "régler" le problème pour le chargement du fichier articles.txt car je pense que c'est le même problème pour le chargement du second fichier. Pourriez-vous m'aider a comprendre mon erreur s'il vous plaît ?

Merci d'avance.
Cordialement hamster18

fichier articles.txt

USB01 clé USB 32GO 11.9 24
USB22 clé USB 8GO 4.99 0
SAM02 GALAXY S7 299.9 6
SAM49 GALAXY A5 208.9 3
SAM45 téléviseur écran plat 890.99 45
AVE15 Figurine pop de Thor 15.99 0
AVE55 Figurine pop de Faucon 15.99 4
MAN10 LOT figurine pop perso anime 15.9 0
LED56 Lampe 3D football 11.9 1
COQ45 Coque GALAXY A5 12.25 0
VET55 Echarpe 5.99 1


Voici le code du .h

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

typedef struct
{
char idArticle[7];
char denomination[40];
float prixU;
int quantEnStock;
}Article;

typedef struct
{
char idClient[7];
char civilite[4];
char nom[30];
char prenom[30];
int codePostal;
char ville[30];
}Client;



Article lireArt(FILE *fe);
void afficherArt(Article a);
int chargementArt(FILE *fe, Article *tArt[], int max);
void afficherTArt(Article *tArt[],int max);



Voici le code du .c

(à la ligne 39 c'est " *tArt[i]=a; " j'ai du l'enlever sinon cela engendrer des problème d'affichage ...)



#include "tp.h"


Article lireArt(FILE *fe)
{
Article a;
fgets(a.idArticle,7,fe);
a.idArticle[strlen(a.idArticle)-1]='\0';
fgets(a.denomination,40,fe);
a.denomination[strlen(a.denomination)-1]='\0';
fscanf(fe,"%f%d%*c",&a.prixU,&a.quantEnStock);
return a;
}


void afficherArt(Article a)
{
printf("%s\t%s\t%.2f\t%d\t\n", a.idArticle, a.denomination, a.prixU, a.quantEnStock);
}


int chargementArt(FILE *fe, Article *tArt[], int max)

{
Article a;
int i=0;
a=lireArt(fe);
while(!feof(fe))
{
if(i==max)
{ printf("Le tableau d'article est plein ! \n");
fclose(fe);
return -2;
}
tArt[i]=(Article*) malloc (sizeof(Article));
if(tArt[i]==NULL)
{ printf("Un problème de MALLOC est survenue ! \n");
return -1;
}
tArt[i]=a;
i=i+1;
a=lireArt(fe);
}

return i;
}


void afficherTArt(Article *tArt[],int max)
{
int i;
system("clear");
printf("------------------------------------------Tableau des articles : -------------------------------\n");
printf("Identifiant\tDésignation\tPrix\tQuantité en stock\n");
for(i=0;i<max;i++)
afficherArt(*tArt[i]);
}









voici le code du test.c




#include "tp.h"

void test(void)
{
FILE *fe;
int nbArticles;
Article *tArticle[200];
char nomFichier;

fe=fopen("articles.txt","r");
if(fe==NULL)
{ printf("Un problème est survenue lors de l'ouverture du fichier %s\n",nomFichier);
return;
}
nbArticles=chargementArt(fe,tArticle,200);
if(nbArticles<0)
return;
afficherTArt(tArticle,nbArticles);
fclose(fe);
}


int main(void)
{
test();
return 0;
}

0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 2 janv. 2019 à 19:19
Lorsque tu postes du code C, utilise la balise <code c>, sinon ton code ne sera pas présenté avec coloration syntaxique, ni numérotation de lignes.

Sur la forme aussi, ton indentation n'est pas bonne (mais peut-être est-ce dû à l'absence d'indication du langage C dans la balise...).

Sur le fond de ton code :

1.

lireArt()
semble incorrect car, si l'identifiant de l'article a une taille fixe, ce n'est pas le cas de la dénomination selon ce que tu as posté. Or, avec
fgets(a.denomination,40,fe);
, tu lis toutes les données restantes sur la ligne compte tenu de la longueur des données présentes dans articles.txt, et il ne reste ensuite plus rien à lire sur cette ligne pour tes deux derniers champs numériques.

Les champs des données dans articles.txt sont-ils séparés par une tabulation ?

Si oui, tu pourrais :

- lire toute la ligne avec fgets
- utiliser
strtok()
pour séparer des chaînes composant les champs (et convertir les chaînes en nombres sur les deux derniers)

Si ce n'est pas une tabulation, mais un espace qui sépare les champs, alors tu ne peux faire, a priori, la différence entre un espace au sein de la dénomination et un espace séparateur. Ce n'est pas impossible de gérer le problème, mais c'est plus difficile (on peut analyser la chaîne en partant de la fin).

S'il te plaît, confirme la nature du caractère séparateur de champs.

2.

afficherArt()
est maladroit, ainsi que le
printf("Identifiant\tDésignation\tPrix\tQuantité en stock\n");
dans
afficherTArt()
, car la différence de longueur de tes champs variables pourra dépasser la largeur standard des tabulations sur ton terminal d'affichage, ce qui produira des décalages.

Tu pourrais :

- déterminer la largeur maximale de chaque colonne
- pour cela lire d'abord toutes les données et dénombrer le nombre de caractères maximum nécessaires pour les afficher par colonne
- utiliser cette information pour justifier ton texte à gauche et tes chiffres à droite avec les spécificateurs de taille de
printf()


http://www.cplusplus.com/reference/cstdio/printf/

par exemple :

#include <stdio.h>

int main(void) {
    char * s1 = "Une description";
    char * s2 = "Une autre description";
    int maxlen_s = 21;
    int n1 = 10;
    int n2 = 200;
    int maxlen_n = 3;
    printf("| %-*s | %*s |\n", maxlen_s, "Desc", maxlen_n, "Num");
    printf("| %-*s | %*d |\n", maxlen_s, s1, maxlen_n, n1);
    printf("| %-*s | %*d |\n", maxlen_s, s2, maxlen_n, n2);

    return 0;
}

donne :

$ gcc -Wall justify.c
$ ./a.out 
| Desc                  | Num |
| Une description       |  10 |
| Une autre description | 200 |
$

Dal
0
Hamster18 Messages postés 178 Date d'inscription mercredi 2 janvier 2019 Statut Membre Dernière intervention 22 janvier 2024
Modifié le 2 janv. 2019 à 20:09
Merci Dal pour vos explications, cependant le programme que je suis entrain de faire est un projet scolaire, et mon professeur refuse que nous utilisions des options que nous n'avons pas vue en cours tel que strtok () par exemple. De ce fait je ne peux pas utiliser votre solution pour résoudre mon problème. Avez vous une autre idée afin de le résoudre ?

Merci d'avance.
Cordialement.
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 3 janv. 2019 à 10:02
Tu n'as pas répondu à cette question :

Les champs des données dans articles.txt sont-ils séparés par une tabulation ?

Si le professeur refuse que vous utilisiez une fonction de la bibliothèque C standard accessible par string.h (que tu utilises par ailleurs), cela me parait étrange. Mais rien ne t'empêche d'en répliquer le fonctionnement dans ton programme.

http://www.cplusplus.com/reference/cstring/strtok/

strtok()
procède en faisant une modification de la chaîne scannée, saucissonnée en sous-chaînes aux caractères séparateurs.

Alternativement, tu peux récupérer la ligne entière, puis énumérer les caractères et les stocker à mesure que tu les énumères dans des variables chaînes représentant chaque champ, en passant au champ suivant lorsque tu rencontres le caractère séparateur. Pour les champs représentant des valeurs numériques, il faudra une conversion, si tu tiens à les stocker en tant que
int
et
float
dans ta liste.
0
Hamster18 Messages postés 178 Date d'inscription mercredi 2 janvier 2019 Statut Membre Dernière intervention 22 janvier 2024
3 janv. 2019 à 13:26
Bonjour Dal,
Oui les différents champs de articles.txt sont séparer par des tabulations. Pour l'alternative que vous me proposer je ne voit pas ce que je doit faire.

Cordialement.
0
Bonjour Dal, je suis l'une des camarades de Hamster18 pour le projet et j'ai tenté quelques modifications suite à vos commentaires. Je voulais savoir ce qu'il en était de cette version ? Merci d'avance, cordialement.


Liste ajouterEnTete(Liste l,Commande c)
{
	Maillon *m;
	m=(Maillon*)malloc(sizeof(Maillon));
	if(m==NULL)
		{
			printf("problème malloc\n");
			exit (1);
		}
	strcpy(m->com.idCommande,c.idCommande);
	strcpy(m->com.idArticle,c.idArticle);
	strcpy(m->com.idClient,c.idClient);
	m->com.quantNonLiv=c.quantNonLiv;
	m->suiv=l;
	return m;
}	

Liste ajouter(Liste l,Commande c)
{
	if(l==NULL)
		return ajouterEnTete(l,c);
	if(c.idCommande==l->com.idCommande && c.idArticle==l->com.idArticle && c.idClient==l->com.idClient && c.quantNonLiv==l->com.quantNonLiv)
		return l;
	l->suiv=ajouter(l->suiv,c);
	return l;
}
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 4 janv. 2019 à 16:46
Bonjour Pllwk,

La question que pose Hamster18 sur ce fil concerne un problème de récupération de champs de données à partir d'une ligne comprenant une tabulation en caractère séparateur et d'affichage correctement formaté sous forme de tableau sans "décalages".

Ton code ne concerne manifestement pas ces problèmes.

De plus, tu ne poses pas de réelle question. Si tu as une question distincte de celle concernant le présent fil, poste un nouveau message sur le forum avec un code minimal compilable et exécutable illustrant ton problème, en décrivant ton problème, c'est à dire ce que fait ton code, ce qu'il devrait faire selon toi, et pourquoi tu penses que c'est un problème et un membre du forum pourra peut-être répondre à ta question.
0