Cours C++

Apprendre à programmer avec le langage C et C++


Télécharger Apprendre à programmer avec le langage C et C++

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

Télécharger aussi :


IUT de Lannion

Dpt Informatique

1ère année

Langage C

Cours et référence

Pierre NERZIC mars 2003


 


Table des matières


A - Présentation.......................................... 1 1 - Historique du langage C................................1 2 - Exemple d'un programme simple.................1 B - Apprentissage du langage.................... 2

1 - Le premier programme C..............................2 2 - Variables simples............................................2 3 - Entrées/sorties ................................................3 4 - Instructions conditionnelles...........................4 5 - Boucles itératives............................................5 6 - Boucles répétitives..........................................6 7 - Fonctions et procédures.................................7 8 - Tableaux..........................................................7 9 - Chaînes de caractères ....................................8 a) Constantes chaînes...............................................8

b) Variables chaînes.................................................9

10 - Types composites : structures ...................10 11 - Variables globales.......................................10

12 - Pointeurs.....................................................11 a) Paramètres de sortie ...........................................11

b) Pointeurs et tableaux..........................................12

C - Structure d’un programme C........... 14

1 - Éléments d'un programme..........................14 2 - Compilation d'un programme C.................15 a) Compilation........................................................15

b) Édition des liens.................................................15

D - Variables et types de données ........... 16

- Définition d'une variable.............................16 a) Syntaxe...............................................................16

b)     Initialisation.......................................................16

- Types simples................................................16 a) Entiers................................................................16

b)     Booléens ............................................................17

c)     Caractères...........................................................17

d)     Réels ..................................................................18

e)     Énumérations .....................................................18 3 - Enregistrements ...........................................19 a) Définition d'un type enregistrement ...................19

b)  Définition d'une variable structurée ...................19

c)  Initialisation d'une variable structurée................19

4 - Tableaux........................................................20 a) Définition d'une variable tableau........................20

b)  Initialisation des éléments..................................20

c)  Définition d'un type tableau ...............................21

d)  Chaînes de caractères.........................................21

E - Opérateurs et expressions.................. 23

1 - Opérateurs numériques...............................23 a) Entiers................................................................23

b)      Réels ..................................................................23

c)      Opérateurs binaires.............................................23 2 - Opérateurs logiques.....................................23 3 - Opérateurs divers.........................................24 a) Accès à un élément d'un tableau ........................24

b)     Accès à un champ d'un struct .............................24

c)     Taille d'une variable............................................24

d)     Conversions de type des valeurs scalaires..........24 4 - Adresses des variables..................................25 a) Obtenir l'adresse d'une variable..........................25

b)  Mémoriser une adresse dans une variable ..........25

c)  Accès à une donnée par son adresse ...................25

d)  Tableaux et adresses...........................................26

F - Instructions et structures de

contrôle ......................................................27 1 - Instructions simples......................................27 a) Affectations ........................................................27

b)      Autres instructions..............................................27

c)      Comment rendre une instruction illisible............28 2 - Blocs et sous-blocs ........................................28 a) Définitions de variables locales..........................29

b) Instructions.........................................................29

- Instructions conditionnelles.........................29 a) Conditionnelles simples......................................29

b)  Conditionnelles multiples...................................29

- Boucles...........................................................30 a) Boucles 'Tant que'...............................................30

b)  Boucles 'Jusqu'à'.................................................30

c)  Boucles 'Pour'.....................................................31

d)  Contrôle des boucles ..........................................31

- Indentation....................................................32

G - Fonctions et procédures.....................32

1 - Définition d'une fonction .............................32 a) Définition............................................................32

b)     Appel..................................................................33

c)     Rappels sur la visibilité d’un symbole................33

d)     Prototypes et prédéclarations..............................33

e)     Passage par valeur ..............................................34

f)      Passage par variable............................................34

g)     Cas des paramètres de type tableau ....................35 2 - Définition d'une procédure..........................35 3 - Procédures et fonctions standard................36 a) Lecture du clavier...............................................36

b)  Affichage sur écran ............................................37

c)  Fichiers...............................................................38

- Librairie mathématique...............................39 a) Déclaration des fonctions ...................................39

b)     Utilisation des fonctions.....................................40

c)     Compilation........................................................40

- Arguments d'un programme.......................40 H - Préprocesseur C..................................41 1 - Inclusion de fichiers .....................................41 a) Présentation ........................................................41

b)     Directives #include.............................................42 2 - Définition de macros ....................................43 a) Constantes ..........................................................43

b) Macrofonctions (macros)....................................43 3 - Compilation conditionnelle..........................44


 


Présentation

A - PRESENTATION

1 - HISTORIQUE DU LANGAGE C

Dennis Ritchie (laboratoires Bell - US) a défini ce langage évolué afin de pouvoir implanter le système Unix sur différents types de machines. Auparavant, les systèmes d'exploitation étaient écrits entièrement en assembleur spécifique à la machine visée. Écrite en langage C, la plus grande partie du système Unix (noyau, librairies et commandes) peut être mise en œuvre sur toute machine possédant un compilateur C. Depuis, ce langage a conquis le monde des entreprises et les universités malgré ses quelques défauts (syntaxe parfois illisible, pas assez de contrôles sémantiques…).

