Académique Documents
Professionnel Documents
Culture Documents
Chapitre 1
1.1 Historique
Le langage C est né en 1972 dans les laboratoires de Bell-laboratories. Il a été conçu par
Denis Ritchie et Brian W.Kernighan.
Les dates marquantes de l’histoire du langage C sont les suivantes :
1972 : La première version de C est écrite en assembleur par Denis Ritchie et Brian
W.Kernighan.
1973 : Alan Snyder écrit un compilateur C portable (thèse MIT).
1975 : Steve C. Johonson écrit et présente le PCC (portable C compiler)
1978 : Le premier compilateur C sur micro par Tom Gibson.
1982 : L’ANSI crée un comité technique pour la standarisation du langage C.
1987 : Normalisation du langage C par I.E.E.E Norme X3J-11. Cette norme a pour but
de rendre plus précise la description du langage C.
1990 : Réalisation du document final normalisé auprès de l’ISO.
1.2 Présentation
Le langage C est un langage :
Langage évolué : Le programmeur n’est pas obligé de connaître l’architecture interne de
l’ordinateur pour écrire son programme.
Langage structuré : le programme est organisé en « blocs d’instructions » emboîtés.
Modulaire: peut être découpé en modules qui peuvent être compilés séparement
Universel: n'est pas orienté vers un domaine d'application particulier
Typé: tout objet C doit être déclaré avant d’être utilisé
Les compilateurs C possèdent les taux d'expansion les plus faibles de tous les langages
évolués (rapport entre la quantité de codes machine générée par le compilateur et la quantité
de codes machine générée par l'assembleur et ce pour une même application).
La connaissance du langage C est aussi nécessaire pour apprendre les langages proches de C
comme C++ qui est un langage orienté objet basé sur C et JAVA qui est un langage orienté
objet dont les structures ressemblent beaucoup à celles du C.
Le langage C possède assez peu d'instructions, il fait par contre appel à des bibliothèques,
fournies en plus ou moins grand nombre avec le compilateur.
1.3. La compilation
Les étapes permettant la création, la mise au point et l’exécution d’un programme sont comme
suit :
1
Langage C
Exemple :
Tva, p250, a_x, _ax.(identificateurs)
2x, x#y (ne sont pas des identificateurs)
2
Langage C
Remarque
Le langage C distingue les minuscules, des majuscules. Les mots réservés du langage C
doivent être écrits en minuscule.
Remarque:
3
Langage C
Le type int est soit équivalent à short (dans le cas où le mot machine est de 16 bits) ou long
(dans le cas où le mot machine est de 32 bits)
1.6.2 Les types réels (types flottants)
Les types flottants en C permettent de représenter, de manière approchée des nombres réels
C dispose de 3 types flottants caractérisés par leurs tailles :
a. le type float qui utilise 32 bits
b. le type double qui utilise 64 bits
c. le type long double qui utilise 80 bits
Un réel est composé - d'un signe - d'une mantisse - d'un exposant
Pour chacun de ces types, la représentation d’un nombre se décompose alors en trois parties :
Un bit réservé au signe.
Un emplacement pour un exposant
• 8 bits pour le type float
• 11 bits pour le type double
• 15 bits pour le type long double.
Un emplacement pour la mantisse
• 23 bits pour le type float
• 52 bits pour le type double
• 64 bits pour le type long double.
Remarque : Ce tableau correspond seulement aux valeurs absolues des nombres, il peut
être complété de façon symétrique pour les valeurs négatives.
Remarque:
En langage C, le type char est un cas particulier du type entier.
Par exemple, Le caractère 'b' a pour valeur 98 (son code ASCII).
Tout objet de type char peut être utilisé dans une expression qui utilise des objets de type
entier. Par exemple, si c est de type char, l’expression c + 1 est valide
Les caractères constants s’écrivent entre ‘ ’
Par exemple : char c = ’A’;
4
Langage C
Syntaxe:
Type variable1, variable2,…. ;
Exemple:
int a,b ;
1.7.2 Initialisations
Le langage C permet l'initialisation des variables dans la zone des déclarations.
Exemple :
char c; c = 'A'; est équivalent à char c = 'A';
int i; i = 50; est équivalent à int i = 50;
5
Langage C
-- opérateur de décrémentation
++ opérateur d’incrémentation
Sizeof opérateur de taille en octets
! NOT logique
- Moins unaire : inverse de signe
Opérateurs tertiaires : Il existe en C un opérateur tertiaire qui porte sur trois opérandes.
C’est l’opérateur ?
Syntaxe :
exp1 ? exp2 :exp3
Où exp1, exp2, exp3 sont trois expressions
Le résultat retourné est exp2 si exp1 est vraie, ou exp3 si exp1 est faux.
Exemple
max =(a>=b ? a :b) ;
6
Langage C
Opérateur Dénomination
== Opérateur d’égalité
< Opérateur d’infériorité stricte
<= Opérateur d’infériorité
> Opérateur de supériorité stricte
>= opérateur de supériorité
!= Opérateur de différence
Remarque :
Le langage C ne dispose pas de type logique.
Une expression est fausse si la valeur qu’elle retourne est égale à 0, elle est vraie si non.
C’est pourquoi ces opérateurs produisent un résultat numérique de type int.
Dans le cas où l’opérateur est post-fixé (opérateur ++ après la variable), l’incrémentation est
appliquée après l’affectation.
Exemple:
int i=0, j=0 ;
j=i++;
A la fin de cette opération i vaut 1 et j vaut 0.
De même que la post-incrémentation, il est possible d’utiliser la post-décrémentation.
7
Langage C
Le langage C autorise des écritures simplifiées lorsqu'une même variable est utilisée de
chaque côté du signe = d'une affectation. Ces écritures sont à éviter lorsque l'on débute l'étude
du langage C car elles nuisent à la lisibilité du programme.
Exemples : a = a+b; est équivalent à a+= b;
a = a-b ; est équivalent à a-= b;
Exemple:
int n,p;
n=1 ;
float x,y;
x=6.25;
y =-14.4.;
x=n; /*conversion implicite*/
p= (int)y; /*conversion explicite*/
le résultat est
x=1
p=-14
8
Langage C
Manipulation |
de bits
Logique &&
Logique ||
Tertiaire ?
Affectation = += -= *= /= %= &= ^= |= <<= >>= De gauche à droite
Séquentiel ,
code type
%c Caractère
%d Décimal
%e Réel sous forme exponentielle
%f Réel avec le point décimal
%lf Réel de type double
%s Chaîne de caractère
%u Décimal non signé
%x Hexadécimal signé
En plus du caractère donnant le type des données, on peut éventuellement préciser certains
paramètres du format d’impression, qui sont spécifiés entre le % et le caractère de conversion
dans l’ordre suivant :
– largeur minimale du champ d’impression : %10d spécifie qu’au moins 10 caractères seront
réservés pour imprimer l’entier. Par défaut, la donnée sera cadrée à droite du champ. Le signe
- avant le format signifie que la donnée sera cadrée `a gauche du champ (%-10d).
– précision : %.12f signifie qu’un flottant sera imprimé avec 12 chiffres après la virgule. De
même %10.2f signifie que l’on réserve 12 caractères (incluant le caractère .) pour imprimer le
flottant et que 2 d’entre eux sont destinés aux chiffres après la virgule. Lorsque la précision
9
Langage C
n’est pas spécifiée, elle correspond par défaut à 6 chiffres après la virgule. Pour une chaîne de
caractères, la précision correspond au nombre de caractères imprimés : %30.4s signifie que
l’on réserve un champ de 30 caractères pour imprimer la chaîne mais que seulement les 4
premiers caractères seront imprimés (suivis de 26 blancs).
La fonction putchar
La fonction putchar permet d’afficher à l’écran un seul caractère.
Soit c une variable de type char, l’écriture putchar(c), est équivalente à printf(’’%c\n’’, c).
La fonction puts
La fonction puts permet d’afficher un texte :
L’écriture puts("bonjour"), est équivalente à printf("bonjour\n").
Remarque
Il vaut mieux utiliser puts et putchar si cela est possible, ces fonctions, non formatées, sont
d’exécution plus rapide, et nécessitent moins de place en mémoire lors de leur chargement.
Syntaxe :
scanf("code format1 code format2... code format n",&variable1, &variable2,..., &variable n);
Remarque
Si l’utilisateur ne respecte pas le format indiqué dans scanf, la saisie est ignorée. Aucune
erreur n’est générée.
La fonction getch
La fonction getch, appartenant à la bibliothèque conio.h permet la saisie au clavier d’un seul
caractère alphanumérique, sans écho écran. La saisie s’arrête dès que le caractère a été frappé.
Exemple
char alpha ;
printf ("Entrer un caractère") ;
alpha=getch() ;
printf ("\n Voici ce caractère :%c", alpha) ;
Remarque
10
Langage C
Les parenthèses vides de getch() signifient qu’aucun paramètre n’est passé à cette fonction par
le programme.
La fonction getchar
La fonction getchar permet la saisie d’un seul caractère (char) avec écho écran.
Exemple
Les deux écritures sont équivalentes :
char c ; char c ;
printf ("Entrer un caractère :") ; printf ("Entrer un caractère :") ;
scanf("%c",&c) ; c=getchar() ;
Remarque
Non formatée (pas de code format), la fonction getchar est moins gourmande en place
mémoire que scanf. Il vaut mieux l’utiliser quand cela est possible.
Exemple d’application
# include <stdio.h>
# include <conio.h>
main ( ){
char c ;
printf("Entrer un caractère :") ;
scanf("%c",&c) ; /* ou bien c=getchar() ; */
printf("Voici son code ASCII en decimal :%d \n" , c) ;
puts("Pour continuer frapper une touche…") ;
getch() ;
}
Notion de flux d’entrée :
Lorsqu’on saisie au clavier une suite de caractères terminées par "RETURN", ces caractères
sont rangés dans un tampan (ou buffer) de type FIFO (First In/First Out). Le dernier caractère
rangé dans le tampan est LF (code ASCII 0x0A). Cette suite de caractères est appelé flux
d’entrée la taille d’un tampan dépend de la machine et de compilateur utilisé. (127 caractères
pour un PC en TURBO C).
Une compilation du programme vide le tampan.
scanf et getchar() et flux d’entrée :
la saisie avec scanf et getchar est terminée par "RETURN", si le tampan est vide tous se passe
normal. Cependant, si le tampan n’est pas vide, ces fonctions testent le dernier élément s’il
correspond au format de la variable invoquée et le tampan perd cet élément.
Tout caractère ou nombre saisi au clavier et non pris en compte par scanf est rangé dans le
tampan.
Exemple :
#include<stdio.h>
main(){
char c1,c2;
printf("donner un caractère\n");
scanf("%c",&c1);
printf("voici son code ASCII en hexadécimal%x\n",c1);
printf("donner un autre caractère\n");
11
Langage C
scanf("%c",&c2);
printf("voici son code ASCII en hexadécimal%x\n",c2);
system("pause");
return 0;
}
Si l’utilisateur saisi A pour c1 :
Après la saisie de K, le caractère LF est rangé dans le buffer, lors du deuxième appel à scanf
le tampan n’est pas vide, pas de saisie au clavier.
Remarque :
En DevC++ la fonction fflush(stdin) permet de vider la tampan d’entrée
En Turbo C la fonction flushall()permet de vider la tampan d’entrée
12
Langage C
Chapitre 2
Syntaxe en C: if (expression) {
............; /* bloc 1 d'instructions */
............;
}
else {
............; /* bloc 2 d'instructions */
............;
}
Le bloc "sinon" est optionnel, une autre forme de l’instruction if est donc comme suit :
si (expression vraie)
alors {BLOC D'INSTRUCTIONS}
Syntaxe en C: if (expression) {
............; /* bloc d'instructions */
............;
}
Remarque:
Les {} ne sont pas nécessaires lorsque les blocs ne comportent qu'une seule instruction.
Exemple 1
char reponse ;
printf ("Voulez-vous jouer ?") ;
reponse = getchar() ;
if(reponse = =’o’)
printf ("Bonjour\n") ;
else printf ("Tant-pis"\n) ;
Exemple 2 : un programme qui lit un nombre réel puis affiche sa valeur absolue :
13
Langage C
#include <stdio.h>
void main(){
float x,absx ;
/* x est une variable réelle et absx contiendra sa valeur absolue*/
printf(" Entrer un nombre réel : ") ;
scanf("%f",&x) ; /* lecture de x au clavier*/
if (x>=0) absx=x ;
else absx=-x ;
printf(" la valeur absolue de %f est %f ",x,absx) ;
getchar() ;}
2.1.2 L’instruction de choix multiple : switch. (AU CAS OU ... FAIRE ...)
L'instruction d’aiguillage switch est une instruction du choix multiple qui effectue un
aiguillage vers les instructions en fonction d’une variable.
Syntaxe:
switch(variable de type char ou int) /*au cas où la variable vaut:*/
{
case valeur1: /*- cette valeur1: exécuter ce bloc1 d'instructions. */
bloc1 d'instructions ;
break;
valeur2: /*- cette valeur2: exécuter ce bloc2 d'instructions. */
bloc2 d'instructions ;
break;
. /*etc ... */
.
default: /* - aucune des valeurs précédentes: exécuter ce bloc
bloc d'instructions ; d'instructions, pas de "break" ici. */
}
Remarques
1) le bloc "default" n'est pas obligatoire.
2) L’instruction switch correspond à une cascade d’instructions if ...else
Exemple 1: (exemple avec variable de type int en argument de switch)
int i ;
scanf ("%d",& i) ;
switch(i)
{
case 0 : printf ("c’est dimanche\n") ;
break ;
case 1 : printf ("c’est lundi\n") ;
break ;
:
:
case 6 : printf ("c’est samedi\n") ;
break ;
default : printf ("ce choix n’est pas prevu") ;
}
14
Langage C
scanf ("%c",& c) ;
switch(c)
{
Case ‘o’ :
Case ‘O’ : printf ("Oui") ;
break ;
Case ‘n’ :
Case ‘N’ : printf ("Non ") ;
break ;
default : printf ("réponse incorrecte") ;
}
Remarques
1) Le test se fait d'abord, le bloc d'instructions peut donc ne jamais être exécuté si
l’expression est fausse dès le début.
2) le bloc d'instructions peut être exécuté à l’infini si l’expression reste toujours vraie. On
parle alors de boucle infinie.
3) On peut rencontrer la construction suivante: while (expression); terminée par un ; et
sans la présence du bloc d'instructions. Cette construction signifie: "tant que
l'expression est vraie attendre".
Exemple: Calcul de la somme des N premiers nombres entiers strictement positives (sans
utiliser la formule de la suite)
# include<stdio.h>
void main( ) {
int i,N,somme;
printf(“entrer le nombre N>0:”);
scanf (“%d”,&N);
i=1;
somme=0;
while(i<=N){somme+=i; i++}
printf(“la somme est: %d”,somme);
15
Langage C
getch();
}
Syntaxe en C: do
{
............; /* bloc d'instructions */
............;
}
while (expression);
Remarque
Le test se faisant après, le bloc est exécuté au moins une fois.
Exemple
Contrôler la lecture d’une valeur entière X avec 0<= X <= 10
Void main( ) {
int X;
do {
printf ("introduire la valeur de X avec 0<= X <= 10") ;
scanf ("%d",& X) ;
} while (X>=0&& X<= 10) ;
}
Syntaxe en C:
for (initialisation ; condition de continuité ; modification)
{
............; /* bloc d'instructions */
............;
}
16
Langage C
Exemple
int i, resultat ;
resultat = 0 ;
for (i = 0 ; resultat< 30 ;i++)
{…………… ;
…………… ;
resultat = resultat + 2*i ;
}
Remarque
En langage C il est possible de regrouper deux instructions en une seul en les séparant par le
symbole virgule (,) par exemple i++, j++.
On peut exploiter cette possibilité pour concevoir des boucles avec deux compteurs à la fois.
Exemple
int i,j ;
for (i = 0,j = 20 ; i< 30 ;i++, j--)
{printf ("i = %d\n", i) ;
printf ("j = %d\n", j) ;
}
17
Langage C
Chapitre 3
Les Tableaux
Définition
On appelle tableau, une variable composée de données de même type, stockées de manière
continue en mémoire (les unes à la suite des autres). Les éléments du tableau peuvent être :
des données de types : int, char, float, long, double, des pointeurs (des objets contenant une
adresse mémoire)…….
Exemples :
char Tableau [8] ; /*déclaration d’un tableau de 8 éléments de types char */
int tab[10] ; */ déclaration d’un tableau de 10 éléments de types int */.
Exemples :
Voici différents exemples de tableaux, et leurs tailles respectives.
18
Langage C
Remarques :
L’indice du premier élément du tableau est 0
Un indice est toujours positif
L’indice du dernier élément du tableau est égale au nombre d’éléments-1
Exemples :
int Tableau[7] ;
Tableau[0] est le premier élément du tableau
Tableau[6] est le dernier élément du tableau.
Exemple :
int tableau [10] ;
tableau [7]=3 ; pour affecter la valeur 3 au huitième élément
tableau [9]=tableau[0]+tableau[1] ; /*Pour affecter au 10ieme élément le résultat de l’addition
du premier et du deuxième élément*/
Remarque :
L’élément tableau[10] n’existe pas(on parle de débordement d’indice).
3.1.5 Initialisation des éléments d’un tableau unidimensionnel
Il existe plusieurs méthodes pour initialiser un tableau :
Exemple :
Tableau [0]= Tableau [1]= Tableau [2]=0 ;Tableau [3]=1 ;
Exemple :
int Tableau [10] ;
int indice ;
for (indice=0 ; indice<10; indice++)
{ Tableau [indice]=0 ; }
19
Langage C
Exemple :
int tableau[10]={5,1,6,-8,1,2,1,-2,3,14} ;
Remarques
1) Le nombre de valeurs entre accolades ne doit pas être supérieur au nombre
d’éléments du tableau
2) Les valeurs entre accolades doivent être des constantes.
3) Si le nombre de valeurs entre accolades est inférieur au nombre d’éléments du
tableau, les derniers éléments sont initialisés à 0.
Une chaîne de caractères est un tableau, comportant plusieurs données de type char, dont le
dernier élément est le caractère nul '\0', c'est-à-dire le premier caractère du code ASCII (dont
la valeur est 0). Ce caractère est un caractère de contrôle (donc non affichable) qui permet
d'indiquer une fin de chaîne de caractères. Ainsi une chaîne composée de n éléments sera en
fait un tableau de n+1 éléments de type char. On peut toutefois utiliser partiellement cet
espace pour acquérir une chaîne de taille inférieure, en insérant le caractère de fin de chaîne à
l'emplacement désiré dans le tableau.
La taille d’une variable de type char est de un octet. Le nombre d’octets d’un tableau de
caractères sera donc égal au nombre d’éléments.
20
Langage C
Vous pouvez lire plusieurs chaînes avec la même fonction, les règles précédentes
s’appliqueront pour chaque chaîne. Par exemple :
Scanf("%S %S %S " , S1,S2,S3);
Si vous tapez Janvier février mars, en réponse à cette instruction S1 sera égal à Janvier, S2 à
février et S3 à mars.
Si vous tapez septembre en réponse à l’instruction suivante :
Scanf("%3S %3S %3S »,S1,S2,S3);
Les valeurs de S1, S2 et S3 seront respectivement sep, tem et bre
La fonction usuel gets() :
La fonction gets() lit une chaîne de caractères entrée au clavier par l’utilisateur, quand cette
fonction est appelée, elle lit tous ce qui est tapé au clavier sans sauter aucun délimiteurs (les
espaces sont lus comme les autres caractères), jusqu’à ce que l’utilisateur enfonce la touche de
retour à la ligne (touche Entrée). La fonction ne prend pas en compte cette touche, ajoute un
caractère nul ‘\0’ en fin de chaîne et renvoie la chaîne au programme appellent.
Pour un tableau de caractères déclaré comme suit : char nom[30] ;
La syntaxe est : gets(nom) ;
21
Langage C
Cette fonction permet de recopier la chaîne source dans la chaîne destination. Il est nécessaire
que la taille du tableau réservé pour la chaîne destination soit suffisante pour accueillir la
chaîne à recopier.
Exemple :
Echanger les lieux de deux mots : mot1 et mot2 :
Pour cela on a besoin d’une troisième adresse, c’est le tableau mot.
#include <stdio.h>
#include <string.h>
#define LG_mot 30
void main (){
char mot1[LG_mot+1] ;
char mot2[LG_mot+1] ;
char mot[LG_mot+1] ;
printf("donnez deux mots:\n ") ;
scanf("%s %s",mot1,mot2) ;
{strcpy(mot,mot1);
strcpy(mot1,mot2);
strcpy(mot2,mot);}
printf("voici les deux mots permutés: %s %s",mot1,mot2) ;
}
La fonction strlen() :
La fonction strlen() (Abréviation de string lenght) permet de connaître le nombre de
caractères que contient une chaîne.
Syntaxe :
Pour un tableau de caractères déclaré comme suit :
char mot[LG_mot+1] ;
strlen(mot) renvoie le nombre de caractères de la chaîne existante dans le tableau.
chaque élément entre crochet désigne le nombre d’éléments dans chaque dimension
Le nombre de dimension n’est pas limité.
Exemple :
int Tableau[3][4] ; correspondent aux matrices en mathématiques et définie un tableau
d’entiers a deux dimensions(3 lignes, 4 colonnes).
22
Langage C
Exemple :
int Tableau[3][4] ;
int i,j ;
for (i=0;i<3;i++)
for (j=0;j<4;j++)
Tableau[i][j]=0 ;
Les valeurs sont attribués aux éléments successifs en incrémentant d’abord les indices de
droite, c'est-à-dire pour un tableau a deux dimensions [0][0],[0][1],[0][2]…..puis [1][0]
etc.…..
23
Langage C
Chapitre 4
LES POINTEURS
Syntaxe :
Nom_type *ptr ;
Nom_type désigne le type de la variable
ptr : nom du pointeur
(*) c’est l’opérateur d’indirection qui indique que le pointeur ptr pointe sur la variable de type
(nom_type)
Exemple:
char *pc; pc est un pointeur pointant sur un objet de type char
int *pi; pi est un pointeur pointant sur un objet de type int
float *pr; pr est un pointeur pointant sur un objet de type float .
24
Langage C
Après avoir déclaré un pointeur il faut l’initialiser. Pour initialiser un pointeur, la syntaxe est
la suivante :
Nom_du_pointeur=NULL ; ou :
Nom_du_pointeur=&nom_de_la_variable_pointee ;
Exemple :
int rt=100 ;
int *P_rt=NULL ;
1004
NULL 100
P_rt rt
Pour stocker l’adresse de rt dans la variable P_rt selon l’instruction d’affectation d’adresse en
utilisant l’opérateur d’adresse &.
P_rt = & rt ; //on dit que P_rt pointe sur rt
D’où le schéma suivant :
1004
1004 100
P_rt rt
Une fois un pointeur affecté avec l’adresse d’une variable, ce pointeur peut être utilisé pour
accéder aux cases mémoires correspondant à la variable à laide de l’opérateur * (valeur de la
variable) :
Exemple
int rt=100, p ;
int *P_rt ;
P_rt =&rt ;
p=* P_rt ; /* affecte à p la valeur désignée par * P_rt c-à-d ici la valeur de rt*/
* P_rt =30 ; /*affecte à l’entier pointé par P_rt la valeur 30 ceci équivalent à rt=30 */.
25
Langage C
La fonction malloc()
Pour l’utiliser il faut inclure la bibliothèque <stdlib.h> en début de programme.
malloc( N ) renvoie l’adresse d’un bloc de mémoire de N octets libres (ou la valeur NULL s’il
n’y a pas assez de mémoire).
Cette fonction retourne par défaut un pointeur de type char * pointant vers un objet de taille N
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.
Exemple :
int *p ;
p = (int*)malloc(800) ; /* fournit l’adresse d’un bloc de 800 octets libres */
/* et l’affecte au pointeur p */
L’opérateur sizeof()
D’une machine à une autre, la taille réservée pour un int, un float,... change. Si nous voulons
réserver de la mémoire pour des données d’un type dont la grandeur varie d’une machine á
l’autre, nous avons besoin de la taille effective d’une donnée de ce type.
26
Langage C
Fonction calloc :
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)
Ainsi, si p est de type int*, l’instruction
p = (int*)calloc(N,sizeof(int));
est strictement équivalente à
p = (int*)malloc(N * sizeof(int));
for (i = 0; i < N; i++)
*(p + i) = 0;
L’emploi de calloc est simplement plus rapide.
4.2.2 Pointeur et tableau à plusieurs dimensions
Un tableau à deux dimensions est, par définition, un tableau de tableaux. Il s’agit donc en fait
d’un pointeur vers un pointeur. Considérons le tableau à deux dimensions défini par :
int tab[M][N];
tab est un pointeur, qui pointe vers un objet lui-même de type pointeur d’entier. tab a une
valeur constante égale `a l’adresse du premier élément du tableau, &tab[0][0]. De même
tab[i], pour i entre 0 et M-1, est un pointeur constant vers un objet de type entier, qui est
le premier élément de la ligne d’indice i. tab[i] a donc une valeur constante qui est égale à
&tab[i][0].
Exactement comme pour les tableaux à une dimension, les pointeurs de pointeurs ont de
nombreux avantages sur les tableaux multi-dimensionnés.
On déclare un pointeur qui pointe sur un objet de type type * (deux dimensions) de la
même manière qu’un pointeur, c’est-`a-dire
type **nom-du-pointeur;
Par exemple, pour crèer avec un pointeur de pointeur une matrice à k lignes et n colonnes à
coefficients entiers, on écrit :
main()
{
int k, n;
int **tab;
tab = (int**)malloc(k * sizeof(int*));
for (i = 0; i < k; i++)
tab[i] = (int*)malloc(n * sizeof(int));
....
27
Langage C
La première allocation dynamique réserve pour l’objet pointé par tab l’espace-mémoire
correspondant à k pointeurs sur des entiers. Ces k pointeurs correspondent aux lignes de la
matrice.
Les allocations dynamiques suivantes réservent pour chaque pointeur tab[i] l’espace-mémoire
nécessaire pour stocker n entiers.
Si on désire en plus que tous les éléments du tableau soient initialisés à zéro, il suffit de
remplacer l’allocation dynamique dans la boucle for par
tab[i] = (int*)calloc(n, sizeof(int));
la fonction free()
pour libérer (désallouer) l’espace mémoire déjà alloué par la fonction malloc en utilise la
fonction free().
Exemple :
for (i = 0; i < k; i++)
free(tab[i]);
free(tab);
Syntaxe
#include <stdlib.h>
char * nom_pointeur=malloc(taille) ;
Exemple :
char *ptr ;
Ptr=malloc(100) ; ou encore :
Ptr=(malloc(100*sizeof(char)) ;
Ptr pointe maintenant sur un bloc de 100 octets qui peut recevoir une chaîne de caractère.
28
Langage C
Affectation
On peut affecter une valeur à un pointeur, c’est une adresse précédée par l’opérateur &.
Différence :
Entre deux pointeurs de même type (si vous avez deux pointeurs sur un même tableau, le
résultat de leur soustraction correspond au nombre d’éléments qui les séparent).
Comparaison :
= = , != , > , < , >= et <=
Ne sont validés que pour deux pointeurs de même tableau.
Remarques
Eviter d’effectuer des opérations mathématiques comme des divisions, des
multiplications ou des modulos
pour incrémenter la valeur d’un pointeur (exemple int *x), il faut utiliser :
(*x)++ et nom pas *x++
29
Langage C
Chapitre 5
Les Fonctions en C
On appelle fonction ou sous programme, une partie de code source qui permet d’effectuer un
ensemble d’instructions par simple appel de la fonction.
Les fonctions permettent d’exécuter dans plusieurs parties du programme une série
d’instructions, cela permet une simplicité du code et donc une taille de programme minimale.
Remarques :
1) L’imbrication d’une fonction n’est pas autorisée en C, une fonction ne peut pas être
déclarée à l’intérieure d’une autre fonction. Par contre une fonction peut appeler une
autre fonction
2) Si la fonction ne renvoie aucune valeur, on la fait précéder du mot-clé void
syntaxe : void nom_fonction(arguments)
3) Fonctions renvoyant une valeur au programme et sans d’arguments
Syntaxe : Type nom_fonction(void)
4) Si aucun type de données n’est précisé, le type int est pris par défaut
5) Les arguments sont facultatifs, mais s’il n’y a pas d’arguments les parenthèses doivent
rester présentes.
30
Langage C
Instruction return:
Le rôle de l’instruction return dans la fonction est double : d’une part, il précise la valeur qui
sera fournie en résultat, d’autre part, il met fin à l’exécution des instructions de la fonction.
Exemple :
float cube(float x)
{ return(x*x*x) ; } /* les ( ) ne sont pas indispensables*/
L’instruction return apparaît comme la dernière de la définition de notre fonction, mais il est
théoriquement possible de placer plusieurs instructions return dans une même fonction
Exemple :
float max(float a, float b)
{ if (a>b) return a;
else return b;
}
Exemple
int carre (int val)
{
int val_retour = 0; /* Déclaration variable locale */
val_retour = val * val;
return (val_retour);
}
void main ()
{
int val_retour = 0; /* Déclaration variable locale */
31
Langage C
Exemple
#include …
int val = 0; /* Déclaration variable globale */
int carre ()
{
int val_retour = 0;
val_retour = val * val;
return (val_retour);
}
void main ()
{
val = 2;
carre ();
printf ("Le carre de 2 est %d", carre ());
}
32
Langage C
getch() ;
}
5.4 Prototype d’une fonction
Le prototype d’une fonction est une description d’une fonction qui est définie plus loin dans
le programme. Cette description permet au compilateur de vérifier la validité de la fonction à
chaque fois qu’il la rencontre dans le programme, en lui indiquant sa signature (le type de
valeur renvoyée par la fonction, le nom de la fonction, les types d’arguments).
Contrairement à la définition de la fonction, le prototype n’est pas suivi du corps de la
fonction (contenant les instructions à exécuter), et ne comprend pas le nom des paramètres
(seulement leur type).
Un prototype de fonction a la syntaxe suivante :
Type Nom_Fonction(type1,type2,…) ;
Remarques :
- Le prototype est une instruction, il est donc suivi d’un point
virgule ;
- Si la fonction n’a aucun argument, la liste des argument est
remplacée par void. Exemple : int fonct(void)
- Le prototype d’une fonction doit être utilisé, lorsque la
définition d’une fonction est placée après les fonctions qui
l’utilisent.
Exemples de prototypes :
void affiche_car(char,int) ;
int somme (int,int) ;
Exemple d’utilisation de prototype
#include <stdio.h>
int x,y ;
void lire (void) ; /*prototype de la fonction lire*/
int somme(void) ; /*prototype de la fonction somme*/
void main()
{
clrscr() ;
lire() ;
printf (" \n la somme de %d et %d est égal à %d",x,y,somme()) ;
getch() ;
}
void lire()
{printf(" Entrer les valeur à sommer : ") ;
scanf("%d %d",&x,&y) ;
}
int somme()
{return(x+y) ;}
33
Langage C
{ int i=2,j=3 ;
echange(i,j) ;
}
void echange(int a,int b)
{ int k /*variable intermidiare*/
k=a;
a=b;
b=k;
}
À l’exécution on a:
Avant l’appel les valeurs sont i=2 et j=3
A la fin de la fonction les valeurs sont 3 et 2
Après l’appel les valeurs sont i=2 et j=3
Il n’y a que recopie des valeurs de i et j (2 et 3) vers les variables locales de la fonction mais
après l’appel il n’y a aucune modification de i et j.
À l’exécution on a:
Avant l’appel les valeurs sont i=2 et j=3
A la fin de la fonction les valeurs sont 3 et 2
Après l’appel les valeurs sont 3 et 2
5.6 Les Macros-Fonctions
Les macro fonctions sont des instructions prédéfinis en C. dans un programme source, une
macro fonction substitue à une instruction ou une séquence d’instructions du langage C. le
traitement des macro fonctions se fait par le compilateur.
La définition de macros grâce au symbole #define
Exemple :
#define carre(a) a*a le préprocesseur remplacera dans la suite carre(x) par x*x
#define SUP(a,b) (a>b) ?a :b
34
Langage C
Chapitre 6
Structures et Unions
Une structure est un objet composé de plusieurs champs qui sert à représenter un concept.
Les types des champs type1, type2,…, typeN peuvent être différents ou identiques.
Remarques :
• la dernière accolade doit être suivi d’un point virgule
• Les champs peuvent être de n’importe quel type hormis le type de la structure dans
laquelle elles se trouvent
Exemples :
struct date
{
int jour ;
int mois ;
int an ;
};
struct Mastructure
{ int Age;
char Nom[12];
float Moyenne;
struct Autre structure StrucBis ;
35
Langage C
struct nom_structure
{ Type1 nom_champ1 ;
Type2 nom_champ2 ;
Type3 nom_champ3 ;
….. ….. ……. ;
TypeN nom_champN ;
}var1, var2, …… ;
var1, var2, ….. Sont des variables associées à la structure nom_structure
Exemple :
struct date
{int jour ;
int mois ;
int an ;} départ,arrivée,naissance ;
Il est possible de déclarer séparément la structure et les variables associées. Dans ce cas, il
faut d’abord déclarer la structure puis les variables après.
Exemple :
Une fois la structure date déclarée, ont peut écrire les déclarations suivantes :
struct date départ, arrivée, naissance ;
Utilisation de structures
Les structures peuvent être manipulées champ par champ ou dans leur ensemble.
36
Langage C
Chaque champ d’une structure peut être manipulé comme n’importe quelle variable du type
correspondant. La désignation de champ se note en faisant suivre le nom de la variable
structure d’un point puis du nom de champ.
Il est possible d’affecter à une structure le contenu d’une autre structure défini à partir du
même modèle. Ainsi si la structure s1 et s2 sont définie suivant le même modèle, nous
pouvons écrire s1=s2 ;
Exemple :
Si départ et arrivée sont deux variables de la structure date déjà définie nous pouvons écrire
départ=arrivée ;
Remarque :
Lorsqu’on dispose d’un pointeur sur une structure, l’écriture diffère un peu en s’écrivant :
Nom_de_variable pointeur->nom_de_champ; où la flèche est construite avec le signe
moins (-) et le signe supérieur (>).
Exemple :
struct date
{ int jour ;
int mois ;
int an ;} ;
struct date date1,*p ;
date1 est une variable structure de type date.
p est un pointeur sur une variable structure de type date
On peut écrire
date1.mois=12 ;
P->jour=15 ; /*equivalent à (*p).jour=15 ; */
La déclaration typedef permet de définir des « types synonymes ». Elle s’applique à tous les
types et en particulier aux structures.
37
Langage C
Exemples :
Typedef int entier ; : signifie que entier est synonyme de int. Dans ce cas :
int n,p ; est équivalent à entier n,p ;
Une définition de ce type sert à définir un modèle de structure associé aux structures
nom_str1,nom_str2,…………… ;
Exemples :
Typedef struct temps
{ int champ1 ;
int champ2 ;
int champ3 ;
}date, time ;
date et time (appelé des images de structures) sont des types de structures équivalents à
struct temps.
2 Les unions
2.1 Définition :
L’union est la déclaration de différentes variables qui occupent toutes la même place en
mémoire. Le système alloue un emplacement mémoire tel qu’il pourra contenir la variable de
plus grande taille
La syntaxe de déclaration d’une union est la suivante :
union nom_union
{ Type1 var1 ;
Type2 var2 ;
Type3 var3 ;
….. ……. ;
TypeN varN ;
} u;
Cette déclaration réserve un emplacement qui pourra contenir l’une des variables var1, var2,
…. varN.
2.2 Accès aux champs
Pour accéder à l’une des variables de l’union, on utilise la syntaxe :
38
Langage C
nom_union.nom_variable ;
Exemple :
union u {
char c ;
float f ;
long l ;}j;
j.c=’a’;
j.f=15.4; /* après cette déclaration, on a plus le caractère ‘a’ dans c */
39
Langage C
Chapitre 7
La gestion des fichiers
Le fichier est le seul moyen utilisé pour stocker les informations sur ordinateurs et
sauvegarder des résultats nécessitant une réutilisation ultérieure.
Le terme fichier, désigne ici un ensemble d’informations, situé sur une mémoire de masse
(disque dure, disquette, CD ROM,…). Néanmoins, tous les périphériques, qu’ils soient
d’archivage (disque, disquette, …) ou de communication (clavier écran imprimante,…)
peuvent être considérés comme un cas particulier de fichiers.
Schéma général de gestion d’un fichier :
Déclaration
Ouverture
Manipulation (Lecture/écriture)
Fermeture
7.1 Ouverture et fermeture d’un fichier
7.1.1 Déclaration d’un fichier
Pour pouvoir utiliser un fichier (l’ouvrir, écrire, lire,…) il faut déclarer un pointeur sur un
objet de type FILE (le type FILE est une structure définie dans le fichier <stdio.h>
Syntaxe : FILE *nom_fichier ;
Exemple : FILE *f ;
Cette déclaration ne réserve qu’un emplacement pour un pointeur. C’est la fonction fopen qui
créera effectivement une telle structure et qui en fournira l’adresse en résultat.
7.1.2 Ouverture d’un fichier
Pour travailler sur un fichier, il est nécessaire de l’ouvrir (association d’un objet extérieur ( le
fichier) au programme en cours d’exécution. La fonction fopen permet de réaliser l’ouverture
d’un fichier selon la syntaxe suivante :
FILE * nom_fichier ;
nom_fichier =fopen(nom_physique_du_fichier,Mode);
nom_physique_du_fichier : chaîne de caractère constante indiquant le nom du fichier sur le
disque.
Mode : chaîne de caractère constante indiquant le mode d’ouverture du fichier (lecture,
écriture/ajout) et (binaire/texte).
La fonction fopen retourne un pointeur sur un objet de type FILE, elle retourne l’adresse du
fichier ouvert ou un pointeur NULL si le fichier n’a pas pu être ouvert (problèmes d’existence
de fichiers ou de droits d’accès).
Exemple: f= fopen("c:\\test.txt", "rt");
Si on n’utilise pas le caractère t dans le mode d’ouverture. "r" implique fichier texte
implicitement.
Le type d’ouverture est spécifié à partir d’un mode de base et de compléments
"r" le fichier est ouvert en lecture. Si le fichier n’existe pas, la fonction ne le crée pas.
"w " le fichier est ouvert en écriture. Si le fichier n’existe pas, la fonction le crée. Si le fichier
existe la fonction le vide.
"a" le fichier est ouvert en ajout. Si le fichier n’existe pas, la fonction le crée. Les écritures
auront lieu à la fin du fichier.
Le type d’ouverture peut être agrémenté de deux caractères qui sont :
"b" le fichier est considéré en mode binaire. Il peut donc contenir des données qui sont
transférées sans interprétation par les fonctions de la bibliothèque.
"+ " le fichier est ouvert dans le mode complémentaire du mode de base.
Par exemple s’il est ouvert dans le mode “r+“ cela signifie qu’il est ouvert en mode lecture et
plus, soit lecture et écriture.
40
Langage C
La combinaison des modes de base et des compléments donne les possibilités suivantes :
“r+“ le fichier est ouvert en lecture plus écriture. Si le fichier n’existe pas, la fonction ne le
crée pas. Le fichier peut être lu, modifié et agrandi.
“w+“ le fichier est ouvert en écriture plus lecture. Si le fichier n’existe pas, la fonction le
crée. Si le fichier existe, la fonction le vide. Le fichier peut être manipulé en écriture et
lecture.
“a+“ le fichier est ouvert en ajout plus lecture. Si le fichier n’existe pas, la fonction le crée.
Les écritures auront lieu à la fin du fichier. Le fichier peut être lu.
“rb“ le fichier est ouvert en lecture et en mode binaire. Si le fichier n’existe pas, la fonction ne
le crée pas.
“wb“ le fichier est ouvert en écriture et en mode binaire. Si le fichier n’existe pas, la fonction
le crée. Si le fichier existe, la fonction le vide.
“ab“ le fichier est ouvert en ajout et en mode binaire. Si le fichier n’existe pas, la fonction le
crée. Les écritures auront lieu à la fin du fichier.
“r+b“ou “rb+“ le fichier est ouvert en lecture plus écriture et en mode binaire. Si le fichier
n’existe pas, la fonction ne le crée pas. Le fichier peut être lu, modifié et agrandi.
“w+b“ ou “wb+“ le fichier est ouvert en écriture plus lecture et en mode binaire. Si le fichier
n’existe pas, la fonction le crée. Si le fichier existe, la fonction le vide. Le fichier peut être
écrit puis lu et écrit.
“a+b“ ou “ab+“ le fichier est ouvert en ajout plus lecture et en mode binaire. Si le fichier
n’existe pas, la fonction le crée. Les écritures auront lieu à la fin du fichier.
7.1.3 Fermeture d’un Fichier :
fclose(nom_fichier) ;
Exp : fclose(f) ;
Exemple : un programme qui se contente d’afficher si un fichier de nom lu par le clavier a pu
être ouvert ou non.
#include <stdio.h>
void main ()
{ FILE *f;
char nom_f[40] ;
printf(" donner le nom du fichier : ") ;
gets(nom_f ) ;
f=fopen(nom_f, " r ") ;
if(f==NULL)
printf(" impossible d’ouvrir le fichier %s\n ",nom_f);
else
printf(" %s a été ouvert avec succés ", nom_f) ;
}
41
Langage C
42
Langage C
Retour :
Une valeur positive si l’écriture s’est correctement déroulée.
Condition d’erreur :
En cas d’erreur d’écriture, la fonction retourne EOF.
La fonction fputs() écrit une ligne dans le fichier. Le tableau de caractère doit être terminé par
un caractère nul (‘\0’). Il faut mettre explicitement la fin de ligne dans ce tableau pour qu’elle
soit présente dans le fichier.
Exemple :
char *s=”ma chaine”;
fputs(s,f) ;
43
Langage C
fgets(chaîne,N,f) ; lit une chaîne de maximum N caractères à partir d’une seule ligne
44
Langage C
fsource=fopen(nomfs, “rb“) ;
if (fsource==NULL)
printf(“\n impossible de créer le fichier source %s“,nomfs) ;
else
{ fdestination=fopen(nomfd,“wb“) ;
if( fdestination==NULL)
Printf (“\n impossible de créer le fichier %s“,nomfd) ;
else
{
While(!feof(fsource))
{fread(&indi,taille,1, fsource);
fwrite(&indi,taille,1,fdestination);
}}
fclose(fsource);
fclose(fdestination) ;
}
getch() ;
}
int fseek(FILE *fp, long int deplacement, int origine) ;cette fonction permet un accès
direct au niveau de l’octet. Elle initialise le positionnement pour la prochaine lecture. La
45
Langage C
valeur du paramètre déplacement désigne la nouvelle valeur que l’on souhaite donner au
pointeur en opérant un déplacement par rapport à origine :
- Si origine vaut 0 ou SEEK_SET, le déplacement se fera par rapport au début du
fichier.
- Si origine vaut 1 ou SEEK_CUR, le déplacement se fera par rapport au pointeur
courant (position courante)
- Si origine vaut 2 ou SEEK_END, le déplacement se fera depuis la fin de fichier
Les valeur SEEK_SET, SEEK_CUR et SEEK_END sont prédéfinies dans le fichier unistd.h
Si le système d’exploitation ne peut pas positionner le pointeur dans le fichier, la fonction
retourne -1, sinon elle retourne 0.
Exemple1 :
fseek(f,20,0) ;char c=fgetc(f) ;
Exemple2 :
fseek(f,sizeof(str)*10,0) ;
str v;
fread(&v,sizeof(str),1,f);
1.1.2 La fonction rewind
void rewind(FILE *fichier) ; cette fonction est identique à fseek(fichier,0L, 0) ; elle
positionne le pointeur au début du fichier.
46