Menu Général 

URL: http://www-ipst.u-strasbg.fr/pat/program/tpc.htm

  • D'autres sites sur le C:  http://www.ltam.lu/Tutoriel_Ansi_C/home.htm

  • http://www.multimania.com/dancel/c/c.html
    http://www.loria.fr/~mermet/CoursC/coursC.html
    http://www-inf.enst.fr/~charon/CFacile/default.htm
    Lycée Pape Clément - PESSAC

    Le Langage C

    Introduction

        Aujourd'hui, l'informatique est présente dans tous les domaines de la vie courante, mais à des degrés différents. Il y a pour cela trois grandes raisons :
     

  •     les gains (en temps, argent, qualité) que l'informatique peut apporter,

  •  
  •     le prix abordable des matériels,

  •  
  •     la disponibilité de logiciels dans tous les domaines.

  •  

     
     
     
     
     
     
     

    Deux domaines sont pleinement exploités :

     - les logiciels généraux, vendus en grande série, et donc relativement bon marché, ( windows, word, ...)

     - les logiciels spécifiques, d'un coût total important et donc limités à des sujets très pointus, pour de très grosses industries.(WVOffice de VIEWlogic@, gestion de site ou de process industriel )

        Le domaine intermédiaire, qui peut encore se développer, concerne les programmes spécifiques, pour des applications de moindre importance. Pour cela, il est nécessaire de disposer de langages de programmation. Les tableurs et bases de données par exemple disposent désormais de véritables langages de programmation (souvent orientés objets) qui vont plus loin que les précédents langages de macro-commandes.
        Pour les autres cas, le C est souvent le meilleur choix. En effet, c'est un langage structuré, avec toutes les possibilités des autres langages structurés. Mais il permet également (avec son extension C++) de gérer des objets. A l'inverse, il permet également une programmation proche du langage machine, ce qui est nécessaire pour accéder aux interfaces entre l'ordinateur et son extérieur. Mais son principal avantage est que ces trois types de programmation peuvent être combinés dans un même programme, tout en restant portable sur tous les ordinateurs existants.
        Le langage C a néanmoins deux inconvénients majeurs, c'est d'être un peu plus complexe d'utilisation (mais uniquement du fait de ses nombreuses possibilités), et d'être séquentiel, ce qui ne lui permettra pas d'être le langage optimal pour les machines massivement parallèles (mais aujourd'hui il n'existe pas encore de langage universel pour ce type de machines qui puisse combiner efficacement des calculs procéduraux et du déclaratif).
     
    Historique

    Langages de programmation

    Un ordinateur est une machine bête, ne sachant qu'obéir, et à très peu de choses :
     

  •  addition, soustraction, multiplication en binaire, uniquement sur des entiers,

  •  
  •  sortir un résultat ou lire une valeur binaire (dans une mémoire par exemple),

  •  
  •  comparer des nombres.

  •  

     
     
     
     
     
     
     

         Sa puissance vient du fait qu'il peut être PROGRAMME, c'est à dire que l'on peut lui donner, à l'avance, la séquence (la suite ordonnée) des ordres à effectuer l'un après l'autre. Le grand avantage de l'ordinateur est sa rapidité. Par contre, c'est le programmeur qui doit TOUT faire. L'ordinateur ne comprenant que des ordres codés en binaire (le langage machine), des langages dits "évolués" ont été mis au point pour faciliter la programmation, au début des années 60, en particulier FORTRAN (FORmula TRANslator) pour le calcul scientifique et COBOL pour les applications de gestion. Puis, pour des besoins pédagogiques principalement, ont été créés le BASIC, pour une approche simple de la programmation, et PASCAL au début des années 70. Ce dernier (comme le C) favorise une approche méthodique et disciplinée (on dit "structurée"). Le C a été développé conjointement au système d'exploitation UNIX, dans les Laboratoires BELL, par Brian W Kernigham et Dennis M Ritchie, qui ont défini en 78, dans "The C Language", les règles de base de ce langage. Le but principal était de combiner une approche structurée (et donc une programmation facile) avec des possibilités proches de celles de l'assembleur (donc une efficacité maximale en exécution, quitte à passer plus de temps de programmation), tout en restant standard (c'est à dire pouvoir être implanté sur n'importe quelle machine). Puis ce langage a été normalisé en 1988 (norme ANSI), cette norme apportant un nombre non négligeable de modifications au langage.

     Le C est un langage compilé, c'est à dire qu'il faut :

     * entrer un texte dans l'ordinateur (à l'aide d'un programme appelé EDITEUR),

     * le traduire en langage machine (c'est à dire en codes binaires compréhensibles par l'ordinateur) : c'est la compilation et, si plusieurs modules ont été compilés séparément, l'édition de liens (LINK ou BIND),

     * l'exécuter.

         Contrairement à un basic interprété, l'exécution sera beaucoup plus rapide puisqu'il n'y a plus de traduction à effectuer, mais la phase de mise au point sera plus complexe.

         Bien que le langage soit normalisé, un certain nombre de points dépendent de la machine et du compilateur utilisé (par exemple comment appeler le compilateur). Ces indications ne seront pas données ici. Si vous avez le choix, je vous conseille TURBO C, le plus pratique d'emploi (en particulier parce qu'il possède son propre éditeur de texte). Il permet une mise au point aussi simple que si le langage était interprété.
     
     
    Caractéristiques

             Langage structuré, conçu pour traiter les tâches d'un programme en les mettant dans des blocs.
         Il produit des programmes efficaces : il possède les mêmes possibilités de contrôle de la machine que l'assembleur et il
         génére un code compact et rapide.

         Déclaratif : normalement, tout objet C doit être déclaré avant d'être utilisé. S'il ne l'est pas, il est considéré comme étant
         du type entier.
         Format libre : la mise en page des divers composants d'un programme est totalement libre.

         Cette possibilité doit être exploitée pour rendre les programmes lisibles.

         Modulaire : une application pourra être découpée en modules qui pourront être compilés séparément.

         Un ensemble de programmes déjà opérationnels pourra être réuni dans une librairie. Cette aptitude permet au langage C
         de se développer de lui même.

         Souple et permissivité : peu de vérifications et d'interdits, hormis la syntaxe. Il est important de remarquer que la
         tentation est grande d'utiliser cette caractéristique pour écrire le plus souvent des atrocités.
         Transportable : les entrées/sorties sont réunies dans une librairie externe au langage.
     
     
    Structure d'un programme C

    Un programme C est composé de :


     
     
    Connaissances de base
    regardons ce petit programme :
     
    #include <stdio.h>
    #define TVA 18.6
    void main(void)
     {
      float HT,TTC;
      puts ("veuillez entrer le prix H.T.");
      scanf("%f",&HT);
      TTC=HT*(1+(TVA/100));
      printf("prix T.T.C. %f\n",TTC);
     }

    On trouve dans ce programme :

     * des directives du pré processeur (commençant par #)      ( pas de ;  )

     #include : inclure le fichier définissant (on préfère dire déclarant) les fonctions standard d'entrées/sorties (en anglais STanDard In/Out), qui feront le lien entre le programme et la console (clavier/écran). Dans cet exemple il s'agit de puts, scanf et printf.

     #define : définit une constante. A chaque fois que le compilateur rencontrera, dans sa traduction de la suite du fichier en langage machine, le mot TVA, ces trois lettres seront remplacées par 18.6. Ces transformation sont faites dans une première passe (appelée pré compilation), où l'on ne fait que du "traitement de texte", c'est à dire des remplacements d'un texte par un autre sans chercher à en comprendre la signification.

     * une entête de fonction. Dans ce cas on ne possède qu'une seule fonction, la fonction principale (main function). Cette ligne est obligatoire en C, elle définit le "point d'entrée" du programme, c'est à dire l'endroit où débutera l'exécution du programme. Les fonctions sont écrites sous la forme : entête { corps }

     L'entête est de la forme : type_résultat nom (arguments) . Le type_résultat n'était obligatoire (avant la norme ANSI) que s'il était différent de int (entier). Il doit désormais être void (rien) si la fonction ne renvoie rien (dans un autre langage on l'aurait alors appelé sous-programme, procédure, ou sous-routine). Les arguments, s'ils existent, sont passés par valeur. Si la fonction ne nécessite aucun argument, il faut indiquer (void) d'après la norme ANSI, ou du moins (),

     Le corps est composé de déclarations de variables locales, et d'instructions, toutes terminées par un ;

     * un "bloc d'instructions", délimité par des accolades {     }, et comportant :

     * des déclarations de variables, sous la forme : type listevariables;

     Une variable est un case mémoire de l'ordinateur, que l'on se réserve pour notre programme. On définit le nom que l'on choisit pour chaque variable, ainsi que son type, ici float, c'est à dire réel (type dit à virgule flottante, d'où ce nom). Les trois types scalaires de base du C sont l'entier (int), le réel (float) et le caractère (char). On ne peut jamais utiliser de variable sans l'avoir déclarée auparavant. Une faute de frappe devrait donc être facilement détectée, à condition d'avoir choisi des noms de variables suffisamment différents (et de plus d'une lettre).

     * des instructions, toutes terminées par un ; (point virgule). Une instruction est un ordre élémentaire que l'on donne à la machine, qui manipulera les données (variables) du programme, ici soit par appel de fonctions (puts, scanf, printf) soit par affectation (=).
    L'instruction nulle est composée d'un ; seul.
    Il est recommandé, afin de faciliter la lecture et le "deboguage" de ne mettre qu'une seule instruction par ligne dans le source du programme.

    Un bloc est une suite d'instructions élémentaires délimitées par des accolades { et }
    Un bloc peut contenir un ou plusieurs blocs inclus
    Un bloc peut commencer par des déclarations/définitions d'objets qui seront locaux à ce bloc. Ces  objets ne pourront être utilisés que dans ce bloc et les éventuels blocs inclus à ce bloc.


     Détaillons les 4 instructions de notre programme :

    puts affiche à l'écran le texte qu'on lui donne (entre parenthèses, comme tout ce que l'on donne à une fonction, et entre guillemets, comme toute constante texte en C).

    scanf attend que l'on entre une valeur au clavier, puis la met dans la mémoire (on préfère dire variable) HT, sous format réel (%f).

     une affectation : on commence par diviser TVA par 100 (à cause des parenthèses), puis on y ajoute 1, puis on le multiplie par le contenu de la variable HT. Le résultat de ce calcul est stocké (affecté) dans la variable cible TTC. Une affectation se fait toujours dans le même sens : on détermine (évalue) tout d'abord la valeur à droite du signe =, en faisant tous les calculs nécessaires, puis elle est transférée dans la mémoire dont le nom est indiqué à gauche du =. On peut donc placer une expression complexe à droite du =, mais à sa gauche seul un nom de variable est possible, aucune opération.

    printf affichera enfin le résultat stocké dans TTC.
     
     
    Fonctions d'entrées/sorties les plus utilisées

        Le langage C se veut totalement indépendant du matériel sur lequel il est implanté. Les entrées sorties, bien que nécessaires à tout programme (il faut lui donner les données de départ et connaître les résultats), ne font donc pas partie intégrante du langage. On a simplement prévu des bibliothèques de fonctions de base, qui sont néanmoins standardisées, c'est à dire que sur chaque compilateur on dispose de ces bibliothèques, contenant les même fonctions (du moins du même nom et faisant apparemment la même chose, mais programmées différemment en fonction du matériel). Ces bibliothèques ont été définies par la norme ANSI, on peut donc les utiliser tout en restant portable. Nous détaillerons ici deux bibliothèques : CONIO.H et STDIO.H.
     
     

     Dans CONIO.H on trouve les fonctions de base de gestion de la console :

    putch(char)affiche sur l'écran (ou du moins stdout) le caractère fourni en argument (entre parenthèses). stdout est l'écran, ou un fichier si on a redirigé l'écran (en rajoutant >nomfichier derrière l'appel du programme, sous DOS ou UNIX). Si besoin est, cette fonction rend le caractère affiché ou EOF en cas d'erreur.

    getch(void)attend le prochain appui sur le clavier, et rend le caractère qui a été saisi. L'appui sur une touche se fait sans écho, c'est à dire que rien n'est affiché à l'écran. En cas de redirection du clavier, on prend le prochain caractère dans le fichier d'entrée.

    getche(void)idem getch mais avec écho
     
     

     Dans STDIO.H, on trouve des fonctions plus évoluées, pouvant traiter plusieurs caractères à la suite (par les fonctions de conio.h), et les transformer pour en faire une chaîne de caractères ou une valeur numérique, entière ou réelle par exemple. Les entrées sont dites "bufférisées", c'est à dire que le texte n'est pas transmis, et peut donc encore être modifié, avant le retour chariot.

     On possède encore d'autres fonctions dans STDIO, en particulier pour gérer les fichiers.
     
     
     
     
     
     
     
     
     
     
     
     
    Structure d'une fonction

    Une fonction est un bloc de code d'une ou plusieurs instructions qui peut renvoyer une valeur à l'expression qui l'utilise.

         Elle peut retourner une valeur à la fonction appelante.
         Le programme principal est une fonction dont le nom doit impérativement être main.
         Les fonctions ne peuvent pas être imbriquées.

    La forme générale (en ANSI)d'une fonction est :

      [classe] [type] nom( [liste_de_parametres_formels] )
         bloc_de_la_fonction

    Les éléments entre [] dans cette syntaxe, signifique que cet élément est facultatif, car une valeur par défaut existe.

    En C, le programme principal et les sous-programmes sont définis comme fonctions. Il n'existe pas de structures spéciales pour le programme principal ni les procédures (comme en Pascal ou en langage algorithmique).

    Le programme principal étant aussi une 'fonction', nous devons nous intéresser dès le début à la définition et aux caractéristiques des fonctions en C. Commençons par comparer la syntaxe de la définition d'une fonction en C avec celle d'une fonction en langage algorithmique:

    Définition d'une fonction en langage algorithmique

       fonction <NomFonct> (<NomPar1>, <NomPar2>, ...):<TypeRés>
       |   <déclarations des paramètres>
       |   <déclarations locales>
       |   <instructions>
       ffonction


    Définition d'une fonction en C

       |<TypeRés> <NomFonct> (<TypePar1> <NomPar1>,
       |                      <TypePar2> <NomPar2>, ... )
       |{
       |   <déclarations locales>
       |   <instructions>
       |}
    En C, une fonction est définie par:
     

    * une ligne déclarative qui contient:
     
    <TypeRés> - le type du résultat de la fonction
    <NomFonct> - le nom de la fonction
    <TypePar1> <NomPar1>, <TypePar2> <NomPar2>, ...
    les types et les noms des paramètres de la fonction 

    * un bloc d'instructions délimité par des accolades { }, contenant:
     
    <déclarations locales> - les déclarations des données locales (c.-à-d.: des données qui sont uniquement connues à l'intérieur de la fonction) 
    <instructions> - la liste des instructions qui définit l'action qui doit être exécutée 

    Résultat d'une fonction

     Par définition, toute fonction en C fournit un résultat dont le type doit être défini. Si aucun type n'est défini explicitement, C suppose par défaut que le type du résultat est int (integer).

    Le retour du résultat se fait en général à la fin de la fonction par l'instruction return.

     Le type d'une fonction qui ne fournit pas de résultat (comme les procédures en langage algorithmique ou en Pascal), est déclaré comme void (vide).
     

    Paramètres d'une fonction

     La définition des paramètres (arguments) d'une fonction est placée entre parenthèses ( ) derrière le nom de la fonction. Si une fonction n'a pas besoin de paramètres, les parenthèses restent vides ou contiennent le mot void. La fonction minimale qui ne fait rien et qui ne fournit aucun résultat est alors:

         void dummy() {}


    Instructions

     En C, toute instruction simple est terminée par un point-virgule ; (même si elle se trouve en dernière position dans un bloc d'instructions). Par exemple:

             printf("hello, world\n");
     
     
     
     
    Règles d'écriture des programmes C

    Afin d'écrire des programmes C lisibles, il est important de respecter un certain nombre de règles de présentation :


     
     
    Exemple de programme
    1ère ligne
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13 
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34ème ligne
    /* **************************
       Programme de démonstration
       ***************************/

    #include <stdio.h>  /* directives au préprocesseur */
    #define DEBUT -10
    #define FIN 10
    #define MSG "Programme de démonstration\n"
    /**********************************/
    int carre(int x);   /* déclaration des fonctions */
    int cube(int x);
    /**********************************/

    main()              /* debut programme principal */
    {                   /* début du bloc de la fonction main */
      int i;            /* définition des variables locales */

      printf(MSG);
      for ( i = DEBUT; i <= FIN ; i++ ) 
      { 
         printf("%d   carré: %d   cube: %d\n", i 
                                             , carre(i)
                                             , cube(i) );

      }                 /* fin du bloc for  */
      return 0;
    }                   /* fin du bloc de la fonction main */

    int cube(int x) {   /* definition de la fonction cube */
       return x * carre(x);
    }

    int carre(int x) {  /* definition de la fonction carre */
       return x * x;
    }


     
     
     
     
    Identificateurs

    Les identificateurs nomment les objets C (fonctions, variables ... )

    Recommandations :
     
    Variables / identificateurs / adresse / pointeurs

        On appelle variable une mémoire de l'ordinateur (ou plusieurs), à laquelle on a donné un nom, ainsi qu'un type (on a précisé ce qu'on mettra dans cette variable (entier, réel, caractère,...), pour que le compilateur puisse lui réserver la quantité de mémoire nécessaire. Dans cette variable, on pourra y stocker une valeur, et la modifier au cours du programme.

     Exemple : int a; a est une variable entière, le compilateur va lui réserver en mémoire la place nécessaire à un entier (2 octets en Turbo C). Le nom de cette variable est choisi par le programmeur. On préfère utiliser le terme identificateur plutôt que le nom, car il permet d'identifier tout objet que l'on voudra utiliser (pas seulement les variables).

        Les identificateurs doivent suivre quelques règles de base : il peut être formé de lettres (A à Z), de chiffres et du caractère _ (souligné). Le premier caractère doit être une lettre (ou _ mais il vaut mieux le réserver au compilateur). Par exemple valeur1 ou prem_valeur sont possibles, mais pas 1ere_valeur. En C, les minuscules sont différentes des majuscules (SURFace et surFACE désignent deux objets différents). Le blanc est donc interdit dans un identificateur(utilisez _). Les lettres accentuées sont également interdites. La plupart des compilateurs acceptent n'importe quelle longueur d'identificateurs (tout en restant sur la même ligne) mais seuls les 32 premiers caractères sont significatifs.

     On considère comme blanc : soit un blanc (espace), soit un retour à la ligne, soit une tabulation, soit un commentaire, soit plusieurs de ceux-ci. Les commentaires sont une portion de texte commençant par /* et finissant par le premier */ rencontré. les commentaires ne peuvent donc pas être imbriqués. mais un commentaire peut comporter n'importe quel autre texte, y compris sur plusieurs lignes.

     Un identificateur se termine soit par un blanc, soit par un signe non autorisé dans les identificateurs (parenthèse, opérateur, ; ...). Le blanc est alors autorisé mais non obligatoire.

     L'endroit où le compilateur a choisi de mettre la variable est appelé adresse de la variable (c'est en général un nombre, chaque mémoire d'un ordinateur étant numérotée de 0 à ? ). Cette adresse ne nous intéresse que rarement de manière explicite, mais souvent de manière indirecte. Par exemple, dans un tableau, composé d'éléments consécutifs en mémoire, en connaissant son adresse (son début), on retrouve facilement l'adresse des différentes composantes par une simple addition.
    On appelle pointeur une variable dans laquelle on place (mémorise) une adresse de variable (où elle est) plutôt qu'une valeur (ce qu'elle vaut).

     Les types de variables scalaires simples que l'on utilise le plus couramment sont le char (un caractère), l'int (entier) et le float (réel). Le char est en fait un cas particulier des int, chaque caractère étant représenté par son numéro de code ASCII.
     
     
    Expressions / opérateurs

    Une expression est un calcul qui donne une valeur résultat (exemple : 8+5). Une expression comporte des variables, des appels de fonction et des constantes combinés entre eux par des opérateurs (ex : MaVariable*sin(VarAngle*PI/180) ).

     Une expression de base peut donc être un appel à une fonction (exemple sin(3.1416) ).
    Une fonction est un bout de programme (que vous avez écrit ou faisant partie d'une bibliothèque) auquel on "donne" des valeurs (arguments), entre parenthèses et séparés par des virgules. La fonction fait un calcul sur ces arguments pour "retourner" un résultat. Ce résultat pourra servir, si nécessaire, dans une autre expression, voire comme argument d'une fonction exemple atan(tan(x)).
    Les arguments donnés à l'appel de la fonction (dits paramètres réels ou effectifs) sont recopiés dans le même ordre dans des copies (paramètres formels), qui elles ne pourront que modifier les copies (et pas les paramètres réels).
    Dans le cas de fonctions devant modifier une variable, il faut fournir en argument l'adresse (par l'opérateur &, voir plus bas), comme par exemple pour scanf.

     Pour former une expression, les opérateurs possibles sont assez nombreux, nous allons les détailler suivant les types de variables qu'ils gèrent.
     
     
    Séquences d'échappement: voir les deux bibliothèques : CONIO.H et STDIO.H.

     Comme nous l'avons vu au chapitre 2, l'impression et l'affichage de texte peut être contrôlé à l'aide de séquences d'échappement. Une séquence d'échappement est un couple de symboles dont le premier est le signe d'échappement '\'. Au moment de la compilation, chaque séquence d'échappement est traduite en un caractère de contrôle dans le code de la machine. Comme les séquences d'échappement sont identiques sur toutes les machines, elles nous permettent d'écrire des programmes portables, c.-à-d.: des programmes qui ont le même effet sur toutes les machines, indépendemment du code de caractères utilisé.

    Séquences d'échappement
    \a sonnerie \\ trait oblique 
    \b curseur arrière \? point d'interrogation
    \t tabulation \' apostrophe
    \n nouvelle ligne  \" guillemets
    \r retour au début de ligne \f saut de page (imprimante)
    \0 NUL \v tabulateur vertical

    Le caractère NUL

     La constante '\0' qui a la valeur numérique zéro (ne pas à confondre avec le caractère '0' !!) a une signification spéciale dans le traitement et la mémorisation des chaînes de caractères: En C le caractère '\0' définit la fin d'une chaîne de caractères.

    1) caractères précédés de " % " :

    .   %b : affiche en binaire
    .   %c : affiche un caractère
    .   %d : affiche en décimal
    .   %o : affiche en octal
    .   %s : affiche une chaine
    .   %u : affiche en décimal non signé
    .   %x : affiche en hexadécimal

    2) caractères de  commande précédés de " \" :
    .    \a : cloche (bel  $07 )
    .   \? : point d'interrogation
    .   \b : tabulation ( $08 )
    .   \f : saut de page   ( $0c )
    .   \n : à la ligne ( $0a )
    .   \r : retour chariot ( $0d )
    .   \' : apostrophe (  '  )
    .   \" : guillemets     (  "  )
    .   \xHH : valeur en hexadécimal ( 2 chiffres )

    Exemple  printf("n = %d soit en hexa %x et en binaire %b",x,x,x);