On peut citer deux versions et une extension de ce langage :

•  version originale non normalisée : C standard ancienne et amenée à disparaître peu à peu.

•  version normalisée : C ansi.

•  version objet : C++     (étudiée en deuxième année)

2 - EXEMPLE D'UN PROGRAMME SIMPLE

Les exemples de ce polycopié sont toujours fournis avec deux versions, à gauche un programme C, à droite le programme équivalent en Pascal.

Langage C – facto.c

Langage Pascal –

/* un programme simple */

#define N_MAX 10 int fact(int n)

{ int i,r;  if (n > N_MAX) return –1;  r = 1;  for (i=1; i<=n; i++) {

  r = r * i;

 }

 return r;

}

int Nombre; main() {

 scanf("%d", &Nombre);  printf("fact(%d) = %d\n",Nombre,

  fact(Nombre));

}

{ un programme simple } program simple; const N_max = 3;

function fact(n:integer):integer; var i,r: integer; begin  if n > N_max then fact := -1  else begin   r := 1;   for i:=1 to n do begin    r := r * i   end;   fact := r  end end;  var Nombre: integer; begin  read(Nombre);  writeln('fact(',Nombre,') = ',

  fact(Nombre)) end.

Saisir ce programme dans le fichier facto.c puis le compiler par la commande :

cc -Wall –o facto facto.c

B - APPRENTISSAGE DU LANGAGE

Ce polycopié présente les principes de programmation en langage C en comparant sa syntaxe à celle du langage Pascal sur des exemples simples. Ce polycopié contient deux parties : un cours pour apprendre le langage et une description du langage élément par élément.

Les exemples sont inspirés d’un cours écrit par Kernighan et Ritchie. Ils peuvent être compilés et essayés.

1 - LE PREMIER PROGRAMME C

Voici un programme très simple :

Langage C – salut.c

commentaire

main() {  printf("bonjour à tous\n"); }

nom de la fonction

début de bloc = groupe d’instructions                  corps du programme, instructions fin du bloc

Comme un programme Pascal, un source C contient des définitions de données : constantes, types, variables et des instructions : fonctions et procédures. Le langage C ne fait pas de différence entre fonctions et procédures, les procédures sont des fonctions dont on n’utilise pas le résultat.

Tout programme exécutable doit contenir une et une seule fonction appelée main, cette fonction est le point d’entrée du programme et peut se trouver n’importe où dans le source.

La fonction printf permet d’afficher des données mises en page (print formatted). Son mode d’emploi est printf(format, données…), voir page 3. Le format est une chaîne de caractères indiquant comment il faut afficher les données. Dans cet exemple, on affiche seulement le format, il n’y a pas de données ; \n envoie un retour à la ligne. Il n’y a pas comme en Pascal deux fonctions, l’une pour écrire un retour à la ligne et une autre pour ne pas en écrire – on met ou pas ce \n :

Langage C

Langage Pascal

printf("bonjour à tous\n"); printf("salut");

writeln('bonjour à tous'); write('salut');

Noter les points-virgule obligatoires sur chaque ligne pour indiquer la fin des instructions.

2 - VARIABLES SIMPLES

Langage C – somme.c

commentaire

main() {

 int a, b, c, somme;  a = 1;  b = 2;  c = 3;  somme = a + b + c;

 printf("somme=%d\n",somme); }

définition (création) des variables affectation de valeurs calcul

affichage de la variable somme

Remarquer les différences avec le langage Pascal en ce qui concerne les définitions des variables locales : les définitions sont à l’intérieur du bloc, les noms des types sont un peu différents et précèdent la liste des noms des variables. Remarquer aussi l’affectation, c’est opérateur = (attention à ne pas confondre avec l’opérateur == qui signifie égalité).

Le langage C contient trois types de données fondamentaux :

 char :               entier sur 1 octet, contient le code ascii d’un caractère, on peut lui affecter un code ascii ou

                               un caractère.                              char c;  c = 48;  c = 'A';  c = '\n';

 int :             entier sur 4 octets.                     int n;   n = -15;  float :        réel IEEE sur 4 octets.     float r; r = 3.14; r = 1e-4;

Au contraire du Pascal, les variables ne sont jamais initialisées. Une syntaxe particulière permet de le faire au moment de la définition :

  int nb = 32;

La manipulation des chaînes de caractères en C est assez compliquée car il s’agit de tableaux qu’on doit gérer « à la main », voir page 8. Les chaînes sont délimitées par des guillemets "…".

Les opérateurs de calcul sont presque les mêmes qu’en Pascal, + - * / (au lieu de div) et % (mod).

Langage C – nbblocs.c

commentaire

main() {  int taille, taillebloc=15, nbblocs;  taille = 36;



 nbblocs = ((taille-1)%taillebloc)+1;  printf("nbblocs=%d\n",nbblocs); }

définition (création) des variables affectation de valeurs calcul

affichage de la variable

Les fonctions mathématiques (sqrt, sin, log…) ne sont pas intégrées au langage, il faut faire appel à des librairies externes (voir G - 4 - page 39).

