Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Premier programme fait maison...

116 réponses
Avatar
listes
Salut,

Voilà... je suis super débutant... Je poste ici mon premier programme
fait maison....

Je voudrait avoir votre avis..

J'utilise Xcode sur un macintosh sous 10.4.4, mais cela n'a pas beaucoup
d'importance...

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

int main (int argc, const char * argv[]) {

//on défini les variables
char Nom[200];
float quantite; // la variable quantité
float prix; // la variable prix
float total; // la variable total
float tauxtva; // le taux de tva
float soustotal; // le sous tatal sans la tva
float tva; // le montant de la tva

printf("Entrez votre nom : ");
scanf("%s", Nom);
printf("\n");
printf("Taux de tva ? : "); // on demande le taux de tva
scanf("%f",&tauxtva);
printf("\n");
printf("Quantite de l'article a facturer ? : "); // on demande
la quantité
scanf("%f",&quantite);
printf("\n");
printf("Le prix de l'article ? : "); // on demande le prix
scanf("%f",&prix);
printf("\n");

// le calcul

soustotal = quantite * prix;
tva = (soustotal * tauxtva)/100;
total = soustotal + tva;

//on affiche le résultat

printf ("Montant a payer hors tva %.2f\n\n",soustotal);
printf ("TVA a payer : %.2f\n\n", tva);
printf ("%s, vous avez un total a payer : %.2f\n", Nom, total);

return 0;
}

Est-ce assez clair dans la présentation (pour ce cas-ci bien sur) ?

A+

10 réponses

1 2 3 4 5
Avatar
Laurent Deniau
David Remacle (Clampin) wrote:
Salut,

Voilà... je suis super débutant... Je poste ici mon premier programme
fait maison....

Je voudrait avoir votre avis..

J'utilise Xcode sur un macintosh sous 10.4.4, mais cela n'a pas beaucoup
d'importance...

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


#include <assert.h> // voir plus bas

