Cours C
Cours C
Introduction
Introduction
• Généralités sur le langage C (Historique)
• C est un langage de programmation impératif généraliste, de bas niveau. Le langage C a été créé en 1972 par Denis
Ritchie avec un objectif relativement limité : écrire un système d’exploitation (UNIX). Mais ses qualités opérationnelles
l’ont très vite fait adopter par une large communauté de programmeurs.
• Il fut limité à l’usage interne de Bell jusqu’en 1978, date à laquelle Brian Kernighan et Denis Ritchie publièrent les
spécifications définitives du langage : The C programming Language.
• Mais ce langage a continué d’évoluer après cette date à travers les différents compilateurs qui ont vu le jour. Son succès
international a contribué à sa normalisation, d’abord par l’ANSI (American National Standard Institute), puis par l’ISO
(International Standards Organization), plus récemment en 1993 par le CEN (Comité européen de normalisation) et enfin,
en 1994, par l’AFNOR. En fait, et fort heureusement, toutes ces normes sont identiques, et l’usage veut qu’on parle de « C
ANSI » ou de « C norme ANSI ».
• L’ISO a publié en 1999, sous la référence ISO/IEC 9899:1999, une extension de la norme du langage C, plus connue sous
l’acronyme C99. Bien qu’ancienne, celle-ci est loin d’être implémentée dans sa totalité par tous les compilateurs.
Introduction
• Généralités sur le langage C (Intérêt)
• Trop permissif
Programmation spaghetti et autres …
Warning interdit
• Programme difficile à maintenir si
La programmation est trop compacte
Les commentaires sont insuffisants
• Portabilité
Dès que l’on utilise des bibliothèques externes, la portabilité devient difficile.
Introduction
• Exemple de programme en langage C
Introduction
• Structure d'un programme en langage C
Introduction
• Structure d'un programme en langage C
• La ligne :
main()
se nomme un « en-tête ». Elle précise que ce qui sera décrit à sa suite est en fait le programme principal (main). Le
programme (principal) proprement dit vient à la suite de cet en-tête. Il est délimité par les accolades «{»et «}». On dit que les
instructions situées entre ces accolades forment un « bloc ».
• Les trois instructions :
int i ;
float x ;
float racx ;
sont des « déclarations ». La première précise que la variable nommée i est de type int , c’est-à-dire qu’elle est destinée à
contenir des nombres entiers (relatifs). Les deux autres déclarations précisent que les variables x et racx sont de type float,
c’est à dire qu’elles sont destinées à contenir des nombres flottants (approximation de nombres réels).
Remarque: en C, comme dans la plupart des langages actuels, les déclarations des types des variables sont obligatoires et
doivent être regroupées au début du programme (on devrait plutôt dire: au début de la fonction main). Cependant, suivant
la norme C99, une déclaration peut figurer à n’importe quel emplacement, pour peu qu’elle apparaisse avant que la variable
correspondante ne soit utilisée.
Introduction
• Structure d'un programme en langage C
• L’instruction :
printf ("Bonjour\n") ;
appelle en fait une fonction prédéfinie (fournie avec le langage, et donc que vous n’avez pas à écrire vous-même) nommée
printf. Ici, cette fonction reçoit un argument qui est : « Bonjour\n » Les guillemets servent à délimiter une « chaîne de
caractères » (suite de caractères). La notation \n est conventionnelle : elle représente un caractère de fin de ligne
• L’instruction suivante :
printf ("Je vais vous calculer %d racines carrées\n", NFOIS) ;
ressemble à la précédente avec cette différence qu’ici la fonction printf reçoit deux arguments.
Ici, on demande à printf d’afficher suivant ce format :
"Je vais vous calculer %d racines carrées\n" la valeur de NFOIS , c’est-à-dire, la valeur 5. Ce format est, comme
précédemment, une chaîne de caractères. Toutefois, vous constatez la présence d’un caractère %. Celui-ci signifie que le
caractère suivant est, non plus du texte à afficher tel quel, mais un « code de format ». Ce dernier précise qu’il faut
considérer la valeur reçue (en argument suivant, donc ici 5) comme un entier et l’afficher en décimal.
Introduction
• Structure d'un programme en langage C
• L’instruction :
for (i=0 ; i<NFOIS ; i++)
Son rôle est de répéter le bloc (délimité par des accolades «{» et «}») figurant à sa suite, en respectant les consignes
suivantes:
• avant de commencer cette répétition, réaliser : i = 0
• avant chaque nouvelle exécution du bloc (tour de boucle), examiner la condition : i < NFOIS si elle est satisfaite, exécuter
le bloc indiqué entre les accolades «{» et «}»), sinon passer à l’instruction qui se trouve après le bloc for (i.e. après
l’accolade } ).
• à la fin de chaque exécution du bloc, réaliser : i++ : il s’agit là d’une notation propre au langage C qui est équivalente à : i =
i+1
En définitive, vous voyez qu’ici notre bloc sera répété cinq fois.
Introduction
• Structure d'un programme en langage C
• La première instruction du bloc répété par l’instruction for affiche simplement le message Donnez un nombre:.
Notez qu’ici nous n’avons pas prévu de changement de ligne à la fin.
• La seconde instruction du bloc :
scanf ("%f", &x) ;
est un appel de la fonction prédéfinie scanf dont le rôle est de lire une information au clavier. Comme printf, la fonction scanf
possède en premier argument un format exprimé sous forme d’une chaîne de caractères, ici : "%f" ce qui correspond à une
valeur flottante.
les arguments suivants (ici, il n’y en a qu’un &x) précisent dans quelles variables on souhaite placer les valeurs lues.
Introduction
• Structure d'un programme en langage C
• Les lignes :
if (x < 0.0)
printf ("Le nombre %f ne possède pas de racine carrée\n", x) ;
else{
racx = sqrt (x) ;
printf ("Le nombre %f a pour racine carrée : %f\n", x, racx) ;
}
constituent une instruction de choix basée sur la condition x < 0.0. Si cette condition est vraie, on exécute l’instruction
suivante, c’est-à-dire : printf ("Le nombre %f ne possède pas de racine carrée\n", x) ; Si elle est
fausse, on exécute l’instruction suivant le mot else, c’est-à-dire, ici, le bloc :
{ racx = sqrt (x) ;
printf ("Le nombre %f a pour racine carrée : %f\n", x, racx) ;
}
La fonction sqrt fournit la valeur de la racine carrée d’une valeur flottante qu’on lui transmet en argument.
Introduction
• Structure d'un programme en langage C
• le caractère souligné (_) est considéré comme une lettre. Il peut donc apparaître au début d'un
identificateur. Voici quelques identificateurs corrects :
lg_lig valeur_5 _total _89
• les majuscules et les minuscules sont autorisées mais ne sont pas équivalentes. Ainsi, en C, les
identificateurs ligne et Ligne désignent deux objets différents.
Introduction
• Quelques règles d'écriture
Les identificateurs
Voici la liste, classée par ordre alphabétique des « mots-clés » réservés par le langage.
Introduction
• Quelques règles d'écriture
Les identificateurs
Lesquels des identificateurs suivants sont acceptés ?
• _ • a • for • Fin_A • 3
Introduction
• Quelques règles d'écriture
Les séparateurs
Dans un programme, deux identificateurs successifs entre lesquels la syntaxe n'impose aucun signe particulier
(tel que :,=;*() [ ] { ) ) doivent impérativement être séparés soit par un espace, soit par une fin de ligne. En
revanche, dès que la syntaxe impose un séparateur quelconque, il n'est alors pas nécessaire de prévoir
d'espaces supplémentaires (bien qu'en pratique cela améliore la lisibilité du programme).
À titre d'exemple, voyez comment pourrait être (mal) présenté notre programme précédent :
Introduction
• Quelques règles d'écriture
Les commentaires
Comme tout langage évolué, le langage C autorise la présence de commentaires dans vos programmes source.
Il s'agit de textes explicatifs destinés aux lecteurs du programme et qui n'ont aucune incidence sur sa
compilation.
Ils sont formés de caractères quelconques placés entre les symboles /* et */. Ils peuvent apparaître à tout
endroit du programme où un espace est autorisé. En général, cependant, on se limitera à des emplacements
propices à une bonne lisibilité du programme.
Voici quelques exemples de commentaires :
/* programme de calcul de racines carrées */
/* commentaire fantaisiste &ç§{<>} ?%!!!!!! */
/* commentaire s'étendant sur plusieurs lignes
de programme source */
/* ============================================
* commentaire quelque peu esthétique *
* et encadré, pouvant servir, *
* par exemple, d'en-tête de programme *
============================================ */
Introduction
• Création d'un programme en langage C
L'édition du programme
L'édition du programme (on dit aussi parfois « saisie ») consiste à créer, à partir d'un clavier, tout ou partie du
texte d'un programme qu'on nomme « programme source ». En général, ce texte sera conservé dans un fichier
que l'on nommera « fichier source ». Chaque système possède ses propres conventions de dénomination des
fichiers. En général, un fichier peut, en plus de son nom, être caractérisé par un groupe de caractères (au
moins 3) qu'on appelle une « extension » (ou, parfois un « type ») ; la plupart du temps, en langage C, les
fichiers source porteront l'extension C.
Introduction
• Création d'un programme en langage C
La compilation
Elle consiste à traduire le programme source (ou le contenu d'un fichier source) en langage machine, en faisant
appel à un programme nommé compilateur. En langage C, compte tenu de l'existence d'un préprocesseur, cette
opération de compilation comporte en fait deux étapes :
• traitement par le préprocesseur : ce dernier exécute simplement les directives qui le concernent (il les
reconnaît au fait qu'elles commencent par un caractère #). Il produit, en résultat, un programme source en
langage C pur.
• compilation proprement dite, c'est-à-dire traduction en langage machine du texte en langage C fourni par
le préprocesseur.
Introduction
• Création d'un programme en langage C
L'édition de liens
• Le module objet créé par le compilateur n'est pas directement exécutable. Il lui manque, au moins, les
différents modules objet correspondant aux fonctions prédéfinies (on dit aussi « fonctions standard »)
utilisées par votre programme (comme printf, scanf, sqrt).
• C'est effectivement le rôle de l'éditeur de liens que d'aller rechercher dans la bibliothèque standard les
modules objet nécessaires.
• Le résultat de l'édition de liens est ce que l'on nomme un programme exécutable, c'est-à-dire un ensemble
autonome d'instructions en langage machine.
Introduction
• Création d'un programme en langage C
Outils
Maintenant que les présentations sont faites, il est temps de découvrir les outils nécessaires pour programmer
en C. Le strict minimum pour programmer se résume en trois points.
• Un éditeur de texte : ce logiciel va servir à écrire le code source. En théorie, n’importe quel éditeur de texte
suffit, mais le mieux est d’en avoir un qui colore le code source, ce qui permet une relecture plus agréable.
• Un compilateur : c’est le logiciel le plus important puisqu’il va nous permettre de transformer le code que
l’on écrit en un fichier exécutable compréhensible par le processeur.
• Un débugger / débogueur : fondamentalement, il n’est pas indispensable, mais ce logiciel est très utile pour
chasser les bugs et vérifier le comportement de son programme.
Introduction
• Création d'un programme en langage C
Outils
À partir de là, il existe deux moyens de récupérer tous ces logiciels : soit on les prend séparément, et dans ce cas il faut
compiler par soi-même, soit on utilise un logiciel qui réunit les trois : un IDE (« Environnement de Développement Intégré »
en français).
Compilateurs
• GNU Compiler Collection, abrégé en GCC, est un ensemble de compilateurs libre capable de compiler divers langages de
programmation, dont C, C++, Objective-C, Java, …
• Borland C++ Compiler est une version gratuite du compilateur C & C++ inclus dans C++ Builder.
• MinGW ou Mingw32 (Minimalist GNU for Windows) est une adaptation des logiciels de développement et de compilation
du GNU (GCC - GNU Compiler Collection), à la plate-forme Win32.
Introduction
• Création d'un programme en langage C
Remarques
Il existe deux types de programmes:
• les programmes avec fenêtres ;
• les programmes en console.
Types de base
Types de base
• La notion de type
Remarque
Les types char, int et float que nous avons déjà rencontrés sont souvent dits scalaires ou simples, car, à un
instant donné, une variable d'un tel type contient une seule valeur. Ils s'opposent aux types structurés qui
correspondent à des variables qui, à un instant donné, contiennent plusieurs valeurs (de même type ou non)
comme les tableaux, les structures, les unions etc.
Dans ce chapitre , nous étudierons en détail ce que l'on appelle les types de base du langage C ; il s'agit des
types scalaires à partir desquels pourront être construits tous les autres types.
Types de base
• La notion de type
La mémoire centrale est un ensemble de positions binaires nommées bits. Ils sont regroupés en octets (8 bits),
et chaque octet est repéré par ce qu'on nomme son adresse. L'ordinateur ne sait représenter et traiter que des
informations exprimées sous forme binaire. Toute information, quelle que soit sa nature, devra être codée sous
cette forme. Dans ces conditions, on voit qu'il ne suffit pas de connaître le contenu d'un emplacement de la
mémoire (d'un ou de plusieurs octets) pour être en mesure de lui attribuer une signification.
Par exemple, si vous savez qu'un octet contient le « motif binaire » suivant : 01001101
D'une manière générale, la notion de type, telle qu'elle existe dans les langages évolués, sert à régler (entre
autres choses) les problèmes que nous venons d'évoquer.
Les types de base du langage C se répartissent en trois grandes catégories en fonction de la nature des
informations qu'ils permettent de représenter :
• nombres entiers (mot-clé int),
• nombres flottants (mot-clé float ou double),
• caractères (mot-clé char) ; nous verrons qu'en fait char apparaît (en C) comme un cas particulier de int.
Types de base
• Les types entiers
• Le mot-clé int correspond à la représentation de nombres entiers relatifs. Pour ce faire : un bit est réservé
pour représenter le signe du nombre, les autres bits servent à représenter la valeur absolue du nombre (en
toute rigueur, on la représente sous la forme de ce que l'on nomme le « complément à deux ».
• Chaque type entier a une forme « signée » pouvant représenter des nombres négatifs et positifs, et une
forme « non signée » ne pouvant représenter que des nombre naturels. Les formes signées et non signées
doivent avoir la même taille.
• Contrairement à de nombreux autres langages, le type char est un type entier comme un autre, bien qu'il
soit généralement utilisé pour représenter les caractères. Sa taille est par définition d'un byte.
Types de base
• Les types entiers
• Le C prévoit que, sur une machine donnée, on puisse trouver jusqu'à trois tailles différentes d'entiers,
désignées par les mots-clés suivants:
short int (qu'on peut abréger en short),
int (c'est celui que nous avons rencontré dans le chapitre précédent),
long int (qu'on peut abréger en long).
• Chaque taille impose naturellement ses limites. Toutefois, ces dernières dépendent, non seulement du mot-
clé considéré, mais également de la machine utilisée.
• Chacun des trois types (short, int et long) peut être nuancé par l'utilisation du qualificatif unsigned (non
signé). (Dans ce cas, il n'y a plus de bit réservé au signe et on ne représente plus que des nombres positifs).
• La norme C99 introduit le type long long, ainsi que des types permettant de choisir :
soit la taille correspondante, par exemple int16 pour des entiers codés sur 16 bits ou int32 pour des
entiers codés sur 32 bits ;
soit une taille minimale, par exemple int_least32_t pour un entier d'au moins 32 bits.
Types de base
• Les types entiers
Types de base
• Les types flottants
• Les types flottants permettent de représenter, de manière approchée, une partie des nombres réels. Plus
précisément, un nombre réel sera représenté en flottant en déterminant deux quantités M (mantisse) et E
(exposant) telles que la valeur 𝑀. 𝐵𝐸 représente une approximation de ce nombre.
• Le C prévoit trois types de flottants correspondant à des tailles différentes : float, double et long double.
• Comme dans la plupart des langages, les constantes flottantes peuvent s'écrire indifféremment suivant l'une
des deux notations :
• Décimale
• Exponentielle
• La notation exponentielle utilise la lettre e (ou E) pour introduire un exposant entier (puissance de 10), avec
ou sans signe. La mantisse peut être n'importe quel nombre décimal ou entier (le point peut être absent
dès que l'on utilise un exposant).
Types de base
• Les types caractères
• Contrairement à de nombreux autres langages, le type char est un type entier comme un autre, bien qu'il
soit généralement utilisé pour représenter les caractères. Sa taille est par définition d'un byte.
• la notion de caractère en C dépasse celle de caractère imprimable, c'est-à-dire auquel est obligatoirement
associé un graphisme (et qu'on peut donc imprimer ou afficher sur un écran). C'est ainsi qu'il existe certains
caractères de changement de ligne, de tabulation, d'activation d'une alarme sonore (cloche),... Nous avons
d'ailleurs déjà utilisé le premier (sous la forme \n). C’est ce qu’on appel « caractères de contrôle ».
• Les constantes de type « caractère », lorsqu'elles correspondent à des caractères imprimables, se notent de
façon classique, en écrivant entre apostrophes (ou quotes) le caractère voulu, comme dans ces exemples :
Types de base
• Les types caractères
Certains caractères non imprimables possèdent une représentation conventionnelle utilisant le caractère « \ ».
Voici la liste de ces caractères.
Types de base
• Initialisation et constantes
• La directive #define permettait de donner une valeur à un symbole. Dans ce cas, le préprocesseur
effectue le remplacement correspondant avant la compilation.
• Il est possible de déclarer que la valeur d'une variable ne doit pas changer lors de l'exécution du
programme. Par exemple, avec :
const int n = 20 ;
Types de base
• Autres types introduits par la norme C99
Outre les nouveaux types entiers dont nous avons parlé, la norme C99 introduit :
• Le type booléen, sous le nom bool ; une variable de ce type ne peut prendre que l'une des deux valeurs ;
vrai (noté true) et faux (noté false) ;
• Des types complexes, sous les noms float complex, double complex et long double
complex ; la constante I correspond alors à la constante mathématique i (racine de -1).
Chapitre III
Exemple:
• ++i est une expression qui réalise une action: incrémenter la valeur de i. Elle aura comme valeur, la valeur
de i après incrémentation.
• i = 7 est une expression de valeur 7 qui réalise une action : affecter à i la valeur 7.
• k = (i = 7) La valeur de l’expression ( i = 7) est affectée á la valeur de k.
Les opérateurs et les expressions
• Les opérateurs arithmétiques en C
Opérateurs arithmétiques binaires
+
addition
-
soustraction
/
division
*
multiplication
%
reste de la division entière (modulo)
• Les opérateurs binaires ne sont définis que sur deux opérandes ayant le même type : ( int, long int, float,
double, long double ). Ils fournissent le même type que leurs opérandes.
• L` opérateur modulo ( % ) ne peut porter que sur des entiers.
Les opérateurs et les expressions
• Les opérateurs arithmétiques en C
Opérateur arithmétique unaire
Un opérateur « unaire » (c'est-à-dire ne portant que sur un seul opérande) correspond à l'opposé noté -
(comme dans -n ou dans -x+y).
Exemples :
Étant données a et b des variables de type entier de valeurs respectives 10 et 3, v1 et v2 deux variables de type flottant et
dont les valeurs respectives sont 12.5 et 2.0, et c1 et c2 de type caractère représentant respectivement les caractères ‘P’ et
‘T’.
Une expression mixte est une expression, dans laquelle interviennent des opérandes de types différents.
Dans une expression mixte, le compilateur met en place des instructions de conversion de la valeur d’un
opérande pour obtenir une expression dont tous les opérandes ont le même type. Le résultat de la conversion
sera exprimé dans le type de plus haute précision.
On peut convertir directement un int en double ; en revanche, on ne pourra pas convertir un double en float ou en int. Par
exemple, si n est de type int, p de type long et x de type float, l'expression :
n * p + x
sera évaluée suivant ce schéma :
Les opérateurs et les expressions
• Les conversions implicites
Les promotions numériques
Les opérateurs arithmétiques ne sont pas définis pour le type short et char. Le langage C prévoit que toute valeur de l’un de
ces types apparaissant dans une expression, est d’abord convertie en int. On parle alors de promotion numérique.
Par exemple, si pl, p2 et p3 sont de type short et x de type float, l'expression :
pl * p2 + p3 * x
est évaluée comme l'indique le schéma ci-après :
Les opérateurs et les expressions
• Les conversions implicites
Les promotions numériques
La promotion numérique permet de considérer le code du caractère ( sur 8 bits) comme la valeur de ce caractère.
Dans ce cas, le langage C confond un caractère avec la valeur ( entier) du code qui le représente.
Remarque :
La valeur entière associée à un caractère donné n’est pas le même sur toutes les machines.
Voici quelques exemples d'évaluation d'expressions, dans lesquels on suppose que cl et c2 sont de type char.
Les opérateurs et les expressions
• Les opérateurs relationnels
• Le langage C permet de comparer des expressions à l’aide d’opérateurs de comparaison.
• Le résultat de la comparaison est une valeur entière de valeur 1 ( si le résultat est vrai) ou 0 ( si le résultat est faux).
• Cette expression faisant intervenir des opérateurs de comparaison, sera alors de type entier et donc pourra intervenir
dans des calculs arithmétiques.
Exemple :
2 * a > b + 5
Remarque :
C se distingue de la plupart des autres langages sur deux points :
• le résultat de la comparaison est, non pas une valeur booléenne (on dit aussi logique) prenant l'une des deux valeurs vrai
ou faux, mais un entier. Ainsi, la comparaison ci-dessus devient en fait une expression de type entier. Cela signifie qu'elle
pourra éventuellement intervenir dans des calculs arithmétiques.
• les expressions comparées pourront être d'un type de base quelconque et elles seront soumises aux règles de conversion
présentées dans le paragraphe précédent. Cela signifie qu'au bout du compte on ne sera amené à comparer que des
expressions de type numérique.
Les opérateurs et les expressions
• Les opérateurs relationnels
Voici la liste des opérateurs relationnels existant en C.
En ce qui concerne leurs priorités, il faut savoir que les quatre premiers opérateurs (<, <=, >, >=) sont de même priorité. Les
deux derniers (== et ! =) possèdent également la même priorité, mais celle-ci est inférieure à celle des précédents. Ainsi,
l'expression :
a < b == c < d
est interprétée comme :
( a < b) == (c < d)
Les opérateurs et les expressions
• Les opérateurs relationnels
• Les opérateurs relationnels sont moins prioritaires que les opérateurs arithmétiques.
Ainsi :
x + y < a + 2
est équivalent à :
( x + y ) < ( a + 2 )
une comparaison peut porter sur deux caractères. Bien entendu, la comparaison d'égalité ne pose pas de
problème particulier ; par exemple (c1 et c2 étant de type char) :
• c1== c2 sera vraie si c1 et c2 ont la même valeur, c'est-à-dire si c1 et c2 contiennent des caractères de
même code, donc si c1 et c2 contiennent le même caractère.
• c1 < c2 sera vraie si le code du caractère de c1 a une valeur inférieure au code du caractère de c2. Le
résultat d'une telle comparaison peut donc varier suivant le codage employé.
Les opérateurs et les expressions
• Les opérateurs logiques
C dispose de trois opérateurs logiques classiques : et (noté &&), ou (noté | | ) et non (noté ! ). Il est important
de constater que, ne disposant pas de type logique, C se contente de représenter vrai par 1 et faux par 0. C'est
pourquoi ces opérateurs produisent un résultat numérique (de type int).
Les opérateurs et les expressions
• Les opérateurs logiques
• L'opérateur ! a une priorité supérieure à celle de tous les opérateurs arithmétiques binaires et aux opérateurs
relationnels.
• L'opérateur || est moins prioritaire que &&. Tous deux sont de priorité inférieure aux opérateurs arithmétiques ou
relationnels.
• Enfin, les deux opérateurs && et || jouissent en C d'une propriété intéressante : leur second opérande (celui qui figure à
droite de l'opérateur) n'est évalué que si la connaissance de sa valeur est indispensable pour décider si l'expression
correspondante est vraie ou fausse.
Exemple :
int i = 7;
float f = 5.5;
char c = ‘w’;
Expression valeur
( i >= 6 ) && ( c = ‘w’ ) 1
( i >= 6 ) || ( c = = 119 ) 1
(f < 11 ) && ( i > 100 ) 0
( c != ‘p’ ) || ( i + f <= 10 ) 1
Les opérateurs et les expressions
• L'opérateur d'affectation
• L'opérateur d’affectation permet de former des expressions d’affectation .
• La partie gauche de l’opérateur d’affectation `` = `` doit être une lvalue (left value). lvalue est une
expression à laquelle on peut affecter une valeur (Les variables sont des lvalues).
• La partie à droite de l’opérateur est une expression dont la valeur est affectée à la lvalue.
• La valeur finale de l’expression d’affectation est la valeur de la lvalue après affectation.
• La priorité de cet opérateur est inférieure à celle de tous les opérateurs arithmétiques et les opérateurs de
comparaison.
• Si les opérandes sont de types différents, il y a une conversion systématique de l’expression dans le type de
la lvalue. Cette conversion peut entraîner à une dégradation de la valeur convertie. Par exemple, une valeur
de type float peut être tronquée si elle est affectée à une lvalue de type entier.
• Contrairement à tous ceux que nous avons rencontrés jusqu'ici, cet opérateur d'affectation possède une
associativité de droite à gauche.
Les opérateurs et les expressions
• Les opérateurs d'incrémentation et de décrémentation
On distingue deux opérateurs unaires:
• L’opérateur d’incrémentation noté ++
• L’opérateur de décrémentation noté - -
Ils ont pour effet d’incrémenter ou de décrémenter de 1 la valeur d'une variable (ou plus généralement d'une Ivalue).
• Si, par exemple, n et p sont des variables entières, l'expression : (double) ( n/p ) aura comme valeur celle de
l'expression entière n/p convertie en double.
• La notation (double) correspond en fait à un opérateur unaire dont le rôle est d'effectuer la conversion dans
le type double de l'expression sur laquelle il porte. Notez bien que cet opérateur force la conversion du
résultat de l'expression et non celle des différentes valeurs qui concourent à son évaluation.
• D'une manière générale, il existe autant d'opérateurs de « cast » que de types différents. Leur priorité
élevée fait qu'il est généralement nécessaire de placer entre parenthèses l'expression concernée. Ainsi,
l'expression (double) n/p conduirait d'abord à convertir n en double.
Les opérateurs et les expressions
• L'opérateur conditionnel
• Considérons l'instruction suivante :
if ( a>b )
max = a ;
else
max = b ;
• Elle attribue à la variable max la plus grande des deux valeurs de a et de b. La valeur de max pourrait être définie par cette
phrase : Si a>b alors a sinon b
• En langage C, il est possible, grâce à l'aide de l'opérateur conditionnel, de traduire presque littéralement la phrase ci-
dessus de la manière suivante : max = a>b ? a : b
• L’opérateur conditionnel est un opérateur ternaire mettant en relation 3 expressions ou opérandes (a>b, a et b)
• Voici un autre exemple d'une expression calculant la valeur absolue de 3*a + 1 :
3*a+1 >0 ? 3*a+1 : -3*a-1
• Sa priorité est faible, relativement aux autres opérateurs.
Les opérateurs et les expressions
• L'opérateur séquentiel
L’opérateur séquentiel noté "," permet d’exprimer plusieurs calculs successifs au sein d’une même expression.
Exemple:
L’expression a*b, i + j
1. évalue a * b
2. puis i + j
3. prend comme valeur la dernière calculée ( la valeur de i + j )
L’expression i ++, j = i + k
1. incrémente la valeur de i
2. puis évalue j = i + k.
Exemple :
Dans une implémentation où le type int est représenté sur 2 octets et le type double sur 8 octets, si l'on suppose que l'on a
affaire à ces déclarations :
int n ;
double z ;
• l'expression sizeof (n) vaudra 2,
• l'expression sizeof (z) vaudra 8.
Cet opérateur peut également s'appliquer à un type de nom donné. Ainsi, dans l'implémentation précédemment citée :
• sizeof (int) vaudra 2,
• sizeof (double) vaudra 8.
Quelle que soit l'implémentation, sizeof (char) vaudra toujours 1 (par définition, en quelque sorte).
Les opérateurs et les expressions
• Récapitulatif des priorités de tous les opérateurs
Le tableau ci-après fournit la liste complète des opérateurs du langage C, classés par ordre de priorité décroissante,
accompagnés de leur mode d'associativité.
Les opérateurs et les expressions
• Exercices 1
Soit les déclarations suivantes :
int n = 10 , p = 4 ;
long q = 2 ;
float x = 1.75 ;
Donner le type et la valeur de chacune des expressions suivantes :
a) n + q g) q + 3 * (n > p)
b) n + x h) q && n
c) n % p +q i) (q-2) && (n-10)
d) n < p j) x * (q==2)
e) n >= p k) x *(q=5)
f) n > q
Les opérateurs et les expressions
• Exercices 2
Quels résultats fournit le programme suivant ?
Les opérateurs et les expressions
• Exercices 3
Quels résultats fournit le programme suivant ?
Chapitre IV
Les entrées-sorties
conversationnelles
Les entrées-sorties conversationnelles
• Les sorties conversationnelles
Afin d’afficher un caractère ou même un texte (on préfère le terme de « chaîne de caractères ») à l’écran, il faut
utiliser des fonctions. Une fonction, en simplifiant un peu, est un morceau de code exécutant des instructions.
Des instructions qui permettent d’effectuer des opérations (avec par exemple des fonctions mathématiques)
sur des variables ou encore d’écrire du texte à l’écran par exemple.
où param_1 à param_n est une suite d'au moins un paramètre transmis à la fonction, séparés par des ','.
• param_1 : est obligatoire c'est une chaîne de caractères qui comporte des caractères à afficher tels quels et
éventuellement des consignes de formatage pour les autres paramètres (s'il y en a). Il doit y avoir autant de
consignes que de paramètres restant à afficher.
• Le résultat est tel que l'on affiche les arguments param_2, param_3,..., param_n aux formats spécifiés dans
param_1.
• Une consigne de formatage commence toujours par le caractère '%', suivi d'autres caractères qui définissent
le format d'affichage. C'est donc une séquence d'échappement.
Les entrées-sorties conversationnelles
• La fonction printf
Voici les indicateurs de conversions de la norme C89 :
Les entrées-sorties conversationnelles
• La fonction printf (gabarit d'affichage)
• Par défaut, les entiers sont affichés avec le nombre de caractères nécessaires (sans espaces avant ou après). Les flottants
sont affichés avec six chiffres après le point.
• Un nombre placé après % dans le code de format précise un gabarit d'affichage, c'est-à-dire un nombre minimal de
caractères à utiliser. Si le nombre peut s'écrire avec moins de caractères, printf le fera précéder d'un nombre suffisant
d'espaces. (Dans les exemples ci-dessous le symbole ^ représente un espace)
Les entrées-sorties conversationnelles
• La fonction printf (la précision)
• Vous pouvez toujours préciser la précision de l’affichage. Une précision, sous la forme d’un point ('.') suivi par un nombre,
indique donc le nombre de chiffres qu’il y aura derrière la virgule. Voici quelques exemples :
Les entrées-sorties conversationnelles
• La fonction printf (Tabulations et compagnie)
• Afin d’afficher une tabulation ou encore un retour à la ligne, on utilise un caractère d'échappement.
printf("La valeur de la variable\n\t x est : %f\n\t y = %d", x, y);
La valeur de la variable
x est : 42.424340
y=1
• '\n' et '\t' font partie de ces caractères. Voici un petit tableau qui en liste quelques-uns parmi les plus utilisés :
Les entrées-sorties conversationnelles
• Putchar et puts
L'expression :
putchar (c)
joue le même rôle que :
printf ( " %c", c)
• Son exécution est toutefois plus rapide, dans la mesure où elle ne fait pas appel au mécanisme d'analyse de
format. Notez qu'en toute rigueur putchar n'est pas une vraie fonction mais une macro.
• L’utilisation de la fonction puts est plus simple puisqu’elle ne se contente d'afficher que des chaînes de
caractères simples.
puts("Salut les zeros !");
Les entrées-sorties conversationnelles
• Interagir avec l’utilisateur (Entrée conversationnelle)
Maintenant que nous savons déclarer, utiliser et même afficher des variables, nous sommes fin prêts pour
interagir avec l’utilisateur. Nous allons voir comment en récupérer grâce à la fonction scanf, dont l’utilisation
est assez semblable à printf.
scanf("%[lettre]", &variable_dans_laquelle_on_va_mettre_notre_valeur);
La fonction scanf a besoin de connaitre l’emplacement en mémoire de nos variables afin de les modifier. Afin
d’effectuer cette opération, on utilise le symbole &.
Exemple:
int age;
tout en étant plus rapide puisque ne faisant pas appel au mécanisme d'analyse d'un format.
En toute rigueur, getchar est une macro (comme putchar) dont les instructions figurent dans stdio.h. Là encore,
l'omission d'une instruction #include appropriée conduit à une erreur à l'édition de liens.
Les entrées-sorties conversationnelles
• Exercice
Quels seront les résultats fournis par ce programme ?
Chapitre V
Les instructions de
contrôle
Les instructions de contrôle
• Instructions de contrôle
Le langage C dispose d’instructions de contrôle permettant de réaliser :
• des choix :
• L’instruction conditionnelle if…else…
• L’instruction d’aiguillage ou de choix switch…case…default…
Exemple 2
int a,b ;
…
if (( a < = b ) && ( b<= c)) printf( “ordonne”);
Les instructions de contrôle
• L'instruction if
Cas d’imbrications des instructions if…else
Le premier else rencontré est associé avec le plus proche if qui le précède:
• 1ère forme d’imbrication :
if (a <= b)
if ( b<= c) {
printf( “ ordonnée” );
max = c; }
else
printf( “ non ordonnée” );
dans cet exemple, dans le cas où l’expression ( a<=b ) est fausse, rien n’est affiché .
• 2ème forme d’imbrication :
if (heure >= 0) && ( heure < 12)
printf( “ bonjour” );
else if ((heure >= 12) && ( heure < 18))
printf( “ bon pares midi” );
else if ((heure >= 18) && ( heure < 24 ))
printf (“ bonsoir” );
else
printf( “ erreur” );
Les instructions de contrôle
• L'instruction if
Exemple
Les instructions de contrôle
• L'instruction if
Exercice :
Ecrire un programme qui compare les valeurs de 3 entiers et affiche le max.
Les instructions de contrôle
• L'instruction switch
• L’instruction switch est une instruction de choix multiple. Elle permet d’évaluer une expression puis
d'exécuter une action parmi plusieurs actions étiquetées.
• Si la valeur de l’expression correspond à une des étiquettes, l’action correspondante est exécutée .
Syntaxe:
Switch ( expression)
{
case constante1 : [ instructions; ]
………….
case constante : [ instructions; ]
………
[default : instructions; ]
}
Pour sortir de l’instruction switch délimitée par { et } et continuer en séquence, on doit utiliser l’instruction
break .
Exemple:
char c;
…
switch (c)
{
case ‘a’ : printf( “ lettre a” ); break;
case ‘b’ : printf ( “ lettre b” ); break;
default : printf ( “ lettre inconnue” );
}
Les instructions de contrôle
• L'instruction switch
Exemple:
Les instructions de contrôle
• L'instruction switch
Exercice :
Écrire un programme permettant d'afficher le jour en toute lettres selon son numéro saisi au clavier.
Les instructions de contrôle
• L'instruction do... while
Elle permet de répéter une ou plusieurs actions tant que la condition spécifiée n’est pas vérifiée.
Syntaxe :
Do
instructions
while ( expression) ;
• Instructions peut être soit une seule instruction suivie de ; soit un bloc d’instructions entre { et } .
• L’expression est évaluée après avoir exécutée au moins une fois instructions.
• Si la valeur de l’expression est non nulle ( vraie), cette exécution est répétée sinon l’itération se termine.
Les instructions de contrôle
• L'instruction do... while
Exemple :
float note;
do{
printf(“saisir la note”) ;
scanf(“%f”,¬e);
}while (note<0 || note>20)
Les instructions de contrôle
• L'instruction do... while
Exemple 2:
Les instructions de contrôle
• L'instruction while
Tant qu’une condition spécifiée n’est pas vérifiée, elle permet de répéter une ou plusieurs actions.
Syntaxe :
while ( expression )
instructions
Instructions peut être soit une seule instruction soit un bloc d’instructions entre { et } .
Exemple :
int i;
while (i<10){
printf(“%d”,i) ;
i++;
}
Les instructions de contrôle
• L'instruction while
Exemple 2:
Les instructions de contrôle
• L'instruction for
L’instruction for est une instruction de boucle faisant intervenir l’initialisation, le test de limite et
l’incrémentation en une seule action.
Syntaxe:
for ( [expr1] ; [expr2] ; [expr3] )
Instructions;
• “ instructions” peut être une instruction composée, et sera dans ce cas délimitée par { et }.
• “ expr1” est une expression ( une initialisation) qui ne sera exécutée qu’une seule fois au début.
• “expr2” est une expression dont le résultat détermine la fin de la boucle.
• Tant que sa valeur est non nulle ( vraie), la boucle continue.
• “ expr3” est une expression ( en général) qui sera exécutée à chaque itération.
Les instructions de contrôle
• L'instruction for
Exemple :
int i;
for (i=1;i<=5;i++){
printf(“veuillez saisir le nombre %d”,i) ;
scanf(“%d”,&a) ;
printf(“%d”,a*a)
}
Les instructions de contrôle
• L'instruction for
Exemple 2:
Les instructions de contrôle
• L'instruction for
Exercices :
1. Ecrire un algorithme qui demande un nombre de départ, et qui calcule sa factorielle.
2. Ecrire un algorithme qui demande un nombre, calcule et affiche la Somme 𝑛𝑖=1 𝑖 2
3. Ecrire un algorithme qui permet d’afficher un triangle rempli d'étoiles, s'étendant sur un nombre de lignes
fourni en donnée et se présentant comme dans cet exemple :
*
**
***
****
*****
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction break
• Elle peut être utilisée dans les boucles ou dans une instruction switch. Elle permet d’interrompre le
déroulement de la structure où elle a été appelée.
• Dans le cas des boucles ou plusieurs ‘switch ’ imbriqués, l’instruction ‘break’ n’a d’effet que sur la boucle
où elle a été définie.
Exemple:
int i, nbr;
i=0;
while (i<3)
{ printf(“saisir votre nombre);
scanf(“%d”,&nbr);
if ( nbr == 0)
break;
i++;
}
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction break
Exemple:
Les instructions de contrôle
• Les instructions de branchement inconditionnel
L'instruction continue
• Elle peut être utilisée dans les boucles .
• Elle permet de sauter une séquence d’instructions sans sortir de la boucle.
• Dans le cas des boucles imbriquées, l’instruction ‘continue’ n’a d’effet que sur la boucle où elle a été définie.
Exemple:
Les tableaux
Les tableaux
• Les tableaux
• Les tableaux sont certainement les variables structurées les plus populaires. Ils sont disponibles dans tous
les langages de programmation et servent à résoudre une multitude de problèmes. Dans une première
approche, le traitement des tableaux en C ne diffère pas de celui des autres langages de programmation.
Nous allons cependant voir plus loin (Chapitre suivant. Les Pointeurs), que le langage C permet un accès
encore plus direct et plus rapide aux données d'un tableau.
• Les chaînes de caractères sont déclarées en C comme tableaux de caractères et permettent l'utilisation d'un
certain nombre de notations et de fonctions spéciales.
• On nomme ainsi un ensemble d'éléments de même type désignés par un identificateur unique ; chaque
élément est repéré par un indice précisant sa position au sein de l'ensemble.
Les tableaux
• Les tableaux à une dimension
Un tableau (uni-dimensionnel) A est une variable structurée formée d'un nombre entier N de variables simples
du même type, qui sont appelées les composantes du tableau. Le nombre de composantes N est alors
la dimension du tableau.
Exemple
La déclaration
int tab[12]={31,28,31,30,31,30,31,31,30,31,30,31};
• définit un tableau du type int de dimension 12. Les 12 composantes sont initialisées par les valeurs
respectives 31, 28, 31, ... , 31.
• On peut accéder à la première composante du tableau par tab[0], à la deuxième composante par tab[1], . . .
, à la dernière composante par tab[11].
Les tableaux
• Les tableaux à une dimension
En C, le nom d'un tableau est le représentant de l'adresse du premier élément du tableau. Les adresses des
autres composantes sont calculées (automatiquement) relativement à cette adresse.
Exemple:
Si un tableau est formé de N composantes et si une composante a besoin de M octets en mémoire, alors le
tableau occupera de N*M octets.
Exemple
En supposant qu'une variable du type long occupe 4 octets (c.-à-d: sizeof(long)=4), pour le tableau T déclaré
par: long T[15]; C réservera N*M = 15*4 = 60 octets en mémoire.
Les tableaux
• Les tableaux à une dimension
• Initialisation
Lors de la déclaration d'un tableau, on peut initialiser les composantes du tableau, en indiquant la liste des valeurs
respectives entre accolades.
Exemples
int A[5] = {10, 20, 30, 40, 50};
float B[4] = {-1.05, 3.33, 87e-5, -12.3E4};
Il faut évidemment veiller à ce que le nombre de valeurs dans la liste corresponde à la dimension du tableau. Si la liste ne
contient pas assez de valeurs pour toutes les composantes, les composantes restantes sont initialisées par zéro.
• Réservation automatique
Si la dimension n'est pas indiquée explicitement lors de l'initialisation, alors l'ordinateur réserve automatiquement le nombre
d'octets nécessaires.
Exemples
int A[] = {10, 20, 30, 40, 50};
Les tableaux
• Les tableaux à une dimension
En déclarant un tableau par:
int A[5];
nous avons défini un tableau A avec cinq composantes, auxquelles on peut accéder par: A[0], A[1], ... , A[4]
Exemples
En C,
• l'accès au premier élément du tableau se fait par T[0]
• l'accès au dernier élément du tableau se fait par T[N-1]
Les tableaux
• Les tableaux à une dimension
Exemple
Les tableaux
• Les tableaux à une dimension
Exercices :
• Ecrire un programme qui lit la dimension N d'un tableau T du type int (dimension maximale: 50
composantes), remplit le tableau par des valeurs entrées au clavier et affiche le tableau. Calculer et afficher
ensuite la somme des éléments du tableau.
• Ecrire un programme qui lit la dimension N d'un tableau T du type int (dimension maximale: 50
composantes), remplit le tableau par des valeurs entrées au clavier et affiche le tableau. Ranger ensuite les
éléments du tableau T dans l'ordre inverse sans utiliser de tableau d'aide. Afficher le tableau résultant.
Idée: Echanger les éléments du tableau à l'aide de deux indices qui parcourent le tableau en commençant
respectivement au début et à la fin du tableau et qui se rencontrent en son milieu.
Les tableaux
• Les tableaux à deux dimensions
En C, un tableau à deux dimensions A est à interpréter comme un tableau (uni-dimensionnel) de dimension L
dont chaque composante est un tableau (uni-dimensionnel) de dimension C.
On appelle L le nombre de lignes du tableau et C le nombre de colonnes du tableau. L et C sont alors les
deux dimensions du tableau. Un tableau à deux dimensions contient donc L*C composantes.
Exemple
Considérons un tableau NOTES à une dimension pour mémoriser les notes de 20 élèves d'une classe dans un
devoir:
int NOTE[20] = {45, 34, ... , 50, 48};
Pour mémoriser les notes des élèves dans les 10 devoirs d'un trimestre, nous pouvons rassembler plusieurs de
ces tableaux uni-dimensionnels dans un tableau NOTES à deux dimensions :
Exemples
int A[3][10] ={{ 0,10,20,30,40,50,60,70,80,90},
{10,11,12,13,14,15,16,17,18,19},
{ 1,12,23,34,45,56,67,78,89,90}};
Les pointeurs
Les pointeurs
• Introduction
Toute variable manipulée dans un programme est stockée quelque part en mémoire centrale. Cette mémoire
est constituée d'octets qui sont identifiés de manière univoque par un numéro qu'on appelle adresse. Pour
retrouver une variable, il suffit donc de connaître l'adresse de l'octet où elle est stockée (ou, s'il s'agit d'une
variable qui recouvre plusieurs octets contigus, l'adresse du premier de ces octets). Pour des raisons évidentes
de lisibilité, on désigne souvent les variables par des identificateurs, et non par leur adresse. C'est le
compilateur qui fait alors le lien entre l'identificateur d'une variable et son adresse en mémoire. Toutefois, il est
parfois très pratique de manipuler directement une variable par son adresse.
Les pointeurs
• Notion d‘adresse
On appelle Lvalue (left value) tout objet pouvant être placé à gauche d'un opérateur d'affectation. Une Lvalue
est caractérisée par :
• son adresse, c'est-à-dire l'adresse-mémoire à partir de laquelle l'objet est stocké ;
• sa valeur, c'est-à-dire ce qui est stocké à cette adresse.
Dans l'exemple,
int i, j;
i = 3;
j = i;
Si le compilateur a placé la variable i à l'adresse 4831836000 en mémoire, et la variable j à l'adresse
4831836004, on a
• Cette déclaration déclare un objet dont la valeur est l'adresse d'un autre objet. L'identificateur nom-du-
pointeur est donc en quelque sorte un identificateur d'adresse. Comme pour n'importe quelle Lvalue, sa
valeur est modifiable.
• Le type d'un pointeur dépend du type de l'objet vers lequel il pointe.
• En effet, pour un pointeur sur un objet de type char, la valeur donne l'adresse de l'octet où cet objet est
stocké. Par contre, pour un pointeur sur un objet de type int, la valeur donne l'adresse du premier des (4
octets) où l'objet est stocké.
Les pointeurs
• Notion de pointeur
Dans l'exemple suivant, on définit un pointeur p qui pointe vers un entier i :
int i = 3;
int *p;
p = &i;
On se trouve dans la configuration
main() main()
{ {
int i = 3, j = 6; int i = 3, j = 6;
int *p1, *p2; int *p1, *p2;
p1 = &i; p1 = &i;
p2 = &j; p2 = &j;
*p1 = *p2; p1 = p2;
} }
Les pointeurs
• Notion de pointeur
Avant la dernière affectation de chacun de ces programmes, on est dans une configuration du type :
objet adresse valeur
i 4831836000 3
j 4831836004 6
p1 4831835984 4831836000
p2 4831835992 4831836004
Après l'affectation *p1 = *p2; du premier programme, on a
objet adresse valeur
i 4831836000 6
j 4831836004 6
p1 4831835984 4831836000
p2 4831835992 4831836004
Si i est un entier et p est un pointeur sur un objet de type int, l'expression p + i désigne un pointeur sur un
objet de type int dont la valeur est égale à la valeur de p incrémentée de i * sizeof(int). Il en va de même pour
la soustraction d'un entier à un pointeur, et pour les opérateurs d'incrémentation et de décrémentation ++ et --
Les pointeurs
• Allocation dynamique
Avant de manipuler un pointeur, et notamment de lui appliquer l'opérateur d'indirection *, il faut l'initialiser.
Sinon, par défaut, la valeur du pointeur est égale à une constante symbolique notée NULL définie dans stdio.h.
En général, cette constante vaut 0. Le test p == NULL permet de savoir si le pointeur p pointe vers un objet.
On peut initialiser un pointeur p par une affectation sur p. Par exemple, on peut affecter à p l'adresse d'une
autre variable. Il est également possible d'affecter directement une valeur à *p. Mais pour cela, il faut d'abord
réserver à *p un espace-mémoire de taille adéquate. L'adresse de cet espace-mémoire sera la valeur de p.
Cette opération consistant à réserver un espace-mémoire pour stocker l'objet pointé s'appelle allocation
dynamique. Elle se fait en C par la fonction malloc de la librairie standard stdlib.h. Sa syntaxe est:
malloc(nombre-octets)
Cette fonction retourne un pointeur de type char * pointant vers un objet de taille nombreoctets octets. Pour
initialiser des pointeurs vers des objets qui ne sont pas de type char, il faut convertir le type de la sortie de la
fonction malloc à l'aide d'un cast. L'argument nombre-octets est souvent donné à l'aide de la fonction sizeof()
qui renvoie le nombre d'octets utilisés pour stocker un objet.
Les pointeurs
• Allocation dynamique
Ainsi, pour initialiser un pointeur vers un entier, on écrit :
#include <stdlib.h>
…
int *p;
p = (int*)malloc(sizeof(int));
Exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int i = 3;
int *p;
printf("valeur de p avant initialisation = %ld\n",p);
p = (int*)malloc(sizeof(int));
printf("valeur de p apres initialisation = %ld\n",p);
*p = i;
printf("valeur de *p = %d\n",*p);
}
Les pointeurs
• Allocation dynamique
La fonction malloc permet également d'allouer un espace pour plusieurs objets contigus en mémoire. On peut
écrire par exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int i = 3;
int j = 6;
int *p;
p = (int*)malloc(2 * sizeof(int));
*p = i;
*(p + 1) = j;
printf("p = %ld \t *p = %d \t p+1 = %ld \t *(p+1) = %d
\n",p,*p,p+1,*(p+1));
}
Les pointeurs
• Allocation dynamique
• La fonction calloc de la librairie stdlib.h a le même rôle que la fonction malloc mais elle initialise en plus
l'objet pointé *p à zéro. Sa syntaxe est
calloc(nb-objets,taille-objets)
• Enfin, lorsque l'on n'a plus besoin de l'espace-mémoire alloué dynamiquement (c'est-à-dire quand on
n'utilise plus le pointeur p), il faut libérer cette place en mémoire. Ceci se fait à l'aide de l'instruction free
qui a pour syntaxe
free(nom-du-pointeur);
• A toute instruction de type malloc ou calloc doit être associée une instruction de type free.
Les pointeurs
• Pointeurs et tableaux
• L'usage des pointeurs en C est, en grande partie, orienté vers la manipulation des tableaux.
• Tout tableau en C est en fait un pointeur constant. Dans la déclaration int tab[10]; tab est un pointeur constant (non
modifiable) dont la valeur est l'adresse du premier élément du tableau. Autrement dit, tab a pour valeur &tab[0]. On peut
donc utiliser un pointeur initialisé à tab pour parcourir les éléments du tableau.
Exemple :
#define N 5
int tab[5] = {1, 2, 6, 0, 7};
main()
{
int i;
int *p;
p = tab;
for (i = 0; i < N; i++)
{
printf(" %d \n",*p);
p++;
}
}
Les pointeurs
• Pointeurs et tableaux
Toutefois, la manipulation de tableaux, et non de pointeurs, possède certains inconvénients dûs au fait qu'un
tableau est un pointeur constant. Ainsi
• on ne peut pas créer de tableaux dont la taille est une variable du programme,
• on ne peut pas créer de tableaux bidimensionnels dont les lignes n'ont pas toutes le même nombre
d'éléments.