3 - ENTREES/SORTIES

Langage C – somme2.c

commentaire

main() {

 int a=4, b=9;  printf("%d + %d = %d\n", a,b, a+b); }

définition et initialisation de deux variables affichage avec un format

Le premier paramètre de la fonction printf est appelé format, c’est une chaîne qui contient du texte normal et des jokers (%d), les jokers sont remplacés par les valeurs fournies, dans l’ordre où elles se trouvent. Il existe différents jokers pour chaque type de données : %c pour un char, %f pour un float.

Pour entrer un entier dans une variable voici comment on fait, le & est indispensable, voir pages 34 et 36 :

Langage C – double.c

commentaire

main() {  int a;  scanf("%d", &a); printf("double(%d)=%d\n", a, 2*a); }

read(a),  NB : mettre un & devant la variable à lire ! ! !

Voici un programme C peu utile qui récrit un caractère qu’on tape :

Langage C – repete.c

commentaire

main() {  char c;

 printf("taper une touche puis entrée:");  c = getchar();  printf("code de %c = %d\n",c,c);  putchar(c);  putchar('\n');

}

définition (création) de la variable

read(c)

affichage de c et de son code réaffichage de c par putchar affichage d’un retour à la ligne

La fonction getchar n’a pas de paramètre mais les parenthèses sont obligatoires. Elle attend qu’on tape une ligne au clavier (stockée dans un tampon) et renvoie le code ascii du premier caractère tapé (ou le caractère suivant si on rappelle cette fonction, ainsi de suite jusqu’à la fin de la ligne).

On fournit un code ascii ou un caractère à la fonction putchar et elle affiche le caractère en question.

4 - INSTRUCTIONS CONDITIONNELLES

Langage C – signe.c

commentaire

main() {  float nb;  printf("entrer un nombre :");  scanf("%f",&nb);  if (nb >= 0.0) printf("positif\n");  else printf("négatif\n"); }

définition (création) de la variable read(nb)

test sur nb

Noter que les chaînes sont mises entre guillements (double quotes), ex : "oui" et les caractères simples sont mis entre apostrophes, ex : 'c' ; les confondre peut provoquer des erreurs difficile à déceler.

Les conditions sont écrites comme en C-Shell et Awk. Lorsqu’on doit effectuer plusieurs instructions c’est à dire un bloc, on les encadre par des accolades {…} qui jouent le rôle de begin…end.

Langage C – signe2.c

commentaire

main() {  float nb;  printf("entrer un nombre :"); scanf("%f",&nb);  if (nb >= 0.0) {   if (nb > 0.0) { printf("positif\n");

  } else {

printf("nul\n");

  }

 } else printf("négatif\n"); }

{ signifie début de bloc (plusieurs instructions ensemble)

} signifie fin de bloc

5 - BOUCLES ITERATIVES

Voici un programme C qui applique la méthode dite de Jules César sur la ligne de texte tapée :

Langage C – cesar.c

commentaire

main() {  char c;  c = getchar();  while (c != '\n') {   putchar((c + 1) % 26 + 'a');   c = getchar();

 }

 putchar(c);

}

Taper toute une ligne à l’avance, retour à la fin.

c = code ascii du caractère lu

(c+1) modulo 26 = nbre entre 0 et 25

'a' vaut 97 = code de a minuscule, on affiche ce code final et on continue avec le caractère suivant

écrire le retour à la ligne

Le traitement indiqué entre accolades est répété tant que la condition est vraie.

Voici un programme C qui compte les lettres, chiffres et autres caractères de la ligne tapée.

Langage C – compte.c

commentaire

main() {

 int lettres, chiffres, autres, c;  lettres = 0; chiffres = 0; autres = 0;  c = getchar() ;  while (c != '\n' ) {   if (  ('A'<=c && c<='Z') ||          ('a'<=c && c<='z'))   { lettres = lettres + 1;   } else if ('0'<=c && c<='9') { chiffres = chiffres + 1;   } else autres = autres + 1;   c = getchar() ;

 }

 printf("%d lettres, %d chiffres, %d autres\n",   lettres, chiffres, autres); }

définition des variables initialisations lire le 1er caractère tq pas fin de ligne si c’est une lettre

incrémenter lettres sinonsi c’est un chiffre ?

incrémenter les compteurs concernés

passer au caractère suivant fin du bloc à répéter affichage final : format valeurs

Noter que c est défini en tant qu’entier. Cela ne pose aucun problème puisqu’un entier 32 bits peut contenir un code ascii sur 8 bits, cela consomme à peine plus de mémoire et ralentit très légèrement le programme.

Ce même programme peut être rendu illisible à l’aide de pseudo-optimisations, pseudo car le gain de vitesse est complétement illusoire, l’optimiseur de code des compilateurs font un travail largement plus efficace que celui qu’on peut faire comme cela. Voici un exemple de ce qui est déconseillé :

Langage C – compte_sale.c

commentaire