int main (int argc, const char * argv[]) {


Si tu n'utilises pas argc ni argv

int main(void)
{

//on défini les variables
char Nom[200];


pourquoi Nom est la seule variable a commencer par une majuscule? Il
faut adopter une convention et s'y tenir, c'est plus lisible.

float quantite; // la variable quantité


a moins que tu traites des fractions d'objets

int quantite;

float prix; // la variable prix
float total; // la variable total
float tauxtva; // le taux de tva
float soustotal; // le sous tatal sans la tva
float tva; // le montant de la tva


Mieux vaut utiliser des 'double' qui est le type flottant le plus commun
en C (malgre son nom), ca evitera pas mal de probleme pour un debutant
(surtout ne pas suivre ce que les "Numerical Recipies in C" font sur ce
point). Le seul interet des float, c'est d'economiser de la memoire (et
probablement pas s'ils sont sur la pile) donc a moins de manipuler des
vecteurs de millions de float, utiliser des doubles simplifie la vie et
ton programme sera probablement plus rapide.

par defaut stdout vide son buffer sur un 'n'

setvbuf(stdout, 0, _IONBF);

evite de mettre des fflush(stdout) apres chaque printf. Vu le programme,
les performances ne chuteront pas ;-)

printf("Entrez votre nom : ");
scanf("%s", Nom);


assert(scanf("%199s", Nom) == 1);

evite un depassement de buffer et il faut tester le retour de ses
fonctions (printf aussi en principe).

printf("n");


putchar('n');

pas la peine de sortir l'artillerie pour un caractere.

printf("Taux de tva ? : "); // on demande le taux de tva


printf("Taux de tva en %% ? : ");

Quand on pose une question, mieux vaut mettre les unites si celles-ci ne
sont pas evidentes (%% donnera % sur la sortie et $ pour l'etat ;-) ).

scanf("%f",&tauxtva);


si tu optes pour les doubles

assert(scanf("%lf", &tauxtva) == 1);

si la tva est en %, convertir et faire une validation

tauxtva /= 100.0;
assert(0.0 < tauxtva && tauxtva < 1.0);

de maniere generale, ne jamais faire confiance aux entrees.

printf("n");
printf("Quantite de l'article a facturer ? : "); // on demande
la quantité
scanf("%f",&quantite);


pourquoi mettre un flottant?

assert(scanf("%d", &quantite) == 1);
assert(quantite > 0);

note que "%u" accepte une valeur de type -1 qui sera ensuite interpretee
comme non signee (et tres grande), ce qui est source de mauvaise
verification. A moins de manipuler des shifts (surtout avec >>) et des
bits, mieux vaut rester sur des entiers signes et faire les tests qui
vont avec.

printf("n");
printf("Le prix de l'article ? : "); // on demande le prix
scanf("%f",&prix);


assert(scanf("%lf",&prix) == 1);
assert(prix > 0.0);

printf("n");

// le calcul

soustotal = quantite * prix;
tva = (soustotal * tauxtva)/100;


Si le tauxtva a ete donne en % et normalise

tva = soustotal * tauxtva;

total = soustotal + tva;


pour les noms des variables, j'aurais plutot utilise des identifiants
plus clairs que total, soustotal, tva, tauxtva

prix_ht = quantite * prix_unitaire;
prix_ttc = prix_ht * (1.0 + tva);

//on affiche le résultat

printf ("Montant a payer hors tva %.2fnn",soustotal);
printf ("TVA a payer : %.2fnn", tva);
printf ("%s, vous avez un total a payer : %.2fn", Nom, total);

return 0;


L'indentation a son importance pour la lisibilite et donc pour la
comprehension = moins de bugs.

}


Par simplicite, j'ai utilise assert pour les verifications, mais un test
avec if() suivit d'un message d'erreur clair et le cas echeant une
sortie propre du programme sont preferable.

Est-ce assez clair dans la présentation (pour ce cas-ci bien sur) ?


Pour un debut, c'est plutot bien. Ce n'est d'ailleurs pas dans mes
habitudes de commenter les programmes des debutants, mais le tient etait
particulierement comprehensible alors je me suis lache (et c'est rare ;-) )

a+, ld.

Avatar
Pierre Maurette
Salut,

Voilà... je suis super débutant... Je poste ici mon premier programme
fait maison....

Je voudrait avoir votre avis..

J'utilise Xcode sur un macintosh sous 10.4.4, mais cela n'a pas beaucoup
d'importance...
Je vous donne celui d'un non professionnel. D'autres suivront ;-)


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

(inutile ici je pense, mais on l'oublie facilement quand on utilise des
float/double)


int main (int argc, const char * argv[]) {
avec:

int main(void) {
vous évitez des warnings possibles et exprimez clairement le fait que
vous ne lirez pas les paramètres de la ligne de commandes.


//on défini les variables
Là, vous entrez dans le mode "commentaires inutiles", ceux qui

paraphrasent l'évident.

// est C99, et effectivement le plus souvent une extension en C89/C90.
Peut-être préférer /* */

char Nom[200];
Il est de bon ton de ne pas coder en dur ce genre de valeur:

#define TAILLE_NOM 200
/* ... */
char nom[TAILLE_NOM];
ou
char nom[TAILLE_NOM + 1];


float quantite; // la variable quantité
Voir "commentaires inutiles" ;-)

Dans ce contexte, utilisez systématiquement des double. C'est pas plus
cher, et le float sont vraiment calamiteux en précision.
Mais même avec des double, posez-vous lma question de la nécessité d'un
calcul exact. Voulez-vous par exemple que la somme des TVA soit égale à
la TVA sur la somme ? Il existe des normes pour ce genre de calcul,
mais vous pouvez déjà envisager un calcul entier sur des centimes ou
des millimes.


float prix; // la variable prix
float total; // la variable total
float tauxtva; // le taux de tva
float soustotal; // le sous tatal sans la tva
float tva; // le montant de la tva
Les noms semblent à peu près corrects, sauf soustotal pour désigner ce

qui sera un prix hors taxe.



printf("Entrez votre nom : ");
scanf("%s", Nom);
printf("n");
printf("Taux de tva ? : "); // on demande le taux de tva
scanf("%f",&tauxtva);
printf("n");
printf("Quantite de l'article a facturer ? : "); // on demande
la quantité
scanf("%f",&quantite);
printf("n");
printf("Le prix de l'article ? : "); // on demande le prix
scanf("%f",&prix);
printf("n");
Je ne suis pas compétent, n'utilisant les entrées standard que pour des

tests rapides, mais c'est de toute évidence insuffisant. Regardez ce
qui se passe selon que vous saisirez une TVA de 5.5 ou de 5,5


// le calcul

soustotal = quantite * prix;
tva = (soustotal * tauxtva)/100;
total = soustotal + tva;

//on affiche le résultat

printf ("Montant a payer hors tva %.2fnn",soustotal);
printf ("TVA a payer : %.2fnn", tva);
printf ("%s, vous avez un total a payer : %.2fn", Nom, total);

return 0;
}

Est-ce assez clair dans la présentation (pour ce cas-ci bien sur) ?

A+



--
Pierre Maurette

Avatar
Fred
Salut,

Voilà... je suis super débutant... Je poste ici mon premier programme
fait maison....

Je voudrait avoir votre avis..

J'utilise Xcode sur un macintosh sous 10.4.4, mais cela n'a pas beaucoup
d'importance...

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

int main (int argc, const char * argv[]) {

//on défini les variables
char Nom[200];
float quantite; // la variable quantité
float prix; // la variable prix
float total; // la variable total
float tauxtva; // le taux de tva
float soustotal; // le sous tatal sans la tva
float tva; // le montant de la tva

printf("Entrez votre nom : ");
scanf("%s", Nom);
printf("n");
printf("Taux de tva ? : "); // on demande le taux de tva
scanf("%f",&tauxtva);
printf("n");
printf("Quantite de l'article a facturer ? : "); // on demande
la quantité
scanf("%f",&quantite);
printf("n");
printf("Le prix de l'article ? : "); // on demande le prix
scanf("%f",&prix);
printf("n");

// le calcul

soustotal = quantite * prix;
tva = (soustotal * tauxtva)/100;
total = soustotal + tva;

//on affiche le résultat

printf ("Montant a payer hors tva %.2fnn",soustotal);
printf ("TVA a payer : %.2fnn", tva);
printf ("%s, vous avez un total a payer : %.2fn", Nom, total);

return 0;
}

Est-ce assez clair dans la présentation (pour ce cas-ci bien sur) ?

A+


Bonjour,

Sur la structure du programme, je préconise toujours d'écrire une
fonction pour traiter le problème. Le "main" se contente alors
d'analyser les paramètres (argc, argv), de les mettre en forme et
d'appeler la fonction. Ceci permettra à terme de mettre facilement la
fonction dans une bibliothèque. Le mieux étant d'écrire d'emblée la
fonction dans un fichier séparé.

Une autre remarque concernant les flux : il est bien de ne pas mélanger
les questions posées à l'utilisateur et l'affichage du résultat, dans
l'optique d'une utilisation du programme au sein d'un script ou en tant
que filtre. Ou alors prévoir un mode silecieux. Il faut toujours
envisager des utilisations du genre :

mon_prog > fic_resultat
ou
cat data | mon_prog | prog2 > result

NB : Ces remarques ne se limitent pas au C. Elles peuvent être
appliquées à n'importe quel langage.

A+
Fred

Avatar
Jean-Marc Bourguet
writes:


Laurent Deniau writes:

Et de tout facon j'utilise eassert qui a le meme comportement que assert
(et eassert.h que assert.h) mais leve une exception ExBadAssert en cas
d'echec au lieu de quitter le programme.


Pour pouvoir faire quelque chose une fois que l'exception est
attrapee, il faut etre sur d'au moins une partie de l'etat du
programme. De quelle partie de l'etat es-tu sur apres qu'une
assertion echoue? Si tu as l'equivalent des destructeurs, comment
ceux-ci peuvent ils etre sur que l'etat des objets qu'ils doivent
detruire, ils ne connaissent pas la cause pour laquelle ils sont
appeles.


C'est un vaste sujet!
[snip des choses interessantes auxquelles je fais faire une

seconde reponse]

Tu ne reponds pas au fond de ma question qui portait sur
l'etat que tu supposais valide apres qu'une *assertion*
echoue.

J'utilise des assertions pour verifier que mes hypotheses
sur l'etat du programme sont vraies. Si elles ne sont pas
vraies, je me demande ce que je peux encore supposer et
faire de sense avant de quitter.

Le plus souvent, la cause de l'echec est un defaut
d'analyse: l'etat est valide mais le programme n'est pas
prevu pour traiter ce cas la. Mais il n'est pas rare qu'on
se retrouve avec un etat invalide, soit que l'hypothese a
ete tenue pour vraie avant, soit qu'il y a une erreur dans
le programme.

Si dans le premier cas on peut imaginer des actions de
recuperation et de continuer a fonctionner, dans le deuxieme
le faire -- surtout sans avertir l'utilisateur -- est plus
problematique. Au pire on risque de fournir des resultats
subtilement faux qui seront difficilement detectes.

Le probleme est que quand on ecrit l'assertion, on ne sait
pas si elle echouera pour la premiere ou la deuxieme raison
(si je sais que c'est un cas possible mais pas encore
traite je n'utilise pas une assertion), donc il faut prevoir
le pire.

Je comprends qu'on puisse tenter de faire des choses
avant de partir, mais a mon sens elles sont limitees
(sauver une copie des donnees en memoire mais
certainement pas ecraser les donnees originales).


Pas seulement. Par exemple liberer de la memoire et
recommencer,
diminuer la taille des paquets/buffers traites et recommencer,
reinterroger une BD avec des entrees differentes, demander a
l'utilisateur qqchose de mieux adapte, changer le contexte d'un
parseur,


Ce ne sont pas des choses que je tenterais apres l'echec
d'une assertion.

afficher/logger qqchose avant de quitter,


Ceci oui.

etc... Bien que je sois partisant de l'utilisation des
exceptions dans des cas ... exceptionnels, cette
stabilite permet aussi de les utiliser pour faire des
tentatives.


Je suis d'accord pour les exceptions. Je comprends bien
qu'on concoive sans elles du tout. Mais quand elles sont
presentes ne pas les utiliser si elles conviennent (par
exemple parce qu'on a decide arbitrairement qu'il ne fallait
les utiliser que pour les erreurs) est aussi stupide de les
utiliser quand elles ne conviennent pas (parce qu'on a
decide qu'il fallait les utiliser pour *toutes* les
erreurs).

A+

--
Jean-Marc



Avatar
Jean-Marc Bourguet
writes:

si le constructeur commence par rendre son objet neutre
pour son destructeur (e.g. mettre les pointeurs a NULL)
avant d'appliquer son code d'initialisation, l'objet est
potentiellement toujours valide pour le destructeur meme
en presence d'une exception pendant la construction
(important pour le dernier point).


Tu as donc une construction en deux phases? Comment
s'organise la construction des parents et des membres?

A+

--
Jean-Marc

Avatar
Harpo
David Remacle (Clampin wrote:

Salut,

Voilà... je suis super débutant...


Ca se voit, tu utilises scanf()

Je poste ici mon premier programme fait maison....

Je voudrait avoir votre avis..


Le mien est 'plutôt bon' pour un premier programme fait maison.
Je n'ai pas grand chose à ajouter à ce qu'ont dit les autres
intervenants, juste :

Compile toujpurs avec de options qui donnent un bon niveau de warning,
avec gcc '-W -Wall' est un minimum.

Utilise les commentaires avec parcimonie et à bon escient.

float prix; // la variable prix


Celui-là, je l'encadre !

Les commentaires sont des armes à double tranchant, il peut arriver
qu'en modifiant un programme on oublie de modifier le commentaire et il
n'a plus guère comme intérêt d'induire en erreur le type qui relit.

Tu as commenté les variables, c'est excellent, il est, amha, souvent
préférable de commenter les variables pour donner leur sémantique que
de commenter les instructions, c'est plus facile pour le type qui
relis, tu as aussi trouvé des noms corrects, mnémoniques, pas des i, j,
k etc., c'est cool.

Sinon, je me suis endormi avant la fin et je n'ai pas vérifié les scanf
(il faut me payer pour ça),
Ok, continue...
--
http://harpo.free.fr/

Avatar
Pierre Maurette
[]
Utilise les commentaires avec parcimonie et à bon escient.
Sacrés joueurs, Parsimoni et Abhonessian. Un toucher de balle ...


--
Pierre Maurette

Avatar
Emmanuel Delahaye
Voilà... je suis super débutant... Je poste ici mon premier programme
fait maison....

Je voudrait avoir votre avis..

Est-ce assez clair dans la présentation (pour ce cas-ci bien sur) ?


Mes commentaires (-ed-)

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

/* -ed-
int main (int argc, const char * argv[]) {

le prototype officiel avec arguments est
*/
int main (int argc, char * argv[]) {

//on défini les variables
/* -ed- 8 caracteres d'indentation, c'est beaucoup.
En principe, 2 a 4 suffisent. (je mets 3)
*/
char Nom[200];
float quantite; // la variable quantité
/* -ed- le choix de float est discutable. On prefere travailler en double,
qui est le type 'naturel des flottants' (pas de conversion,
meilleure precision), et ne passer en float que si necessaire
(gain de place, stockage de masse...) */

float prix; // la variable prix
float total; // la variable total
float tauxtva; // le taux de tva
float soustotal; // le sous tatal sans la tva
float tva; // le montant de la tva

printf("Entrez votre nom : ");
/* -ed- cette ligne n'est pas terminee. Il faut ajouter : [1] */
fflush (stdout);

scanf("%s", Nom);
/* -ed- scanf() n'est pas une fonction pour debutant.
Elle est ici mal utilisee et produit un trou de securite.
(pas de limitation du nombre de caracteres saisis.

Il existe des alternatives sures. [2]
*/

printf("n");
printf("Taux de tva ? : "); // on demande le taux de tva
scanf("%f",&tauxtva);
printf("n");
/* -ed-
printf("Quantite de l'article a facturer ? : "); // on demande
la quantité

Une parfaite illustration de 2 problemes :
- Le placement d'un commentaire en bout de ligne n'est pas une bonne idee.
Sa place est plutot au-dessus de la ligne a commenter.
- L'usage des commentaires // qui ne sont pas recommandes pour cette
raison
et parce qu'ils sont C99, donc pas portable sous C90.

D'autre part, je deconseille l'usage des accentuees dans les
commentaires
pour des questions de portabilite.
*/
/* on demande la quantite */
printf("Quantite de l'article a facturer ? : ");

scanf("%f",&quantite);
printf("n");
printf("Le prix de l'article ? : "); // on demande le prix
scanf("%f",&prix);
printf("n");

// le calcul

soustotal = quantite * prix;
tva = (soustotal * tauxtva)/100;
total = soustotal + tva;

//on affiche le résultat

printf ("Montant a payer hors tva %.2fnn",soustotal);
printf ("TVA a payer : %.2fnn", tva);
printf ("%s, vous avez un total a payer : %.2fn", Nom, total);

return 0;
}

/*
Details

[1] http://mapage.noos.fr/emdel/notes.htm#fflush_stdout

[2] http://mapage.noos.fr/emdel/notes.htm#saisie
http://mapage.noos.fr/emdel/notes.htm#fichiers

*/

--
A+

Emmanuel Delahaye

Avatar
Emmanuel Delahaye
#include <math.h>
(inutile ici je pense,


ben oui. A quoi ca sert ?
char Nom[200];


Il est de bon ton de ne pas coder en dur ce genre de valeur:


Pourquoi ? Il n'y a pas de meilleur endroit pour definir la taille d'un
tableau que la definition du tableau lui meme. Ca facilite la lecture et
la maintenance. sizeof permet toujours de retrouver la taille, sinon, la
passer en paramètre.

#define TAILLE_NOM 200
/* ... */
char nom[TAILLE_NOM];
ou
char nom[TAILLE_NOM + 1];


incoherent.

char nom[LONGUEUR_MAX_NOM + 1];

printf("Quantite de l'article a facturer ? : "); // on demande
la quantité



Ne compile pas... (ligne coupée)

--
A+

Emmanuel Delahaye


Avatar
Emmanuel Delahaye
par defaut stdout vide son buffer sur un 'n'

setvbuf(stdout, 0, _IONBF);


main.c:33: error: too few arguments to function `setvbuf'

assert(scanf("%199s", Nom) == 1);


Argh, ! Ne jamais faire ça ! Non compilé (du tout) en mode release ! Le
scanf() saute aussi !

Par simplicite, j'ai utilise assert pour les verifications, mais un test
avec if() suivit d'un message d'erreur clair et le cas echeant une
sortie propre du programme sont preferable.


Je veux !

--
A+

Emmanuel Delahaye

1 2 3 4 5