Initiation pragmatique au langage C


Télécharger Initiation pragmatique au langage C

★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Télécharger aussi :


CHAPITRE 1 : Les éléments de base du langage C

1)  Introduction :

Un langage de programmation a pour finalité de communiquer avec la machine. Il y a diverses manières de communiquer avec la machine. Le langage « maternel » de la machine n'utilise que deux symboles (0 et 1) : c'est le langage machine. Par exemple le nombre 5 est reconnu par une machine par la succession des symboles 1,0,1 (c'est la représentation du nombre en base 2). De même, les opérations qu'une machine est capable d'exécuter sont codées par des nombres, c'est-à-dire une succession de 0 et 1. Par exemple, l'instruction machine

00011010  0001    00000010

demande à la machine d'effectuer l'opération 1 + 2. A chaque type de machine correspond, un jeu d'instructions spécifiques; de même le codage des instructions est également dépendant de la machine utilisée.

Même si ce langage est le seul qui soit compris par l'ordinateur, il n'est pas le seul moyen de communiquer avec celui-ci. En effet, le besoin d'humaniser cette communication et la première tentative en ce sens est l'invention du langage assembleur. Par exemple, l'instruction assembleur

add $1 $2

demande à la machine d'effectuer l'opération 1+ 2. Ce langage est très proche du langage machine et se contente de donner des noms mnémotechniques pour les instructions ainsi qu'une manière plus naturelle de désigner des entiers. Le langage assembleur fut suivi par des langages plus sophistiqués. En particulier, on distingue les langages qui permettent la programmation structurée (fortran, pascal, algol, C, perl, tcl ),

  • la programmation structurée et modulaire (ada, modula, C, pascal),
  • la programmation fonctionnelle (lisp)
  • la programmation logique (prolog)
  • la programmation objet (smalltalk, eifel, C++, java).

2)  Le compilateur :

Ces langages, que nous avons cités, ont tous pour ambition de faciliter la programmation en la rendant plus proche du « langage humain ». Tous ces langages de programmation ont besoin d'un « traducteur » pour être compris par la machine. De tels traducteurs sont généralement appelés interpréteurs ou compilateurs.  

ils traduisent le texte écrit par un programmeur en un programme exécutable contenant que des suites de 0 et 1  (compréhensible par la machine).

Un programme C est un texte écrit avec un éditeur de texte, respectant une certaine syntaxe et stocké sous forme d'un ou plusieurs fichiers (généralement avec l'extension .c). A l'opposé du langage assembleur, les instructions du langage C sont obligatoirement encapsulées dans des fonctions et il existe une fonction privilégiée appelée main qui est le point de départ de tout programme. Voici, un exemple de programme C

main()

{

   printf("Bonjour");

}

Ce programme afficher la chaîne de caractères Bonjour à l'écran. Pour afficher cette chaîne, le programme fait appel à la fonction printf qui fait partie de l'une des fonctions prédéfinies fournies avec tout compilateur C (la fonction write() est son équivalente en langage Pascal). L'ensemble de ces fonctions prédéfinies (appelé bibliothèque C) est stocké dans un ou plusieurs fichiers(s). La traduction du fichier texte ci-dessus en un programme exécutable se décompose en deux phases:

  • la compilation qui est la traduction d'un programme C en une suite d'instructions machine; le résultat produit est un fichier objet (généralement avec l'extension .o).
  • l'édition des liens produit à partir d'un ou de plusieurs fichiers objets et des bibliothèques, un fichier exécutable. Outre l'assemblage des divers fichiers objets, l'édition des liens inclut les définitions des fonctions prédéfinies utilisées par le programme.

Exemple : compilation de fichier (fich.c) contenant un programme :

3)  Les fichiers include :

Pour compiler correctement un fichier, le compilateur a besoin d'informations concernant les déclarations de structures de données et de variables externes ainsi que de l'aspect (on dira prototype) des fonctions prédéfinies se trouvent dans des fichiers avec l'extension .h.

Ces fichiers doivent être inclus dans le fichier que l'on veut compiler. Pour ce faire, le langage C offre la directive du préprocesseur.

# include nom de fichier

Par exemple, pour utiliser la fonction printf (fonction qui affiche une chaîne de caractère sur l’écran), il faut inclure le fichier « stdio.h », qui contient les déclarations de variables externes et les prototypes de fonctions de la bibliothèque d'entrée-sortie standard (standard input/output), dans le fichier que l'on veut compiler de la manière suivante:

#include <stdio.h>

Voici la version correcte du programme présenté précédemment

#include <stdio.h>

main()

{

printf("Bonjour");

}

4)  Les commentaires :

Dès lors que l'on écrit un programme important, il est indispensable d'y inclure des

commentaires qui ont pour but d'expliquer ce qu'est sensé faire le programme, les conventions adoptées et tout autre information rendant le programme lisible à soi même et à autrui.

Un commentaire commence par les caractères /* et se terminent par */. A l'intérieur de ces délimiteurs toute suite de caractères est valide (sauf évidemment */).

Exemple :

/* Ce programme imprime la chaine de caractéres "bonjour" à l'écran

*/

#include <stdio.h>     /* Fichier include pour utiliser la fonction printf */

main()

{

    printf(" Bonjour ");

}

5)  Les types de données :

5.1)  Les entiers :

En C, on dispose de divers types d'entiers qui se distinguent par la place qu'ils occupent en mémoire :

  • sur 1 octet, les entiers signés et non signés (char) et (unsigned char).
  • sur 2 octets, les entiers signés et non signés (short) et (unsigned short).
  • sur 4 octets, les entiers signés et non signés (long) et (unsigned long) .
  • le type int (unsigned int) est selon les machines synonymes de short (unsigned short) ou de long (unsigned long) 4

5.1.1)  Le type char :

Le type char désigne un entier signé codé sur 1 octet.

Comme nous pouvons constater le type char n'est qu'un entier codé sur un octet. Il en découle que toutes les opérations autorisées sur les entiers peuvent être utilisées sur les caractères, on peut par exemple ajouter ou soustraire deux caractères, ajouter ou soustraire un entier à un caractère.

5.1.2)  Les types short, long ou int

Le type short représente un entier signé codé sur 2 octets (de -32768 à 32767) et le type unsigned short représente un entier non signé codé sur 2 octets (de 0 à 65535). Le type long (ou int pour nos machines) représente un entier signé codé sur 4 octets (de -2147843648 à 2147843647) et le type unsigned long (ou unsigned int pour nos machines) représente un entier non signé codé sur 4 octets (de 0 à 4294967295).

5.2)  Le type réel :

Les nombres à virgule flottante (abusivement appelés réels) servent à coder de manière approchée les nombres réels. Un nombre à virgule flottante est composé d'un signe, d'une mantisse et d'un exposant. On dispose de trois types de nombres à virgule flottante, les types float, double et long double.

5.3)  Les constantes de type caractère :

Les constantes de type caractère se note entre apostrophes:

'a'  ,  '2'



Le caractère ' se note '\'' et le caractère \ se note '\\'. On peut également représenter des caractères non imprimables à l'aide de séquences d'échappement. Voici une liste non exhaustive de caractères non imprimable:

5.4)  Les chaînes de caractères :

Les chaînes de caractères se note entre guillemets:

"langage C"     "C'est bientot fini !!!"

Une chaîne de caractères est une suite de caractères (éventuellement vide) entre guillemets. Il en découle que l'on est autorisé à utiliser les séquences d'échappement dans les chaînes.

Exemple :

La fonction suivante :

printf("Bonjour\nComment ca va \n");

produit la sortie suivante :

Bonjour

Comment ca va

En mémoire, une chaîne de caractères est une suite de caractères consécutifs et dont le dernier élément est le caractère nul '\0'.

6)  Définir et déclarer des variables

En C, toute variable utilisée dans un programme doit auparavant être définie. La définition d'une variable consiste à la nommer et lui donner un type et éventuellement lui donner une valeur initiale (on dira initialiser ). C'est cette définition qui réserve (on dira alloue) la place mémoire nécessaire en fonction du type.

Initialiser une variable consiste à remplir, avec une constante, l'emplacement réservé à cette variable. Cette opération s'effectue avec l'opérateur =.

Exemple :

int x ;                                     /*variable de type entier*/

char c;                                 /*variable de type caractère  */

float  q = 1.3;     /* variable réel initialisée par 1,3 */

Un certain nombre d'identificateurs sont réservés et ne peuvent être utilisés comme noms de variables. Voici la liste des noms réservés :

auto      break      case      char      const      continue      default      do

double      else      enum      extern      float      for      goto      if     int

long      register      return       short      signed      sizeof      static     struct

switch      typedef      union      unsigned      void      volatile      while

7)  Les entrées-sorties :

