Cours ebook : la pratique du langage C de CEPTA


Télécharger Cours ebook : la pratique du langage C de CEPTA
3.53.5 étoiles sur 5 a partir de 1 votes.
Votez ce document:

Télécharger aussi :


Cours ebook : la pratique du langage C de CEPTA

1.1 L’analyse une étape indispensable pour un projet important.

C’est la phase la plus importante lors de la réalisation d’un programme informatique. Un projet important qui ne commence pas par une analyse sérieuse est destiné à de grandes difficultés ou à l’échec. Les coûts de développements de logiciels sont très élevés, le temps investi dans cette analyse permettra de diminuer le temps de développement global.

1.2 L’éditeur

Crée les fichiers sources *.c et les fichiers header *.h

1.3 Le précompilateur

Il transforme le code source C en code source C pur en exécutant les directives du précompilateur.

1.4 Le compilateur

Il transforme le code C pur en code objet relogeable *.obj 1.5 Le linker (Éditeur de lien)

Il relie les fichiers objets et les librairies utilisateurs et systèmes pour créer le fichier exécutable *.exe

1.6 Le debugger

Permet de tester le programme. 1.7 Les commentaires

Il existe deux méthodes pour écrire des commentaires en C. Le commentaire délimité par /* indiquant le début et */ indiquant la fin du commentaire qui peut être sur plusieurs lignes.

/* J’affirme que cette ligne est un commentaire pouvant se répartir sur plusieurs lignes.*/

Il est aussi possible d’avoir un commentaire se terminant par la fin de ligne. (attention, ne fonctionne par sur tous les compilateurs).

// Ce commentaire se termine à la fin de la ligne.

// Il ne fonctionne pas sur tous les compilateurs (issu du C++)

1.7.1 La pertinence des commentaires

Documenter un programme est une nécessité. Cette documentation doit permettre de comprendre pour pouvoir exécuter des modifications et des corrections de bugs éventuels.

1.7.2 En-tête du programme.

Le programme doit commencer par un en-tête, il doit comprendre au minimum le nom de l’entreprise, l’auteur du programme, le nom du fichier, la description du projet, la date de création, les versions avec une description des modifications ainsi que la date.

Nom de fichier : Monfichier

Auteur : XXX

Description : Programme de gestion de cartes à puces

Version : 1.0 10 jan 00 JMC Version de base.

Version : 1.1 20 jan 00 JMC

Correction du bug 123 (voir rapport x)

1.8 Premier programme

Fichier: PrPrg.cpp

Auteur: JMC

Description: Premier exemple de programme

Version: 1.0

Modifications: pas de modification

#include // accès à la librairie standard input/output

programme principal

void main (void) // fonction main obligatoire

{ // début de bloc

unsigned char MonChar; // Variable locale de type caractère

printf("Voulez vous afficher Hello ? [O/N] \n");

MonChar = getchar(); // lecture d'un caractère du clavier

if(MonChar == 'O') // test si le caractère lu est O

printf("Hello"); // Si O => Affichage à écran

} // fin de bloc

end

1.9 Règles de présentation

L'écriture en C est très compacte. Il faut tout faire pour rendre le programme le plus lisible possible. Pour faciliter la compréhension des logiciels, beaucoup d'entreprises éditent des règles de codage interne. Voici quelques règles de présentation des programmes.

  • Avoir une présentation cohérente tout au long du projet
  • Aligner dans la verticale les accolades de début et fin de bloc
  • Indenter les lignes à l'intérieur d'un bloc
  • Ne pas mélanger sur une même ligne un test et une instruction.
  • Ecrire une seule instruction par ligne.

2 Les variables

Les variables permettent de stocker les données en RAM. Par défaut les variables sont signées. Pour gagner un bit supplémentaire on peut déclarer des variables non signées en ajoutant le préfixe unsigned.

Tous les types de variables permettent d’effectuer des calculs ou des opérations logiques.

Attention : Les tailles des variables peuvent changer en fonction de l’implémentation Il faut vérifier la taille dans la documentation du compilateur.

2.1 Les types de variables

2.1.1 Le type char

Elle peut contenir au minimum 1 caractère du système.

char peut être utilisé pour des opérations arithmétiques.

Si les caractères sont en ASCII => char est un byte (octet).

char ma_data; // ou signed char)

unsigned char ma_ data; //

2.1.2 Le type int

Elle correspond à la taille d’un mot machine, peut être de 8, 16. 32, 64 bits etc.

int ma_data; // ou signed int

unsigned int ma_ data; //

2.1.3 Le type short