main() {

 char l, c, a, x;  l = c = a = 0;

 while ((x = getchar()) != '\n')

  if (('A'<=x && x<='Z')||('a'<=x && x<='z')) ++l; else ('0'<=x && x<='9')?++c:++a;  printf("%d lettres, %d chiffres, %d autres\n",l,c,a); }

définition des variables

initialisation en une instruction lecture et test !

pas de {} pour 1 instr. test et incrémentations pas de {} car une seule instruction !

Certains programmeurs raffolent de cette syntaxe à écriture seule et c’est ce qui contribue à la réputation de difficulté du langage C. Voici quelques explications :

 une affectation peut servir de valeur pour une comparaison, ainsi (c = getchar()) a pour valeur le code ascii du caractère lu, il est comparé à la constante '\n' : code du retour à la ligne.

 ++var est à peu près identique à (var = var + 1). Ne pas l’employer dans des expressions plus complexe sous peine de ne pas pouvoir prévoir les résultats. On l’appelle opérateur de préincrémentation.

 il est inutile de mettre des {} lorsqu’il n’y a qu’une instruction. Une structure de contrôle est considérée comme une seule instruction. Un point-virgule achève l’instruction en cours.

 la structure condition ? action1 : action2 permet de spécifier de petites conditionnelles lors d’affectations.

6 - BOUCLES REPETITIVES

La boucle pour est une boucle tantque déguisée, il n’y a pas de vraie boucle pour en langage C :

Langage C – facto5.c

commentaire

main() {  int v,factoV,i;  v = 5; factoV = 1;  for (i=1 ; i<=5; i=i+1) {

  factoV = factoV * i;

 }

 printf("%d! = %d\n,v,factoV);  }

for (init ; condition ; progression) { corps ;

}

Une boucle for contient 4 éléments : initialisation, condition, progression et corps. L’exécution commence par l’initialisation. Les instructions du corps sont faites tantque la condition est vraie. C’est une condition de continuation et non une condition d’arrêt. Après avoir exécuté le corps, le langage C effectue l’affectation contenue dans progression et reprend au niveau du tantque.

Voici l’équivalence entre les deux types de boucles :

structure for

équivalence while

 for (init ; cond ; svt) {

 instructions ;

}

init ; while (cond) {  instructions ;  svt ;

}

Voici comment on fait les boucles les plus fréquentes en Pascal :

Langage C

Langage Pascal

for (i=3 ; i<=8 ; i=i+1) xxx; for (i=4 ; i>=0 ; i=i-1) yyy ;

for i := 3 to 8 do xxx ; for i := 4 downto 0 do yyy ; 

Evidemment, s’il y a plusieurs instructions dans le corps de la boucle, il faut les encadrer par des {}.

7 - FONCTIONS ET PROCEDURES

La syntaxe de définition d’une fonction est plus compacte que celle du Pascal :

Langage C – plancher.c

commentaire

int max(int a, int b)

{  if (a > b) return a;  return b;

} main() {  int i; scanf("%d",&i);  i = max(i,0);  printf("%d",i);

}

type du résultat, nom, paramètres

return provoque une sortie immédiate de la fonction donc pas besoin de else après un return

lecture d’un nombre entier

appel de la fonction max, max(v,0)=0 si v<0 affichage

Noter que les paramètres sont passés par valeur. L’instruction return provoque le retour immédiat de la valeur de la fonction. Les instructions suivantes ne sont pas effectuées.

Voici maintenant comment on définit une procédure : on met void pour indiquer qu’il n’y a pas de résultat :

Langage C

commentaire

void affiche(int nb)

{  printf("nb=%d\n", nb); }

pour une procédure on met void (vide)

pas de return ou bien return sans valeur

Voici maintenant comment on appelle cette procédure :

Langage C

commentaire

main() {  int i; scanf("%d",&i);  affiche(max(i,0));

}

on appelle la procédure

Voici maintenant quelques cas d’erreurs difficiles à déceler à cause des possibilités du langage C :

Erreurs de programmation

commentaire

c = getchar; max(i,j);

sans (), le C n’appelle pas la fonction mais affecte l’adresse du code machine on peut appeler une fonction sans utiliser son résultat

8 - TABLEAUX

Le langage C en a une approche très bas niveau, proche du langage d’assemblage. Quand on manipule un tableau en langage C, il faut constamment imaginer les opérations effectuées par l’unité centrale : des adressages indexés (voir le cours d’architecture). Un tableau C est une zone mémoire contenant plusieurs cases successives, on les manipule grâce à l’adresse de la première qui est représentée par le nom du tableau, et un indice. Pour créer un tableau, le langage C ne demande que la taille (le nombre d’éléments). On ne peut pas choisir l’étendue des indices comme en Pascal, en C les indices vont obligatoirement de 0 à la taille - 1.

Voici un exemple : int t[10] ;   crée un tableau de 10 cases, la première est t[0], la dernière est t[9] Ces cases peuvent être manipulées par des indices appliqués à t : les éléments de t sont t[0],t[1], t[2]…t[9]. Bien noter que les indices commencent obligatoirement à 0. Ils vont donc jusqu’au nombre d’éléments – 1.

Langage C – factos.c

commentaire

main() {



 int f[10],i,facti;  facti = 1;  for (i=1; i<=10; i=i+1) {   t[i-1] = facti;

  facti = facti * (i + 1);

 }

}

création d’un tableau de 10 entiers (non initialisés)

la boucle va de i=1 à i=10

on place i ! dans chaque case, noter la translation des indices pour aller de 0 à 9 dans le tableau calcul de i ! pour le i suivant

Attention, les tableaux ne peuvent pas être, comme en pascal, affectés l’un à l’autre et comparés. Il faut écrire soi-même des fonctions et des procédures pour faire ces traitements, voir page 12.

9 - CHAINES DE CARACTERES

Les chaînes sont un cas particulier de tableaux, ce sont de simples tableaux d’octets qui sont les codes ascii des caractères. Perdre de vue cette réalité ferait commettre de graves erreurs de programmation. En effet le C n’est capable ni d’affecter un tableau à un autre, ni de comparer deux tableaux, il faut obligatoirement employer des fonctions spécifiques : strcpy et strcmp.

Une chaîne est une zone mémoire d’une certaine taille (au moins aussi grande que ce qu’on veut y mettre). Cette zone mémoire contient des codes ascii : ceux des caractères de la chaîne. Le langage C oblige à mettre le code ascii zéro tout à la fin : \0. Attention le code ascii de '0' est 48 et celui de '\0' est zéro. Voici un exemple de chaîne (en réalité, au lieu des caractères, on trouve les codes ascii dans les cases) :

… 0        1        2        3        4        5        6        7        8        9       10      11      12      13      14      15      16      17      18    19          …

 D e m e s m a e k e r \0 A r s è n e \0 L  

Cette zone mémoire contient 20 emplacements, on y a placé un texte « Demesmaeker » puis le code ascii nul (noté aussi \0) ; les cases suivantes contiennent du texte qui n’est pas pris en compte et qui résulte probablement d’opérations précédentes sur cette chaîne.

Ne pas oublier que le tableau fait partie de la mémoire, il y a d’autres octets avant et d’autres octets après la zone mémoire attribuée à cette chaîne. Si on affecte les cases trop loin (indice > 19), on risque de modifier d’autres données, d’autres variables situées au delà.

a)  Constantes chaînes

La syntaxe "texte" crée un tableau sans nom (ce n’est pas une variable affectable), contenant les codes ascii des caractères indiqué suivis d’un code nul. Ainsi "bonjour" réserve 8 octets en mémoire.

Attention, selon les options de compilation et les compilateurs, deux chaînes constantes contenant la même chose oeuvent être placées à des adresses différentes ou pas. Elles seront donc considérées comme différentes ou pas selon le compilateur. Pour comparer deux chaînes par leur contenu, il faut obligatoirement utiliser la fonction strcmp ci-dessous.

b)  Variables chaînes