Un programme n'a d'intérêt que dans la mesure où il communique avec l'utilisateur. Il faut donc que l'utilisateur lui entre des données et que le programme, après calcul  sorte des résultats. Les fonctions d'entrée-sortie vont permettre de réaliser cette communication.

7.1)  Les sorties.

Les résultats calculés par un programme sont affichés à l'utilisateur soit sur l'écran (sortie standard), soit dans un fichier de résultats.

sortie formatée avec printf : La fonction printf affiche à l'écran les arguments fournis.

La syntaxe de cette fonction est de la forme :

printf("format", arg1, arg2, ..., argN); .

L'argument format est une chaîne de caractères contenant éventuellement des spécifications.

Une spécification de format est donnée par le caractère % suivi d'une ou plusieurs lettres clé.

Voici à titre d'exemple, quelques spécifications possibles:

Exemple :

#include<stdio.h>

main()

{

 int i,j ;                             /*déclaration de deux variables i et j de type entier*/

 float x ;                           /*déclaration de variable de type réel*/

char c;                             /*déclaration de variable de type caractère*/

i=5;                                 /*initialisation de i par 5*/

j=i+1 ;                            /*initialisation de  j par i+1*/

x=3.2;                             /* initialisation de x par 3.2*/ 

c=’A’;                             /*initialisation de c par le caractère A*/

printf(“ la valeur du nombre réel est : %f ‘’ ,x );

printf(‘’ la variable c contient le caractère : %c‘’, c) ;

printf(‘’ i= %d et j=%d‘’ ,i , j );

}

7.2)  Les entrées.

Il s'agit de donner au programme les données nécessaires à son exécution. Par exemple, si l'on veut calculer la somme de deux entiers, le programme attend de l'utilisateur qu'il donne la valeur des entiers. Selon la nature du programme, l'utilisateur aura le choix de fournir ces valeurs de manière interactive (entrée standard), soit en remplissant un fichier contenant ces valeurs.

Entrée formatée avec scanf. La fonction scanf  lit à la console des données. La syntaxe de cette fonction est de la forme :

scanf("format", &arg1, &arg2, ..., &argN); .

L'argument format est celui décrit plus haut. On notera la présence du symbole & devant chaque argument à imprimer. Lorsqu'une lecture est faite avec scanf, il est impératif de rentrer quelque chose qui est rigoureusement identique au format que l'on a défini.

Exemple 1:

scanf("%d", &x); : Le contenu de la variable x est rempli avec ce que l'utilisateur fournira au clavier. Il faut donc entrer un entier suivi d'un retour à la ligne.

Autre entrée. : On dispose également des fonctions int getchar(void) et char *gets(char *s) qui retourne un caractère (resp. une chaîne de caractères) lu par le clavier.

Exemple 2 :

 

#include<stdio.h>

main()

{

  int i,j ;                             /*déclaration de deux variables i et j de type entier*/

 scanf(‘’ %d,& i‘’) ;         /* lecture à partir du clavier de la valeur de i */

 scanf(‘’ %d‘’,& j) ;         /* lecture à partir du clavier de la valeur de j */



 printf(“ la somme de i et j :  %d’’, i+j );

}


CHAPITRE 2 : Opérateurs et expressions

1)  Généralités sur les opérateurs :

Une expression est un objet syntaxique obtenu en assemblant correctement des constantes, des variables et des opérateurs. Par exemple, l'expression x+3. est une expression. Dans le langage C, il y a bien d'autres opérateurs que les opérateurs arithmétiques (+, -, /, …) qu'on a l'habitude de manipuler; il y en a, en fait, plus de quarante opérateurs

1.1)  Opérateurs et priorités :

Nous avons l'habitude de manipuler des expressions (par exemple arithmétiques) et il nous est relativement aisé de préciser exactement le sens des expressions comme : 2+3*4*5-2, 2-3-4  etc...

On sait que ces expressions sont équivalentes à (2+(3*(4*5)))-2, (2-3)-4.

Introduire les parenthèses permet de définir sans ambiguïté l'expression que l'on manipule. A priori, c'est notre culture mathématique qui nous permet de parenthéser ces expressions. Pour éviter l'usage des parenthèses qui alourdissent la lecture, lorsque cela est possible, les mathématiciens ont fixé des règles de priorité pour entre les opérateurs. Par exemple, dans l'expression 2+3*4, la sous expression 3*4 est évaluée en premier et le résultat obtenu est ajouté à la valeur 2 (forme parenthésée : 2 + ( 3 * 4)). On dit que l'opérateur * possède une priorité supérieure à la priorité de l'opérateur +.