Il est plus petit ou égal à un integer short <= int.

short ma_data; // ou short int ou signed short int

unsigned short ma_data; // ou unsigned short int

2.1.4 Le type long.

il est plus grand ou égal à integer long >= int.

long ma_data; // ou long int ou signed short int

unsigned long ma_data; // ou unsigned long int

...

4 Les chaînes de caractères (strings)

Les chaînes de caractères (ASCII ou autres) sont entourées de deux caractères ″.

″ceci est une chaîne de caractères″

4.1 Les caractères non imprimables :

Il peut être nécessaire d’incorporer des caractères non imprimables dans une chaîne de caractères. Ces caractères non imprimables font partie des caractères de contrôle. ils permettent principalement des manipulations du curseur.

\n new line nouvelle ligne

\t horizontal tabulation tabulation horizontale

\v vertical tabulation tabulation verticale

\b back space back space

\r carriage return retour du chariot

\f form feed saut de page

\a audible alert alarme sonore

\000 caractère octal 0 nul ASCII exprimé en octal

\x00 caractère hexadécimal nul ASCII exprimé en hexa

4.2 La représentation des caractères réservés à la syntaxe des strings.

Un certain nombre de caractères sont utilisés pour la syntaxe des chaînes de caractères, pour cette raison ils ne peuvent pas être utilisés telle quel dans des chaînes de caractères, ils sont remplacés par une séquence de caractères.

4.3 Utilisation des caractères de contrôle

″c’est la ligne 1 \n c’est la ligne 2 \n c’est la ligne 3″



Le string s’affiche sur 3 lignes.

4.4 Le string de 1 caractère et le caractère. Il ne faut pas confondre :

‘A’ // est un caractère ASCII A

”A” // représente deux caractères A ASCII et la fin de string NULL ASCII

...

5.2 La fonction de librairie scanf()

Cette fonction fait partie de la libraire stdio (standard input output) Elle permet la saisie de données depuis le clavier. Exemple :

scanf(″%d″,&i) // La variable i est la destination

// %d indique une variable entière signée

On passe à cette fonction le type de donnée et l’adresse de la variable de destination. 5.2.1 Acquisition en une fois de plusieurs variables.

scanf(″%d %d″,&i,&j) // On saisit plusieurs variables en une fois.

L’utilisateur répond en séparant les variables a acquérir par des caractères espace ou par des caractères carriage return.

La fin de l’acquisition étant toujours signalée par un carriage return.

5.2.2 Imposition du format maximum

scanf(″%3d″,&i) // On impose un format maximum pour la variable

Dans ce cas l’acquisition s’interrompt lorsque le nombre de maximum de caractères est atteint. 5.2.3 Caractère invalide dans un format :

La réception d’un caractère invalide termine l’acquisition de la donnée. Par exemple si on entre une variable alphabétique dans un entier.

5.2.4 La valeur de retour de scanf()

int compte ;

compte = scanf(″%3d″,&i) // compte = nombre de champs mis à jour

Le retour de la fonction scanf indique le nombre de champs correctement mis à jour.

compte = scanf(″%3d %3d %3d ″,&i,&j,&k); //compte = nbr de champs

// saisis correctement

Dans ce cas valeur de compte sera de 3 seulement si les 3 champs ont été correctement remplis. Il est donc possible de contrôler si tous les champs à acquérir ont été correctement remplis.

6 Quelques fonctions de librairie 6.1 La fonction getchar()

Cette fonction permet d’acquérir un seul caractère ASCII au clavier. Elle ne requière aucun paramètre. Le caractère de retour est le code de la touche qui doit être mis dans une variable de type char. Exemple :

char c; //

c = getchar(); // keyboard input

6.2 La fonction de librairie putchar()

Cette fonction permet d’afficher un seul caractère ASCII sur l’écran (imprimante). Le paramètre d’entrée est le nom de la variable contenant le caractère à afficher. Exemple :

char c ;

c = ‘A’; // A ASCII dans c

putchar(c); // A ASCII à l’écran

6.3 La fonction de librairie strlen()

Cette fonction string length retourne la longueur d’une chaîne de caractère.

On peut l’appeler de 2 manières, en lui passant le string en paramètre, ou une solution plus élégante en passant l’adresse du string en paramètre.

Exemple avec passage du string sur le stack ( peu recommandable).

int lng; // déclaration, stock la longueur du string

lng = strlen(″hello″); // ici tout le string est mis sur le stack

Autre solution :

int lng; // stock la longueur du string

char *MonString = ″hello″; // pointeur sur le string hello

