IV. Les entrées-sorties standards▲
Dans cet exercice, on étudiera plus en détail les fonctions d'entrées-sorties standards, printf
(
) et scanf
(
).
On approfondira sur l'usage des fonctions personnalisées et leur prototype ainsi que sur l'importance d'une spécification du programme adéquate et le choix judicieux des types de variables.
Cet exercice consiste à créer un programme qui contribuera à l'analyse d'un circuit électrique série simple à courant continu en prenant en compte les tolérances des composants. Supposez qu'on ait un circuit avec une source de tension constante et une résistance.
On cherche à déterminer le courant traversant le circuit et la puissance dissipée par la résistance. C'est un exercice assez simple faisant seulement appel à la loi d'Ohm et à l'expression de la puissance électrique. Pour rendre la chose plus intéressante, la tolérance sur la valeur de la résistance sera prise en compte. Le programme créera un tableau des courants et puissances pour les valeurs nominale, maximale et minimale de la résistance. Ce programme devrait être très utile pour quelqu'un qui commence ses études en électricité. Gardons cela à l'esprit pendant la conception du programme.
Quand on conçoit un programme, on essaie de garder les interactions utilisateur les plus simples et les plus claires possible. Ainsi, essayez de structurer le code afin de faciliter sa maintenance. Les études ont montré que la majeure partie du temps passé en programmation d'applications non triviales relève du domaine de la maintenance (ajouter des fonctionnalités, corriger les bogues, etc.). Efforcez-vous de produire du code aussi clair que l'eau de roche et d'y inclure les commentaires appropriés. Toutefois, n'ajoutez pas de commentaires inutiles et semant la confusion sur du code que n'importe quel débutant comprendrait. Voici un exemple de commentaire superflu :
a =
b +
c; /* additionner b et c */
Bien entendu, ce commentaire n'apporte aucune valeur ajoutée. De même, utilisez des noms de variables mnémoniques quand c'est possible. C'est une façon de commenter le code, par exemple :
x =
y +
z *
60
;
total_seconds =
seconds +
minutes *
60
;
Ces deux lignes de code réalisent chacune les mêmes opérations mathématiques, mais la seconde ligne vous donne un indice sur l'intention du développeur. La première ligne devrait probablement nécessiter l'insertion d'un commentaire pour éclairer tandis que la seconde ligne se suffit à elle-même.
Le programme
Voici une première tentative de spécification de notre programme.
Au prompt (invite de commande), l'utilisateur doit saisir la valeur de la source de tension continue, la valeur nominale de la résistance et sa tolérance. Le programme affichera alors les valeurs de courant et de puissance dissipée sur la base des valeurs nominale, minimale et maximale de la résistance.
Pas mal, mais il faut encore préciser les choses. Premièrement, les programmes en ligne de commande doivent afficher des indications au démarrage. Souvenez-vous qu'il n'y a pas d'interface graphique avec des menus d'aide pour guider l'utilisateur.
Deuxièmement, toujours indiquer les unités des valeurs à saisir au prompt. Si le programme s'attend à des valeurs en ohms et que l'utilisateur saisit des kiloohms, il va y avoir des ennuis. À moins qu'il n'y ait un motif impérieux, il faut toujours préférer les unités de base (ohms plutôt que kiloohms par exemple).
Voici nos spécifications revues et affinées.
Le programme commencera par donner des directives et explications à l'utilisateur sur son fonctionnement. Le programme demande ensuite à l'utilisateur de saisir la valeur de la source de tension continue en volts, la valeur nominale de la résistance en ohms et sa tolérance exprimée en pourcentage. Il affichera alors les valeurs de courant en ampères et la puissance dissipée en watts sur la base des valeurs nominale, minimale et maximale de la résistance.
Remarquez qu'on a spécifié une tolérance exprimée en pourcentage plutôt qu'en facteur. Cela parce que l'utilisateur a plutôt tendance à saisir « 10 » pour 10 % que 0,1. Vous pouvez maintenant exploiter cette spécification pour préparer un pseudo-code ou un diagramme. Voici un pseudo-code possible :
- Affichage des directives à l'utilisateur ;
- Saisie de la valeur de la tension (en volts) ;
- Saisie de la valeur de la résistance (en ohms) ;
- Saisie de la valeur de la tolérance (en pourcentage) ;
- Détermination des valeurs minimale et maximale de la résistance ;
- Calcul des courants sur la base des trois valeurs de résistance ;
- Calcul des puissances dissipées sur la base des trois valeurs de résistance ;
- Affichage d'un entête de tableau pour les valeurs ;
- Affichage des valeurs sous forme tabulaire.
Vous pouvez évidemment choisir un algorithme alternatif ou une autre méthode. Par exemple, vous préférerez peut-être afficher l'entête du tableau avant de faire les calculs, puis afficher les valeurs au fur et à mesure qu'elles sont calculées. Vous préférerez peut-être aussi changer le format d'affichage avec trois colonnes pour chacune des résistances, les courants et puissances étant disposés en ligne.
Vous pourriez aussi changer totalement d'approche en utilisant des boucles ou des tableaux. Il y aura des avantages et des inconvénients pour chaque approche. Parfois, la question n'est pas « Puis-je résoudre ce problème ? », mais « Quelle est la meilleure façon de résoudre ce problème ? » Étendez votre réflexion avant de coder.
Sur la base du pseudo-code ci-dessus, le programme suivant devrait répondre aux objectifs. Il sera amélioré plus tard. Notez l'usage du type de données double
étant donné qu'on a affaire à des valeurs fractionnaires.
Afin d'éviter tout problème d'encodage des caractères accentués dans l'éditeur ou la console, ceux-ci ont volontairement été retirés du code source.
#include <stdio.h>
int
main
(
void
)
{
double
v, tol;
double
rnom, rlow, rhigh;
double
inom, ilow, ihigh;
double
pnom, plow, phigh;
printf
(
"
Ce programme determine le courant et la puissance.
\n
"
);
printf
(
"
Entrez la valeur de la source de tension en volts.
\n
"
);
scanf
(
"
%lf
"
, &
v);
printf
(
"
Entrez la valeur de la resistance nominale en ohms.
\n
"
);
scanf
(
"
%lf
"
, &
rnom);
printf
(
"
Entrez la valeur de la tolerance de la resistance en pourcentage.
\n
"
);
scanf
(
"
%lf
"
, &
tol);
tol =
tol/
100
.0
; /* tolerance convertie en facteur */
rlow =
rnom -
rnom*
tol;
rhigh =
rnom +
rnom*
tol;
inom =
v/
rnom;
ihigh =
v/
rlow;
ilow =
v/
rhigh;
pnom =
v *
inom;
plow =
v *
ilow;
phigh =
v *
ihigh;
printf
(
"
Resistance (ohm) Courant (amp) Puissance (watt)
\n
"
);
printf
(
"
%lf %lf %lf
\n
"
, rnom, inom, pnom );
printf
(
"
%lf %lf %lf
\n
"
, rhigh, ilow, plow );
printf
(
"
%lf %lf %lf
\n
"
, rlow, ihigh, phigh );
}
Une mise au point s'impose : la variable ihigh est la valeur la plus élevée du courant, et non la valeur du courant associée à la plus grande valeur de la résistance. Ce point pourrait prêter à confusion, et pourrait amener à insérer un commentaire ! Ainsi, les bases sont posées. Dans tous les cas, saisissez le code précédent et générez l'exécutable, puis vérifiez qu'il fonctionne.
Vous avez peut-être noté qu'il y avait des répétitions dans le code au niveau des formules et des affichages.
Il serait plus commode de créer des fonctions pour gérer ces répétitions. Par exemple, on pourrait créer une fonction pour calculer le courant :
double
find_current
(
double
voltage, double
resistance )
{
double
current;
current =
voltage/
resistance;
return
(
current );
}
Vous pourriez aussi faire cela en une ligne :
double
find_current
(
double
voltage, double
resistance )
{
return
(
voltage/
resistance );
}
Après mise à jour du programme, on obtient le code suivant :
#include <stdio.h>
double
find_current
(
double
voltage, double
resistance )
{
return
(
voltage/
resistance );
}
int
main
(
void
)
{
double
v, tol;
double
rnom, rlow, rhigh;
double
inom, ilow, ihigh;
double
pnom, plow, phigh;
printf
(
"
Ce programme determine le courant et la puissance.
\n
"
);
printf
(
"
Entrez la valeur de la source de tension en volts.
\n
"
);
scanf
(
"
%lf
"
, &
v);
printf
(
"
Entrez la valeur de la resistance nominale en ohms.
\n
"
);
scanf
(
"
%lf
"
, &
rnom);
printf
(
"
Entrez la valeur de la tolerance de la resistance en pourcentage.
\n
"
);
scanf
(
"
%lf
"
, &
tol);
tol =
tol/
100
.0
; /* tolerance convertie en facteur */
rlow =
rnom -
rnom*
tol;
rhigh =
rnom +
rnom*
tol;
inom =
find_current
(
v, rnom );
ihigh =
find_current
(
v, rlow );
ilow =
find_current
(
v, rhigh );
pnom =
v *
inom;
plow =
v *
ilow;
phigh =
v *
ihigh;
printf
(
"
Resistance (ohm) Courant (amp) Puissance (watt)
\n
"
);
printf
(
"
%lf %lf %lf
\n
"
, rnom, inom, pnom );
printf
(
"
%lf %lf %lf
\n
"
, rhigh, ilow, plow );
printf
(
"
%lf %lf %lf
\n
"
, rlow, ihigh, phigh );
}
L'amélioration n'est pas flagrante. En fait, elle semble même rallonger le code ! C'est vrai, mais attardez-vous un moment sur l'idée sous-jacente. Que deviendrait le code si le calcul du courant impliquait une douzaine de lignes au lieu d'une seule ? Cette nouvelle écriture permettrait donc de réduire considérablement le nombre de lignes de code. Il ne s'agit pas seulement d'avoir moins de code à taper, mais plutôt d'économiser sur la taille de l'exécutable, et cela est particulièrement important sur les systèmes embarqués contraints avec peu de mémoire disponible.
Remarquez que la nouvelle fonction a été ajoutée avant le main
(
). Ce n'est pas obligatoire. On pourrait l'ajouter après le main
(
), mais dans ce cas il faut ajouter le prototype de la fonction pour que le compilateur soit informé quand il découvrira l'appel de la fonction dans le main
(
). Le code avec le prototype devrait ressembler à ce qui suit :
#include <stdio.h>
/* Prototype de la fonction afin de prevenir le compilateur */
double
find_current
(
double
voltage, double
resistance );
int
main
(
void
)
{
....
}
double
find_current
(
double
voltage, double
resistance )
{
return
(
voltage/
resistance );
}
Complétez le programme pour mettre en œuvre cette nouvelle fonction de calcul du courant, et testez-le. Complétez le programme à nouveau pour implanter une fonction qui calcule la puissance, et une fois encore pour implanter une fonction d'affichage des trois valeurs.
Prenez la fonction de calcul du courant comme modèle. Finalement, reconsidérez le fonctionnement du programme et envisagez les dysfonctionnements possibles.
Qu'arriverait-il si l'utilisateur saisissait la valeur 0 comme valeur de résistance ? Comment pourrait-on résoudre ce problème ?