De même, dans l'expression 2-3-4, la sous expression 2-3 est évaluée en premier et, au résultat obtenu, on soustrait la valeur 4 (forme parenthésée : (2 - 3) - 4). On dit que l'ordre (d'évaluation) de l'opérateur - est de gauche à droite.

En effet, on utilise les parenthèses lorsqu'on veut évaluer une expression d'une manière autre que celle définie à l'aide de la priorité et de l'ordre d'évaluation. Par exemple, si l'on veut faire 2+3 et multiplier le résultat par 4, on notera (2+3)*4 et il n'est pas possible de l'écrire sans les parenthèses.

1.2)  Les opérateurs du langage C :

1.2.1)  L'opérateur d'affectation :

L'opération la plus importante dans un langage de programmation est celle qui consiste à donner une valeur à une variable. Cette opération est désignée par le symbole= 

L'affectation range une valeur dans une variable (une zone mémoire).

Exemple :

  • l'affectation x=2 range la valeur 2 dans la variable x,
  • l'affectation x=y range dans la variable x le contenu de la variable y,
  • l'affectation x=y+1 range dans la variable x le contenu de la variable y incrémenté de 1.

Remarque :

Une affectation peut figurer en membre droit d'une autre affectation.

L'affectation x=y=1 est parfaitement valide car elle représente l'affectation x=(y=1). Puisque y=1 est une expression, elle peut figurer donc en membre droit d'une affectation. Puisque elle est syntaxiquement juste.

1.2.2)  Les opérateurs arithmétiques :

Les opérateurs +, -, * fonctionnent comme on s'y attend. Par contre, l'opérateur / se comporte de manière différente selon que les opérandes sont des entiers ou des nombres flottants. Lorsqu'il s'agit de nombres flottants, le résultat est un nombre flottant obtenu en divisant les deux nombres. Lorsqu'il s'agit de nombres entiers, le résultat est un nombre entier obtenu en calculant la division entière.

L'opérateur % n'est défini que pour les entiers et le résultat est le reste de la division entière des opérandes.

Rappel sur la division entière : On appelle quotient (q) et reste (r) de la division entière de a et de b, les nombres entiers q et r vérifiant :


a = q * b + r;          0 ≤ r < b

Exemple : Si a=20 et b=3 alors q=6 et r=2 (20 = 6 * 3 + 2).

1.2.3)  Les opérateurs de comparaison :

Théoriquement, le résultat d'une comparaison est une valeur booléenne (vrai ou faux ). Dans le langage C, le résultat d'une comparaison est 1 ou 0 selon que cette comparaison est vraie ou fausse.

Il n'existe pas de type booléen en C; la valeur entière 0 sera considérée comme équivalente à la valeur faux et toute valeur différente de 0 équivalente à la valeur vrai.

Attention !!!

Il ne faut pas confondre  == (test d'égalité) et = (affectation).

Cette confusion (souvent involontaire) est source de nombreuses erreurs. Cette confusion est d'autant plus facile à faire que les deux écritures sont syntaxiquement correctes :

if (x == 2) { ...}

if (x = 2) { ... }

La première teste l'égalité de x et de 2, alors que la deuxième teste la valeur de l'affectation x=2 qui vaut 2. Ainsi, selon que la valeur de x est 2 ou pas, la première forme fera des choses différentes. Par contre, quelque soit la valeur de x, la valeur de l'expression x=2 est toujours 2.

Est donc :

La condition if (x == 2) { ...} est vrai si x égal à 2

La condition if (x = 2) { ... } est toujours vrai

1.2.4)  Les opérateurs logiques :

Rappel de logique : Une variable booléenne est une variable pouvant prendre la valeur vrai ou faux.

Dans le langage C, on dispose des opérateurs logiques (sous une syntaxe particulière) avec lesquels on peut construire des expressions. La valeur d'une expression booléenne est, comme le résultat des comparaisons, une valeur entière.

exemple :

  • : (x<2 && y>3)

L’expression (1) est vrai si x et inférieur à 2 et y supérieur à 3.

1.2.5)  Les autres opérateurs binaires d'affectation :

Les opérateurs suivants ne sont que des raccourcis de notation :

1.2.6)  Les autres opérateurs unaires d'affectation :