lng = strlen(MonString); // ici seule l’adresse du string est mise // sur le stack.

7 Les opérateurs les plus usuels. 7.1 L’affectation

= Affectation MaData = 12 ;

7.2 Les opérateurs arythmétiques.

...

9 Les opérateurs logiques

&& and logique pour des conditions (i == TempData) && (j == TempData2);

¦¦ ou logique pour des conditions (i == TempData) ¦¦ (j == TempData2);

! not inversion logique, complément à 1 MaData = (!TempData);

9.1.1 Deux conditions doivent être réalisées

if ((MaData == ProvData) && (MaData2 == ProvData2)) // test avec and

{ // le début de bloc

MaData = MaData + 1; // les instructions

MaData2 = MaData + 2;

} // la fin du bloc if

9.1.2 La conditions 1 ou 2 doit être réalisée

if ((MaData == ProvData) ¦¦ (MaData2 == ProvData2)) // test avec or

{ // le début de bloc

MaData = MaData + 1; // les instructions

MaData2 = MaData + 2;

} // la fin du bloc if

9.1.3 Test avec la condition vraie => différente de 0.

if (MaData)  // si MaData est != 0

{   // le début de bloc

 MaData = MaData + 1; // les instructions

 MaData2 = MaData + 2; 

}   // la fin du bloc if

9.1.4 Test avec condition non vraie => égale à 0.

if (!MaData)  // Si MaData == 0

{   // le début de bloc

 MaData = MaData + 1; // les instructions

 MaData2 = MaData + 2; 

}   // la fin du bloc if

9.1.5 Remarque sur les parenthèses. A la place de

if ((MaData == ProvData) && (MaData2 == ProvData2))

On peut écrire

if (MaData == ProvData && MaData2 == ProvData2)

Les parenthèses clarifient le programme, elles sont recommandées.

10 L’incrémentation et la décrémentation

Pour ajouter ou soustraire 1 à une variable on peut écrire :

i = i + 1 ; // ajoute 1 à la variable i

i = i – 1 ; // soustrait 1 à la variable i

On peut simplifier ces écritures en les remplaçant par :

i++ ; // ajoute 1 à la variable i

i-- ; // soustrait 1 à la variable i

10.1 La pré incrémentation et la pré décrémentation L’incrémentation (décrémentation) est faite avant l’affectation

j = ++i ; // i est incrémenté puis affecté à j

j = --i ; // i est décrémenté puis affecté à j

10.2 La post incrémentation et la post décrémentation L’incrémentation (décrémentation) est faite après l’affectation

j = i++ ; // i est affecté à j puis incrémenté

j = i-- ; // i est affecté à j puis décrémenté.

10.3 Exemple avec pré-incrémentation On va affecter 1 à la variable n, et i = 6

i = 5 ; // initialisation de i

n = ++i -5 ; // n = 1 car i est incrémenté avant !

10.4 Exemple avec post-incrémentation On va affecter 0 à la variable n, et i = 6

i = 5 ; // initialisation de i

n = i++ -5 ; // n = 0 car i est incrémenté après !



...

13 Les contrôles de flux 13.1 La boucle while (tant que)

La boucle while est exécutée tant que la condition entre parenthèse est réalisée.

Le test est fait en début de boucle, le traitement peut ne jamais être exécuté si la condition est déjà réalisée.

while(MaData <= ProvData) //

// condition entre () est testée en début de bloc

{  // le début de bloc du while

 MaData = MaData + 1; 

 MaData2 = MaData + 2; 

}  // la fin du bloc du while

13.1.1 La boucle while infinie.

Il peut être nécessaire de disposer d’une boucle infinie. Cette boucle infinie peut être réalisée de la manière suivante :

while(1) //La condition est toujours réalisée

{ //le début de bloc while

MaData = MaData + 1; MaData2 = MaData + 2;

} //la fin du bloc while

13.2 La boucle do while (faire tant que)

La boucle do while est exécutée tant que la condition entre parenthèse est réalisée.

Le test est fait en fin de boucle, le traitement est toujours exécuté au moins une fois quelque soit la condition d’entrée.

do

{  // le début de bloc du while

MaData = MaData + 1;

MaData2 = MaData + 2;

} while(MaData <= ProvData); // condition entre () est testée

// en fin de bloc, traitement est // effectué au moins une fois.

13.3 La boucle for

La boucle for est exécutée selon trois conditions spécifiées en début de boucle. Elle est surtout utilisée pour des boucles avec compteurs de boucles.

for(cond-1 ;cond-2 ;cond-3) // les conditions de la boucles