Les constantes chaînes ne peuvent pas être modifiées car elles n’ont pas de nom symbolique. Au contraire, avec les variables chaînes, on peut modifier le contenu : affecter, concaténer, tronquer, comparer… Voici un exemple de création d’une chaîne :

char nom[21] ; réserve 20 octets pour stocker des codes ascii, càd des caractères. Il faut en prévoir un de plus pour mettre le code nul.

Langage C – chaine.c

commentaire

main() {

 char nom[31],prenom[21],mail[61]; printf("ton prénom :"); gets(prenom);  if (strcmp(nom,"pierre") == 0)   printf("ah, salut pierrot !\n");  printf("ton nom :"); gets(nom);  strcpy(mail,nom); strcat(mail,".");  strcat(mail,prenom); strcat(mail,"");  puts(mail);

}

réserve des chaines de 30, 20 et 60 caractères (1 de plus pour le \0) comparaison de chaines

mail := nom mail := mail + ‘.’ mail := mail + prenom mail := mail + ‘’ afficher la chaîne mail

La procédure strcpy(dst,src) copie dans la chaîne dest ce qui se trouve dans la chaîne src.

La procédure strcat(dst,src) ajoute au bout de la chaîne dest ce qui se trouve dans la chaîne src.

La fonction strcmp(ch1,ch2) compare les contenus des deux chaînes et renvoie 0 si elle contiennent la même chose. strcmp renvoie un nombre non nul si elles ne contiennent pas la même chose.

La fonction strlen(ch) calcule la longueur de la chaîne, attention distinguer la longueur de la chaîne (quantité de mémoire utilisée, variable) de sa taille (quantité de mémoire allouée, constante). Ainsi la chaîne nom du haut peut contenir jusqu’à 20 caractères utiles mais occupe toujours 21 octets en mémoire.

Voici maintenant quelques exemples techniques :

Langage C

équivalence

char txt[5]; txt[0] = 'j'; txt[1] = 'e'; txt[2] = '\0';

char txt[5]; strcpy(txt, "je");

Les affectations de chaînes sont impossibles directement car le C ne sait pas recopier des tableaux, attention à réserver assez de place dans la chaîne destination, sans quoi on écrase la suite de la mémoire :

Impossible/interdit

correct

char txt1[5], txt2[5]; txt1 = "oui"; txt2 = txt1;