Les opérateurs d'incrémentation et de décrémention sont en position de préfixe ou de sufixe :

L’expression  x++ est le raccourci pour :

          x = x + 1;  

L’expression y = x++ est le raccourci pour :

          y = x;

          x = x + 1;

L’expression y = ++x est le raccourci pour :

          x = x + 1;

           y = x;.

CHAPITRE 3 : Les structures de contrôle

1)  Introduction :

Un programme C est constitué de définitions et déclarations de variables et de fonctions. Les fonctions sont construites à l'aide d'instructions combinées entre elles avec des structures de contrôles.

Qu'est qu'une instruction?

Une expression telle que x=0, i++ ou printf("langage C \n") sont des instructions lorsqu'elles sont suivies du caractère point-virgule (;).

x=0;

i++;

printf("langage C \n");

Le point-virgule est appelé terminateur d'instruction.

Les instructions composées ou blocs sont construites avec des instructions simples regroupées à l'aide des accolades { et }. On peut déclarer des variables au début d'un bloc. L'accolade fermante n'est pas suivie d'un point-virgule.

{

  Int i = 0;

  i++;

  printf("langage C\n");

}



2)  L'instruction if :

Cette instruction conditionnelle permet d'exécuter des instructions de manière sélective en fonction du résultat d'un test. La syntaxe de l'instruction est :

          if ( expression) instruction1

ou

          if ( expression)

                    instruction1

          else

                    instruction2

Si l'expression est vraie, l'instruction1 s'exécute; sinon, dans le deuxième cas, c'est l'instruction2 qui s'exécute.

Exemple :

If (i<0)

         printf(‘’ la valeur de i est négative’’) 

Else

         printf(‘’ la valeur de i est positive’’) ;  

si la valeur de i est négative le programme affichera  sur l’écran ‘’ la valeur de i est négative’’

si la valeur de i est positive le programme affichera sur l’écran ‘’ la valeur de i est positive’’

3)  Les instructions while, do et for :

Les instructions itératives ou boucles sont réalisées à l'aide d'une des trois structures de contrôle suivantes:

while ( expression)

             instruction

do

    instruction

while ( expression);

for ( expression1; expression2; expression3)

        instruction

3.1)  L’instruction while :

La structure de contrôle while évalue l'expression et exécute l'instruction tant que cette expression est vraie.

Exemple :

Le programme suivant affiche à l'écran (dans l'ordre) les nombres de 10 à 0.

#include<stdio.h>

main()

{

   x = 10;

    while (x >= 0)                            /* tant que x est positif */

   {

       printf("%d ", x);                        /* afficher x */

       x = x -1;                                 /* décrémenter x */

   }

}

Le résultat  affiché par ce programme :

10   9   8   7   6   5   4   3   2   1   0

3.2)  L'instruction do ... while :

Une variante de l’instruction while est l'instruction do ... while. Contrairement à l'instruction while, l'instruction :

     do instruction while (expression1);

est exécutée au moins une fois. L'itération s'arrête lorsque l'expression1 est fausse.

Exemple :

Le programme suivant fournit le même résultat que l’exemple précédent

main()

{

   x = 10;

    do                           

         {

       printf("%d", x);                        /* afficher x */

       x = x -1;                                 /* décrémenter x */

   } while (x >= 0)                         /* tant que x est positif */

}

La différence entre ce programme et le programme précédent (programme avec l’instruction while) c’est que le programme précédent fait le teste sur x avant l’exécution de bloc d’instruction (printf("%d", x) et x=x-1), alors que ce programme effectue le test sur x après l’exécution du bloc d’instruction.       

3.3)  L'instruction for :

L'instruction for, comme l'instruction while, n'exécute l'instruction que si l'expression est vraie.

for ( expression1; /* Initialisation */

expression2; /* Conditions d'arrêt */

expression3) /* Fin du corps de boucle */

instruction;

Cette instruction qui est composée de trois parties séparées par des point- virgules:

  • expression1 : constitue les initialisations nécessaires avant l'entrée dans la boucle.
  • expression2 : constitue les conditions de bouclage.
  • expression3 : constitue les instructions de fin de boucle.

Exemple :

Le programme suivant calcule le tableau de multiplication de 2.

#include<stdio.h>

main()

int c,i ;

For (i=1 ; i<=10 ; i++)

{

   c = 2 * i ;

   printf(‘’2 x %d =’’,c);

}

L’exécution de ce programme donnera le résultat suivant :


293