{  // le début de bloc for

MaData = MaData + 1; 

MaData2 = MaData + 2; 

}  // la fin du bloc for

13.3.1 Les conditions de la boucle for

for(cond-1 ;cond-2 ;cond-3) // les 3 conditions de la boucles

// sont entre les ()

  • cond-1 C’est l’initialisation du critère de boucle. Cette initialisation est effectuée une seule fois au début de la 1ère boucle.

Remarque : Il est possible d’indiquer plusieurs critères séparés par des virgules et terminés par un ;

cond-2 C’est la condition de test, si elle vraie la boucle est exécutée.

.Le test est effectué au début de la boucle.

Remarque : Il est possible d’indiquer une combinaison logique de plusieurs critères.

cond-3 C’est la modification du compteur de boucle. En pratique on utilise la post incrémentation, c’est à dire une incrémentation en fin de boucle.

Remarque : Il est possible d’indiquer plusieurs critères séparés par des virgules et terminés par un ;

13.3.2 Exemple d’une boucle for

for(i=0;i<3;i++) // conditions de la boucles

{ // le début de bloc for

printf (”la valeur de i = %d/n”,i);

} // la fin du bloc for

L’exécution de cette boucle donnera le résultat suivant :

la valeur de i = 0

la valeur de i = 1

la valeur de i = 2

Il est possible d’omettre des conditions du for. Si la condition n’existe pas elle considérée comme vraie.

13.3.3 La boucle for infinie

for(;;) // Sans condition la boucles

{ // est sans fin

MaData = MaData + 1; MaData2 = MaData + 2;

} // la fin du bloc for

Remarque : Chaque condition est optionnelle.

13.3.4 La boucle for a plusieurs conditions.

for(i=0,j=4;i0;i++,j--) // Conditions multiples

{ // Début de bloc

printf (”la valeur de i = %d j=%d/n”,i,j);

} // fin du bloc for

L’exécution de cette boucle donnera le résultat suivant :

la valeur de i = 0 j = 4

la valeur de i = 1 j = 3

la valeur de i = 2 j = 2

13.4 L’instruction break (rupture)

L’instruction break permet de sortir d’une boucle for, while, do while par un saut à la fin de la boucle. (nous verrons que cette instruction est aussi utilisée dans un switch) Exemple :

while(1) // La boucle est infinie

{ //

MaData = MaData + 1; if (MaData >= 10)

break; // sortie du while par un saut

} // à la fin de la boucle.

L’instruction break fonctionne de la même manière dans les boucles while, do while et for. 13.5 L’instruction continue

L’instruction continue permet de sauter à l’itération suivante est de sauter un traitement. La fin du traitement de la boucle est sauté et l’on passe directement à la boucle suivante. Exemple :

for(i=0 ;i<3;i++) //

{ //

if (i == 1) //Si cette condition est vraie

continue ; //On saute à la boucle suivante

printf (”la valeur de i = %d/n”,i);

} // la fin du bloc for

L’exécution de cette boucle donnera le résultat suivant :

la valeur de i = 0 la valeur de i = 2

L’instruction continue fonctionne de la même manière dans les boucles while, do while et for.

13.6 L’instruction GOTO(Aller à)

L’instruction goto a régné sur la programmation informatique jusqu’à l’arrivée du langage Pascal. Son usage irraisonné a donné naissance à des problèmes de logiciel totalement insurmontables. Actuellement le goto est bannit de la programmation sérieuse. Il reste cependant quelques cas ou le goto est encore nécessaire.

Il s’agit par exemple du traitement d’exceptions nécessitant un redémarrage du programme, ou d’un programmation devant être optimisée en vitesse d’exécution. Attention danger, a utiliser avec extrême prudence et modération.

reset_all: // label pour le saut du programme

if (b==0) // risque de division par 0

goto reset_all // erreur, nouvelle initialisation

else

{

a = a/b ;

}

13.7 L’instruction switch (sélection)

L’instruction switch permet un aiguillage vers différents blocs d’instructions en fonction d’une condition. La condition du switch est entre les (), le programme saute au cas correspondant.

switch(i) // i est la condition du switch

{

case 0 : // Est exécuté si i == 0

j++ ;

break ; // Saut à la fin du switch

case 1 : // Est exécuté si i == 1

j-- ;



break ; // Saut à la fin du switch

case 2 : // Est exécuté si i == 2

j = j + 2;

break ; // Saut à la fin du switch

default : // Est exécuté en cas d’erreur,

i = 0; // la valeur de i n’est pas prévue.

break ; // saut à la fin du switch

}