char txt1[5], txt2[5]; strcpy(txt1, "oui"); strcpy(txt2, txt1);

De la même façon, le C ne sait pas comparer des tableaux, donc :

Faux ami, mauvais résultat

correct

char txt1[5], txt2[5]; if (txt1 == txt2) ... if (txt1 == "tu") ...

char txt1[5], txt2[5]; if (strcmp(txt1,txt2) == 0) ... if (strcmp(txt1,"tu") == 0) ...

Il existe des procédures/fonctions d’entrées/sorties pour les chaînes :

Langage C

Langage Pascal

char texte[80]; gets(texte); puts(texte);

var texte : string(80); read(texte); writeln(texte);

La fonction gets remplit le tableau avec ce qu’on tape au clavier jusqu’à la fin de ligne et place le code de fin de chaîne à la fin (‘\0’). La fonction puts écrit la chaîne à l’écran.

Langage C

Langage Pascal

char texte[80]; scanf("%s",mot); printf("%s",mot);

var mot : string(80); read(mot); writeln(mot);

La fonction scanf remplit le tableau avec le premier mot lu sur le clavier et place le code de fin de chaîne à la fin (‘\0’). Le joker %s écrit la chaîne à l’écran.

10 - TYPES COMPOSITES : STRUCTURES

Langage C – infos.c

commentaire

struct client {  char nom[20];  int age; }; 

void afficher(struct client  untel)

{

 printf("%s, %d ans\n",     ,);

}  main() {  struct client  cahier[5];  strcpy(cahier[0].nom, "Michel") ; cahier[0].age = 25;  afficher(cahier[0]);

}

définition d’un type structuré, la syntaxe est très différente de celle du Pascal

définition d’une procédure d’affichage avec une strcture en paramètre, remarquer le mot clé struct présent à chaque fois

définition d’une variable tableau de 5 structures affectation des champs de la première case

appel de la fonction d’affichage

Noter que de cette façon le type ne s’appelle pas client seulement mais struct client. L’utilisation de ce type est identique à Pascal.

11 - VARIABLES GLOBALES

Langage C

commentaire

float TVA = 19.6;

float prixttc(float prixht)

{  return prixht * TVA;

}

variable globale préinitialisée

TVA est prise en dehors de la fonction

Il s’agit de variables situées hors de toute fonction. On peut y accéder partout dans le programme. Lorsqu’une variable locale porte le même nom, c’est cette dernière qui est prise en compte.

12 - POINTEURS

Le langage C est très proche de la machine et n’offre pas des mécanismes très élaborés pour manipuler certaines structures de données dynamiques (tableaux dynamiques, listes, arbres, graphes). Pour les représenter en C, il faut manipuler directement les adresses des données et faire des indirections sur ces adresses (adressage indirect registre). En C, on appelle pointeur une variable qui contient une adresse.

Langage C

commentaire

int a,b,c;

 main() {  int *adr;  adr = &b;  (*adr) = 50; }

définition de trois variables globales

adr : adresse d’une variable de type int adr = adresse de la variable b

mettre 50 dans la case mémoire désignée par adr, càd b

L’opérateur & donne l’adresse de son opérande : &a est l’adresse de a, &c est l’adresse de c.

L’opérateur * donne la valeur située à l’adresse indiquée par l’opérande : *15 donne le contenu de la case mémoire d’adresse 15. Attention, on ne doit donner que des adresses valides (situées dans le segment de données du programme et correspondant à des variables).

a)  Paramètres de sortie

On se sert de ce mécanisme pour passer des paramètres de sortie :

Langage C – echange.c

commentaire

void echanger(int *adrv1, int *adrv2)

{ int inter;  inter = (*adrv1);  (*adrv1) = (*adrv2);

 (*adrv2) = inter;

} main() {

 int a=14, b=23;  printf("avant: a=%d b=%d\n",a,b);  echanger(&a, &b);  printf("apres: a=%d b=%d\n",a,b); }

adrv1 et adrv2 sont deux adresses de variables int

adrv1 = adresse d’un entier

*adrv1 = cet entier

&a = adresse de a placée dans adrv1

&b = adresse de b placée dans adrv2

b)  Pointeurs et tableaux

Le langage C entretient une relation très forte entre pointeurs et tableaux. Le nom d’un tableau est un pointeur non affectable sur son premier élément, d’indice 0. Ainsi &(tab[0]) = tab et (*tab)= tab[0]. D’autre part, on peut additionner une constante à un pointeur pour désigner une des cases suivantes (adressage basé avec un décalage). Ainsi tab+i = &tab[i] et (*(tab+i)) = tab[i].

Langage C

commentaire

main() {  int tab[4];  (*(tab+2)) = 4; echange(tab+1,&tab[3]); }

tableau de quatre entiers, tab = adresse du 1er élément tab+2 = adresse du 3e entier (*(tab+2)) = tab[2] tab+1 = &tab[1]

En Pascal, le nom d’un tableau représente toutes ses cases tandis qu’en C, le nom d’un tableau représente uniquement l’adresse du début du tableau. C’est pour cela qu’en C on ne peut pas affecter des tableaux l’un à l’autre et que les tableaux sont toujours passés par variable.

Lorsqu’on passe un tableau en paramètre, on passe uniquement l’adresse de ce tableau, cette adresse permet d’accéder au contenu.

Langage C – zeros.c

commentaire

int nbnuls(int *tab, int taille)

{

 int i, n=0;

 for (i=0 ; i<taille ; i=i+1)   if (tab[i] == 0) n=n+1; return n;

} main() {  int tab[4] = { 2,0,8,0 };

 printf("nuls=%d\n",nbnuls(tab,4)); }

le paramètre tab est un pointeur, adresse de la première case d’un tableau

aucune différence d’emploi car tab[i] = (*(tab+i))

tableau de quatre entiers initialisés appel de la fonction adresse de tab et taille

Les chaines sont également manipulées de cette façon :

Langage C – zeros.c

commentaire

int longueurphrase(char *chaine)

{ int i;

 for (i=0 ; chaine[i] !='\0'; i=i+1)   if (chaine[i] == '.') return i;  return i;

} main() {

 char texte[80] = "."; printf("lngphrase(%s)=%d\n",   texte,longueurphrase(texte)); }

le paramètre sera un tableau de caractères

boucle tant qu’on reste dans la chaîne arrêt immédiat quand on trouve un point on renvoie son indice

texte[0]=’N’…texte[3]=’v’…texte[6]=’l’…texte[14]=’\ 0’



En C on ne peut pas affecter un tableau à un autre : il faut clairement indiquer si on souhaite affecter les adresses ou si on souhaite affecter le contenu :

affectation des adresses

affectation du contenu

int tab1[5] = { 1, 4, 2, 6, 7 }; int *tab2;

 {

 tab2 = tab1;

}

int tab1[5] = { 1, 4, 2, 6, 7 }; int tab2[5];

{  int i;

 for (i=0 ; i<5 ; i++)   tab2[i] = tab1[i];

}

Les deux programmes créent tab1, tableau de 5 entiers et font en sorte que tab2 contiennent les mêmes valeurs que tab1. La différence est que dans le programme de gauche tab2 est à la même adresse que tab1, si on modifie tab2[3], on modifie aussi tab1[3], tandis que à droite, tab2 est un autre tableau dont les valeurs ont été initialisées avec celles de tab1, si on modifie tab2[3], cela ne change rien à tab1[3].

Bien noter qu’on peut affecter une valeur à un pointeur (comme tab2 à gauche) mais qu’on ne peut pas affecter un tableau (tab1 est en lecture seule). D’autre part, il faut veiller à réserver assez de place dans le tableau destination.

Les mêmes considérations s’appliquent aux chaînes de caractères. La fonction strcpy effectue la recopie des octets d’une chaîne à l’autre.


C - STRUCTURE D’UN PROGRAMME C

1 - ÉLEMENTS D'UN PROGRAMME

Un programme C est composé des éléments suivants : définitions des constantes, types, variables globales, procédures et fonctions et corps principal. Ces éléments sont disposés en vrac (sans structuration), la seule contrainte est qu’un élément doit être défini ou déclaré avant son utilisation : ce qui est défini ou déclaré à un endroit devient disponible pour la suite du programme.

Vocabulaire : définir = créer (réserver la place en mémoire à l'exécution) ; déclarer = prévenir le compilateur que la définition est faite plus loin. Voir aussi le paragraphe G - 4 - a) page 39.

Dans la plupart des cas, certaines définitions de constantes et types et déclarations de variables et de fonctions sont placées dans des fichiers inclus au programme. Ces fichiers portent l'extension .h.

•    Commentaires

Un commentaire doit être encadré par /*... */. Il n'y a pas de limite à la longueur d'un commentaire. Un commentaire ne peut pas en contenir d'autres.

Langage C

Langage Pascal

/* ceci est un commentaire */

/* il n'y a qu'une possibilité */

(* ceci est un commentaire *)

{ il y a deux possibilités }

•    Fichiers inclus et librairies

Lorsque le programme fait appel à des fonctions extérieures (par exemple, les fonctions mathématiques ou les fonctions système Unix), il est souvent nécessaire d'inclure des déclarations de constantes, types et prototypes de fonctions qui se trouvent dans certains fichiers appelés fichiers d’entêtes de librairies. Ces fichiers sont regroupés dans le répertoire /usr/include et sont inclus par la directive  #include <fichier.h>. Voir aussi le §H - 1 - page 41.

Langage C

#include <stdio.h>

Lorsque le fichier à inclure se trouve dans le répertoire courant, des "" remplacent les <> :

Langage C

#include "donnees.h"

•    Définition des constantes

Une constante est un identificateur simple pour représenter une valeur numérique compliquée. Syntaxe : #define constante valeur définit la valeur du symbole constante

Langage C

Langage Pascal

#define PI 3.1415

const PI = 3.1415;

Pièges : ne pas mettre de ; après la valeur. Cela provoque une erreur de syntaxe à toutes les mentions de la constante.

Conseil : en général, les constantes sont mises en majuscules afin de les localiser facilement.

#define permet également de définir des macro-fonctions. Il s'agit de pseudo-fonctions dont la définition remplace chaque appel. Il faut donc faire attention à ne pas les employer à mauvais escient. Voir page 43.

Langage C

#define dernierchar(S) (S[strlen(S)-1])

Cette macro donne le dernier caractère d'une chaîne non-vide.

•    Définition des types

Voir le paragraphe D - 2 - page 16.

•    Définition des variables globales

Une variable globale est définie de la même manière qu'une variable locale dans une fonction ou procédure. Se reporter au paragraphe D - 1 - page 16.

•    Déclaration des fonctions et procédures

Dans certains cas, il faut indiquer au compilateur quels sont les types des paramètres et le type du résultat d'une fonction sans pouvoir fournir en même temps le corps de cette fonction (récursivité croisée, modularité ou simple confort du programmeur). Cela s'appelle une déclaration de prototypes et consiste à fournir l'entête d'une fonction sans son corps. Voir le paragraphe G - 1 - c)   page 33.