Remarque : l’instruction break permet le saut à la fin du switch. En cas d’absence du break, le traitement du case suivant est effectué.

switch(i) {

case 0 : // Exécuté si i == 0

printf (”C’est le cas 0”);

break ; // saut à la fin du switch

case 2 : // Exécuté si i == 2

printf (”C’est le cas 2”);

case ’A’ : // Exécuté si i == au caractère ascii A

printf (”C’est le cas A”);

break ; // saut à la fin du switch

default : // Erreur, valeur de i non prévue.

printf (”C’est le cas d’erreur”);

break ; // saut à la fin du switch

}

Remarques :

  • Le case (i == 1) n’est pas prévu dans le switch.
  • Le case (i == 2) n’a pas d’instruction break, le traitement du case ‘A’ sera effectué à la suite de case 2. Ce programme donnera les résultats suivants :

avec i == 0 => on exécute le case 0, on affiche C’est le cas 0

avec i == 1 ou (i > 2 et i != ’A’) =>On exécute la case default car le cas n’est pas prévu.

C’est le cas d’erreur

avec i == 2 => on exécute le case 2 et 3 car l’instruction break du cas 2 manque. C’est le cas 2

C’est le cas A

avec i == ‘A’ => on exécute le case ‘A’ C’est le cas A

14 Le type enum (énuméré)

Il peut être nécessaire d'affecter des valeurs à une liste de symboles. Le type enum permet de réaliser cette liste. Exemple:

enum couleur // nom facultatif de l'énumération

{

ROUGE, // rouge vaut 0

BLEU, // bleu vaut 1

VERT = 4, // vert vaut 4

JAUNE // jaune vaut 5

};

Si aucune valeur n'est précisée le premier élément vaut 0. Chaque élément suivant vaut 1 de plus que le précédent excepté si sa valeur est définie.

14.1 Le switch et l'énumération

Un programme sérieux ne doit contenir aucun chiffre. C'est aussi vrai pour le switch.

Pour assurer la sécurité et fiabilité du switch, il est indispensable chaque fois que c'est faisable de baser chaque cas (case) sur une énumération. Un switch sera ainsi fiable et modifiable. On a alors :

Pour obtenir une fiabilité maximum il est indispensable de baser le switch sur une énumération. On obtient ainsi une fiabilité maximum et on crée ainsi un programme modifiable.

15 Les problèmes dus à la fonction scanf( )

La fonction scanf() pose des problèmes insurmontables. Elle ne peut pas être utilisée dans un programme professionnel pour les raisons suivantes.

  • Aucune maîtrise n'est possible lors de la conversion du code ASCII du clavier en une valeur numérique.
  • Lors d'un appel à la fonction scanf, le PC est en attente d'une pression sur le clavier, pendant cette attente aucune tâche ne peut être exécutée.
  • Lors de plusieurs lectures an moyen d'une boucle le buffer tampon n'est pas encore vidé lors de la boucle suivante, alors le même caractère peut être lu plusieurs fois.

15.1 La maîtrise de la conversion de type.

Pour maîtriser la conversion de type il faut faire l'acquisition des caractères frappés au clavier en deux temps.

  • Acquérir les données dans un buffer temporaire de type char[ ], ce qui permet l'acquisition sans conversion, les caractères sont stockés en code ASCII.
  • Convertir le code ASCII en valeur numérique en utilisant la procédure sscanf().

15.1.1 La fonction gets()

Elle permet l'acquisition d'un string sans conversion. 15.1.2 La fonction sscanf()

Cette fonction convertit un string en une valeur numérique. Elle est appelée avec plusieurs paramètres.

15.1.2.1 En entrée

  • Le string à convertir
  • Le (les) types de la (des) conversions.
  • La ou les variables de destination.

15.1.2.2 En sortie

  • Le compteur de conversion, qui indique le nombre de conversions réussies.

Exemple:  void main (void)

unsigned char TempString[80]; // string temporaire

unsigned int CntInput = 0; // nombre de champs acquis

unsigned int JourMois; //

unsigned int Mois; //

unsigned int Année; //

clrscr();

while(1)

{

printf("entrer une date selon le format jj mm aa\n");

gets(TempString);

CntInput = sscanf(TempString,"%d %d %d", &JourMois, &Mois, &Année);

if ((CntInput == 3) && (JourMois >= 1) && (JourMois <= 31)

&& (Mois >= 1) && (Mois <= 12) && (Année <= 99))

break;

printf("le format n'est pas juste, recommencer !\n");

};

Cette méthode permet d'effectuer la conversion ASCII => numérique après coup avec sécurité.


458