•    Définition des fonctions et procédures

Voir le paragraphe G - 1 - page 32.

•    Définition du point d'entrée : le corps du programme

Dans le langage C, le point d'entrée est défini simplement à l'aide d'une procédure particulière qui s'appelle main. Le programmeur doit définir cette procédure qui sera automatiquement appelée lors de l'exécution.

2 - COMPILATION D'UN PROGRAMME C

Comme en Pascal, le but est d'obtenir un programme exécutable à partir du ou des programmes source. La construction de l'exécutable se déroule en deux étapes : compilation des fichiers sources et édition des liens. a)  Compilation

Cela consiste à traduire les instructions et définitions de données en langage machine. Le compilateur consulte le source .c et tous les fichiers .h qu'il mentionne. Il construit un fichier dit objet .o.

Il existe également des fichiers .a dits librairies construits à partir des .o. Ces fichiers contiennent les corps des fonctions tandis que les fichiers .h contiennent les déclarations des fonctions.

Commande : cc –Wall -c prog.c

L’option –Wall affiche tous les messages d’avertissement. La présence d’avertissements est mauvais signe mais leur absence ne signifie pas pour autant que le programme est sain.

b)  Édition des liens

Cela consiste à rassembler tous les fichiers .o et les librairies de fonction en associant les appels de fonctions aux définitions. Voir le cours de production/maintenance.

Commande : cc prog.o -o prog

compile le source prog.c et crée l'exécutable prog.

Dans le cas d'un programme simple, les deux étapes peuvent être rassemblées :

Commande : cc -Wall prog.c -o prog

D - VARIABLES ET TYPES DE DONNEES

1 - DEFINITION D'UNE VARIABLE

a)  Syntaxe

Syntaxe1 :         type variable;

Syntaxe2 :         type variable1, variable2, ...;

définit la ou les variables : réserve la place pour une variable de ce type, la variable devient connue et utilisable dans la suite du programme si c'est une variable globale (c'est à dire définie en dehors d'une fonction) ou seulement dans le bloc d'instructions d'une fonction si c'est une variable locale (voir F - 2 - page 28). Les identificateurs autorisés sont les mêmes qu'en Pascal : lettre puis suite de lettres ou de chiffres. b) Initialisation

Cela consiste à placer des valeurs dans les variables avant l'exécution du programme, au moment de leur définition. La ligne suivante définit la variable ainsi que sa valeur initiale.

Syntaxe :          type variable = valeurinitiale;

2 - TYPES SIMPLES

a)  Entiers

Le C offre plusieurs sortes d'entiers afin de s'adapter à toutes sortes de machines (micro-processeurs 8-16 bits ou 16-64 bits). Il existe donc des entiers courts, normaux ou longs qui sont mémorisés sur un nombre d'octets différents. Par exemple, en 2003 sur un PC linux, un entier court occupe 2 octets (16 bits), les normaux et les longs en occupent 4 (32 bits).

D'autre part, pour une même taille, il existe des entiers signés et des entiers non-signés. Cela change les valeurs entières minimum et maximum qui peuvent être représentées. Voici les différents types entiers :

signé

non-signé

entier court

short

unsigned short

entier normal

int

unsigned int

entier long

long

unsigned long

Exemple :

Langage C

Langage Pascal

unsigned long nbatomes; short variation; int code;

var nbatomes: integer; var variation: integer; var code: integer;

Les constantes entières peuvent être données dans différentes bases :

base

syntaxe

exemple

valeur en base 10

10

comme en Pascal

45

45

8

faire précéder d'un 0

067

55

16

faire précéder de 0x

0x3E

62

Les entiers longs sont suffixés d'un L. Exemple : 125L est l'entier long qui vaut 125.

Langage C

Langage Pascal

nbatomes = 1868376613L; code = 0xFFE;

nbatomes := 1868376613; code := 4094;

b)  Booléens

Il n'existe pas de type spécialisé pour gérer les booléens. Ils ont été intégrés à la syntaxe du langage C en tant qu'entiers avec la convention suivante :

                                                                                     0 : faux,                         0 : vrai.

Tous les opérateurs booléens (voir E - 2 - page 23) respectent cette convention.

Langage C

Langage Pascal

int f; f = 1



1116