Académique Documents
Professionnel Documents
Culture Documents
1
Plan
• CHAPITRE 1. ELEMENTS DE BASE
• CHAPITRE 2. LES INSTRUCTIONS
• CHAPITRE 3. LES FONCTIONS
• CHAPITRE 4. OBJETS STRUCTURES
• CHAPITRE 5. POINTEURS ET TABLEAUX
• GENIE LOGICIEL
2
Bibliographie
• Braquelaire J.P., Méthodologie de la programmation en
langage C – Principes et applications, Masson, 1993.
• Delannoy C., le livre du C – Premier langage, Eyrolles.
• Drix Ph., Langage. Norme ANSI, Masson, 1994.
• Kernighan B.W., Ritchie D.M., le langage C (ANSI),
Masson, 1992.
• Rifflet J.M., La programmation sous UNIX (chapitre 8),
Ediscience International, 1994.
• Roberts E.C. The Art and Science of C, Addison Wesley,
1995.
3
CHAPITRE I
ELEMENTS DE BASE
4
Présentation
• Le langage C a été crée par une petite équipe
d’informaticiens pour satisfaire ses besoins internes,
principalement l’écriture d’un système d’exploitation
(Unix).
• Les concepteurs de C ont notamment voulu:
– Avoir un langage C réduit et simple
– Faire confiance au programmeur
5
I. Structure générale d’un programme C
6
Exemple
#include <stdio.h>
#define N 10
float calcul(float x, float y) {
float z = x+y;
return z;
}
void main( ) {
float a;
a = calcul(N, N+1);
printf(“%f”, a);
}
7
Structure générale d’un programme C
8
Structure générale d’un programme C
compilateur compilateur
Edition de liens
Fichier exécutable
9
II. Préprocesseur
10
Préprocesseur
1) Inclusion de fichiers
include est utilisé pour l’inclusion de fichiers.
• Inclusion de fichiers dans d’autres fichiers, par exple
pour insérer dans chacun des fichiers séparés qui
constituent un programme l’ensemble de leurs
déclarations communes.
• 2 formes :
#include “nom_de_fichier“
Forme générale. Le fichier spécifié est inséré à l’endroit
où la directive figure avant que la compilation ne
commence.
“nom_de_fichier“ doit être un nom complet.
11
Préprocesseur
#include <nom_de_fichier>
Ici le nom est incomplet puisqu’il s’agit d’un fichier de la
bibliothèque standard.
• Exemple
#include <stdio.h>
#include “/fall/LangageC/tri.h"
12
Préprocesseur
13
Préprocesseur
• Exemple
#define PI 3.14159
#define N 100
|
|
int t[N] → int t[100]
x = 2 * PI * r → x = 2 * 3.1415 * r
Erreur souvent commise : point-virgule (;) après
#define, #include
14
Préprocesseur
15
III. ELEMENTS LEXICAUX
• Notion d’identificateur : même qu’en Pascal
Suite de lettres et de chiffres contigüs, premier-lettre
• Commentaires :
// sur une ligne
/*
*/ sur plusieurs lignes
• En C, les minuscules sont différentes des majuscules
• Quelques mots réservés
int char float double struct typedef
sizeof long short unsigned void extern
case default switch do for while else
16
ELEMENTS LEXICAUX
• Constantes entières
– Notation décimale
-20 1 360
– Notation octale (base 8). Commence par 0 (Zéro)
0761 06
– Notation hexadécimale. Commence par 0x ou 0X
0xA63 0xF56
Exemple : 3 manières d’écrire le même nombre
27 033 0x1B
• Constantes réelles
– Notation fixée
-1.64 166.7
– Notation flottante
35E8 -3.14E-10
17
ELEMENTS LEXICAUX
18
ELEMENTS LEXICAUX
• On peut faire figurer n’importe quel caractère, même non
imprimable dans une constante caractère ou chaîne de
caractères en utilisant les combinaisons suivantes
appelées séquences d’échappement :
– \n nouvelle ligne
– \t tabulation
– \a signal sonore
– \\ antislash
– \? ?
– \’ ‘
– \“ “
– \abc le caractère ayant pour code le nombre octal abc
Exemple : printf(“Bonjour\n“);
Chaîne “A\033B\”\\E” suite des caractères A, escape, B, “, \ et E 19
ELEMENTS LEXICAUX
• Exemple
#include <stdio.h>
main() {
char a, b, c, d;
a = ‘A’; b = 65; c = ‘\101’; d = ‘\x41’;
printf(‟%c %c %c % \n”, a, b, c, d);
printf(‟%c %d %o %x \n”, a, a, a, a);
}
AAAA
A 65 101 41
20
IV. TYPES FONDAMENTAUX
• Le type char
– Caractères représentés par leurs codes ASCII
– Signification d’un char en C différente de celle d’un char en
Pascal
• Le type int
– Entiers; 2 ou 4 octets ( selon les machines)
• Le type float
– Nombres réels à virgule flottante; 4 octets
• Le type double
– Nombres réels à virgule flottante en double précision; 8 octets
• Des variantes utilisent les préfixes modificateurs :
signed, unsigned, short (short int), long (long int)
21
TYPES FONDAMENTAUX
unsigned short 16 bits 0…216-1
short 16 bits -215…215-1
unsigned long 32 bits 0…232-1
long 32 bits -231…231-1
• Le type booléen n’existe pas en C
expr = 0 faux
expr ≠ 0 vrai
expr expr « vrai » (expr ) != 0
Exemple : x < 3 vaut 0 ou 1 selon que x est inférieur à 3 ou non
22
TYPES FONDAMENTAUX
• Déclaration de variables et initialisation
int x, y;
char ch;
float valeur;
Une variable peut être initialisée lors de sa déclaration
int t =0;
int niter = 16 * 15;
char fin = ‘f’;
23
V. LES TABLEAUX
• Tableau : arrangement de variables identiques et
contiguës
• Définition : type identificateur [taille]
la taille doit être calculable pendant la compilation
ex : int table[100];
int x, t[4], y;
t[i] = 0 ( affectation )
Remarques
1) le premier indice vaut toujours 0 (t[0])
2) taille = nombre de composantes
3) Il n’y a pas de contrôle de débordement
t = & t[0] t = adresse de t[0]
24
LES TABLEAUX
• Tableaux à plusieurs dimensions
• Définition : type identificateur[nb_lignes][nb_colones]
• Accès identificateur[i][j]
• Exemple constantes
#define N 10
float m [N][N+2]
m[i][j]
25
VI. LES EXPRESSIONS
• Expression – texte correct qui détermine une valeur
• Instruction – texte qui détermine une action à faire
• Toute expression possède au moins 2 attributs : un type
et une valeur.
exemple : Si i est un entier de valeur 10, 2*i+3 a pour
type entier et pour valeur 23.
• Deux sortes d’expressions :
– Lvalue (expressions signifiant « le contenu de »
expressions représentant un emplacement de la mémoire. La
valeur de l’expression est alors définie comme le contenu de cet
emplacement. Cas des variables, des composantes des
tableaux.
Une lvalue possède 3 attributs : adresse, type, valeur
Ex : x, t[2*i+4] 26
LES EXPRESSIONS
– Rvalue « la valeur de »
Ces expressions ont un type et une valeur, mais pas d’adresses
Ex : 2*x+3, 12
• Expressions pures et expressions à effet de bord
– Expressions pures
ex : 2*x+3
– Expressions avec effet de bord
ex : i++ (vaut i et remplace i par i+1)
y = 2*x+3 (modifie y)
27
VII. LES OPERATEURS
• Opérateurs arithmétiques : +, -, *, /, %
5/2 = 2; 5.0/2 = 2.5
• Opérateurs de comparaison : ==, !=, <, <=, >, >=
– Ils sont prioritaires par rapport à “et“ et “ou“.
• Affectation
expr 1 = expr2 (expr1 – lvalue, expr2 – rvalue)
Considérée comme une expression. Peut ainsi figurer comme
opérande dans une expression. Il est ainsi possible d’écrire en C :
i = j = k = 0 i = (j = ( k = 0))
Ex :
c = getchar( );
while ( c != ‘f’) {
t[nbcars] = c;
nbcars = nbcars +1;
c = getchar( ); 28
}
LES OPERATEURS
• L’affectation étant une sorte d’expression, ce programme
peut s’écrire :
while (( c = getchar()) != ‘f’) {
t[nbcars] = c;
nbcars = nbcars+1;
}
• Opérateurs d’affectation étendues (élargies)
C propose des combinaisons puissantes d’opérateurs,
dans le cas où l’opérande à gauche du signe= se
retrouve à droite.
expr1 += expr2 expr1 = expr1 + expr2
29
LES OPERATEURS
• De manière générale, si expr1 et expr2 sont des expressions
expr1 op= expr2 expr1 = (expr1) op (expr2)
p *= x p = p * x
n /= 2 n = n /2
• Opérateurs d’incrémentation et de décrémentation
Il existe deux opérateurs unaires ++ différents : l’un est
postfixé (écrit derrière l’opérande), l’autre est préfixé (devant)
– Post-incrémentation
Format : exp++
exp doit être de type numérique (entier ou flottant) ou pointeur.
Cette expression a le même type que exp, le même effet de bord que
celui de l’affectation exp = exp + 1 et a la valeur de exp avant
l’évaluation de exp++
30
LES OPERATEURS
– Pré-incrémentation
Format : ++exp
Ici l’expression a la même valeur que exp après l’évaluation
Exemples
y = x++ { y = x; x = x + 1; }
y = ++x { x = x+1; y = x; }
Il en est de même des opérateurs –
• Expressions conditionnelles
expr1 ? expr2 : expr3
expr1 est d’abord évaluée
Si sa valeur ≠ 0, expr2 est évaluée et définit la valeur de
l’expression conditionnelle. Dans ce cas, expr3 pas
évaluée. Sinon expr3 est évaluée et définit la valeur de
l’expression conditionnelle, expr2 pas évaluée. 31
LES OPERATEURS
• Exemple : y = (x != 0) ? (1/x) : maxfloat
abs = x>=0 ? x : -x
Macros avec arguments
• Les opérateurs logiques
Opérateurs && et ||
Les expressions dans lesquelles figurent ces opérateurs
sont évaluées de gauche à droite, et l’évaluation cesse
dès que la véracité ou la fausseté du résultat est établie.
&& est prioritaire sur ||, mais tous deux s’appliquent après
les opérateurs de comparaison et d’égalité
ex : if (a < b && a < c) a = 0;
32
LES OPERATEURS
• Changement de type
conversion explicite par l’opérateur de cast
(nom de type) expression
ex : (int) c;
(int)2.35 → 2
(float) 2 → 2.0
conversions utiles
1) entier → flottant
2) flottant → entier
33
LES OPERATEURS
• Opérateur sizeof
Donne la taille en octets
sizeof (type); sizeof(expression);
renvoie la taille en octets du type donné ou du type de
l’expression
sizeof(int)
sizeof(t) = taille du tableau t
sizeof(t) / sizeof(t[0]) = nombre de composantes de t
• Opérations bit à bit
Opérations non abstraites
Opération abstraite : ne fait pas intervenir les
particularités du langage 34
LES OPERATEURS
• Complément à 1 ~
ex expr 10101100
~ expr 01010011
• & et
• | ou
• ^ ou exclusif (xor)
ex 0011 0011 0011
& | ^
0101 0101 0101
0001 0111 0110
35
LES OPERATEURS
• S’appliquent à des entiers (char, int, …)
• Forcer un ou plusieurs bits à 0
char c; 13 0…01101
c = 13 & 3 3 0…00011
0…00001 -> 1
• Forcer un ou plusieurs bits à 1
char c; 13 0…01101
c = 13 | 3 3 0…00011
0…01111 -> 15
• Inverser un ou plusieurs bits
char c; 13 0…01101
c = 13 ^ 3 3 0…00011
0…01110 -> 14 36
LES OPERATEURS
• << décalage à gauche
• >> décalage à droite
ex expr1 b1b2b3b4
expr = expr1 << 1 b2b3b40
• Opérateur séquentiel (Opérateur virgule)
syntaxe e1, e2
Permet de regrouper plusieurs expressions en une seule
L’expression possède le type et la valeur de e2
Le plus souvent utilisé dans les boucles "for"
37
LES OPERATEURS
• Opérateur d’adressage
Donne l’adresse d’une variable ou d’une expression qui
est une lvalue
Format : &exp
int i, *p;
p = &i; i et *p désignent le même objet
Utilisé dans scanf(“%d%f“, &i, &t[j]);
• Opérateur de sélection
. x.info
-> x -> info
à revoir dans les structures
38
LES OPERATEURS
Opérateur Symbole Exemple Associativité
indexation [] t[i][j] gauche
champs de structure . -> c.reel p->imag gauche
appel de fonction () max(t) gauche
négation logique ! !x droite
négation bit à bit ~ ~x droite
incrémentation ++ i++ ++i droite
décrémentation -- i-- --i droite
moins unaire - -2 droite
plus unaire + +2 droite
conversion (type) (int) droite
taille sizeof sizeof(int) sizeof(p) droite
adresse & &x droite
indirection * *p droite 39
LES OPERATEURS
Opérateur Symbole Exemple Associativité
multiplication * x*y gauche
division / x/y gauche
modulo % x%y gauche
Addition + x+y gauche
soustraction - x-y gauche
décalage à gauche << x << 4 gauche
décalage à droite >> x >> n gauche
opérateurs relationnels < <= > >= x <= 0 x > y gauche
opérateurs d’égalité- == != x ==y x != 0 gauche
inégalité
et bit à bit & x&b gauche
ou exclusif bit à bit ^ x^y gauche
ou bit à bit | x|y gauche 40
et logique && (x ==0) && (y>0) gauche
LES OPERATEURS
Opérateur Symbole Exemple Associativité
ou logique || (x ==0) || (y>0) gauche
expression conditionnelle ?: (x > 0)? x : -x droite
affectation = x =1 droite
affectation étendue += -= *= /= x %= 1 y += 1 droite
&= ^= |= z <<= 5
<<= >>=
composition d’expressions , x = 1, b = x+1; gauche
z += 10
Priorité des opérateurs : décroissante par niveau et du haut vers le bas
Associativité des opérateurs (indique l’ordre des opérations si on omet les ( ))
Associativité gauche : x+y+z = ((x+y) + z)
Associativité droite : x = y = z = (x = (y = z)) 41
IX. LES ENTREES-SORTIES
ELEMENTAIRES
#include <stdio.h> // utilisation des fonctions d’e/s
• Entrées-sorties de caractères
stdin – unité standard d’entrée → clavier
stdout – unité standard de sortie → écran
stderr – unité standard d’affichage des erreurs → écran
• Fonction getchar
Permet d’obtenir le caractère suivant du fichier courant
des entrées. Si la fin du fichier est rencontrée, la valeur
EOF est retournée
42
LES ENTREES-SORTIES
ELEMENTAIRES
int i = 0; char c;
while ((c = getchar()) != EOF && (i < 20)) {
tab[i++] = c;
}
• Fonction putchar
Permet d’envoyer le caractère précisé en paramètre dans
le fichier courant de sortie
for (i = 0; i < 10; i++)
putchar(tab[i]);
43
LES ENTREES-SORTIES
ELEMENTAIRES
• Entrées-sorties formattées
• Fonction printf
Permet d’envoyer dans le fichier courant de sortie, une
édition d’informations formattées
Syntaxe : printf(<format>, p1, p2, …, pn);
<format> - chaîne de caractères contenant du texte et
des spécificateurs de format (% suivi d’un caractère de
conversion)
%d – int %u – unsigned int char %ld – long %lu –
unsigned long
%f – double ou float (notation décimale, 6 chiffres après .) ex
1.234500
%e – double ou float (notation exponentielle, 6 chiffres après .) 44
LES ENTREES-SORTIES
ELEMENTAIRES
%c – char %s – char[ ]
printf(“Bonjour“); printf(“Resultats : %d\n”, res);
printf(“x = %d\t y = %f\n”, x, y);
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.
printf(“%3d“,n); n=4 ☐☐4
n=35 ☐35
printf(“%10.3f“,x); x=22.5621 ☐☐☐☐22.562
45
LES ENTREES-SORTIES
ELEMENTAIRES
• Erreurs souvent commises
– Code de format en désaccord avec le type de l’expression
• Même taille mauvaise interprétation
• Tailles différentes peut afficher n’importe quoi
– Nombre de codes de format ≠ nombre d’expressions de la liste
• printf(“%d“, a, b);
n’affiche pas b
• printf(“%d %d “, a);
peut afficher n’importe quoi
46
LES ENTREES-SORTIES
ELEMENTAIRES
• Exemple
#include <stdio.h>
main() {
char a, b, c, d;
a = ‘A’; b = 65; c = ‘\101’; d = ‘\x41’;
printf(‟%ch! %ch! %ch! %ch! \n”, a, b, c, d);
printf(‟%c, %d %o %x \n”, a, a, a, a);
}
Ah! Ah! Ah! Ah!
A 65 101 41
47
LES ENTREES-SORTIES
ELEMENTAIRES
• Fonction scanf
Permet de rechercher des informations, selon un format
précisé dans le fichier courant des entrées
Syntaxe : scanf(<format>, &p1, &p2, …, &pn)
Même format que pour printf
%c – char, %d – int, %u – unsigned int, %hd – short int,
%hu – unsigned short, %ld – long int, %lu – unsigned
long, %f – float, %e – float, %lf – double, %le – double,
%s - chaine de caractères
int a, b; float c;
scanf(“%d%d%f“, &a, &b, &c);
48
LES ENTREES-SORTIES
ELEMENTAIRES
• L’information saisie au clavier est rangée dans un emplacement
mémoire appelée le tampon. Ce dernier est exploré par scanf
caractère par caractère. Les séparateurs blancs (dont espace et fin
de ligne jouent un rôle particulier dans les données. Il existe un
pointeur qui précise le prochain caractère à prendre
int a, b; char c;
scanf(“%d%d“, &a, &b);
53☐42⏎ a=53, b=42
☐53☐☐42☐☐⏎ a=53, b=42
53
⏎
☐42⏎ a=53, b=42
scanf(“%c%d“, &c, &a);
b75⏎ c=b, a=75
b☐☐75⏎ c=b, a=75 49
LES ENTREES-SORTIES
ELEMENTAIRES
scanf(“%d%c“, &a, &c);
25☐d⏎ a=25, c=‘ ‘
• Gabarit d’affichage
scanf(“%3d%3d“, &a, &b);
53☐42⏎ a=53, b=42
☐☐☐☐☐48523 a=485,b=23
53⏎ 42⏎ a=53, b=42
• Rôle d’un espace dans le format
– Un espace entre deux codes de format demande à scanf de faire
avancer le pointeur au prochain caractère différent d’un
séparateur
scanf(“%d☐%c“, &a, &c);
25☐d⏎ a=25, c=‘d’
25☐☐☐d⏎ a=25, c=‘d’
50
25⏎d⏎ a=25, c=‘d’
LES ENTREES-SORTIES
ELEMENTAIRES
• Entrées-sorties de lignes de caractères
• Fonction puts
Ecrit sur la sortie standard la ligne fournie en paramètre.
Le caractère ‘\n’ est automatiquement ajouté après le
dernier caractère de la ligne
puts(“Bienvenue“);
51
LES ENTREES-SORTIES
ELEMENTAIRES
• Fonction gets
Lit une ligne à partir de l’entrée standard et la mémorise
dans une zone réservée par l’appelant en la complétant
par ‘\0’.
char buf[20]; int i =0;
gets(buf);
while(buf[i] != ‘\0’) {
putchar(buf[i]);
i = i + 1;
}
52
CHAPITRE 2. LES
INSTRUCTIONS
53
LES INSTRUCTIONS
• Le bloc
Suite de déclarations et d’instructions encadrée par les
deux accolades { et }
{ déclaration … déclaration …instruction … instruction }
exemple
if (t[i] > t[i+1]) { Rq : optimisation de l’espace
int w; if (----) {
w = t[i]; int i;
t[i] = t[i+1]; …
t[i+1] = w; } else {
} float x
…
} 54
LES INSTRUCTIONS
• Etiquettes et instruction
Format : etiquette : instruction
une étiquette est un identificateur
goto etiquette;
transfère le contrôle à l’instruction préfixée par l’étiquette
A ne pas utiliser, sauf dans certains cas
for (--------) {
for (---- -- -)
for(---------)
if (-----) goto sortie;
….
sortie : ….
} 55
LES INSTRUCTIONS
• Instruction « if … else »
Format : if (expr) instr1 else instr2
if (expr) instr1
if (x != 0) y = A/x;
if (c >= ‘0’ && c <= ‘9’) printf("chiffre“);
• Instruction “while” et “do while”
Syntaxe while(expression)
instruction
c = ‘A’;
while(c <= ‘Z’) {
putchar(c);
c = c + 1;
} 56
LES INSTRUCTIONS
• Syntaxe do
instruction
while(expression);
instruction est exécutée au moins une fois
do {
printf(“donnez un nb > 0 :“);
scanf(“%d”, &n);
} while ( n <= 0);
63
LES INSTRUCTIONS
Exemple : on compte la fréquence de chaque chiffre et des caractères blancs
dans un texte
int nb_blancs = nb_autres = 0;
for (i = 0; i < 10; i++)
nb_chiffre[i] = 0;
while ((c = getchar()) != EOF)
switch(c) {
case ‘0’ :
case ‘1’ :
case ‘2’ :
case ‘3’ :
case ‘4’ :
case ‘5’ :
case ‘6’ :
case ‘7’ :
case ‘8’ :
case ‘9’ : nb_chiffre[c - '0']++; break;
case ' ‘ :
case '\n‘:
case '\t‘ : nb_blancs++; break;
default :
nb_autres++; 64
}
LES INSTRUCTIONS
• Instructions « break » et « continue »
Dans la portée d’une structure de contrôle (for, while, do,
switch), l’instruction break provoque l’abandon de la
structure et le passage à l’instruction suivante
2 4 6 8...
.
.
.
9 18 27 36 …
2) Ecrire un programme C qui affiche m tables de multiplication pour
les entiers de 1 à m avec n éléments dans chaque table. On
demandera m ≤ 20.
68
Exemple 1 : exercice d’application
#include<stdio.h>
int main() {
int i,j,n,m;
scanf("%d",&n);
do{
} while(m>20); 69
Exemple 1 : exercice d’application
/* Impressions des tables */
printf("------------------- \n");
for(i=1;i<=n;i++) {
for(j=1;j<=m;j++) {
printf("%d \t",i*j);
}
/* Le symbol \t sert a faire des espaces blancs */
printf("\n");
#include <stdio.h>
#include <math.h>
void main() switch(n) {
{ double a, b, c, x1, x2, delta; case 0 : printf(“Aucune racine”); break;
int n; case 1 : printf(“Une racine double: %f“, x1);break;
printf (“a = ? ”); scanf(‟%f”, &a); case 2 : printf(“Deux racines: %f %f“, x1,x2);break;
printf( “b = ? ”); scanf(‟%f” , &b); }
printf( “c = ? ”); scanf((‟%f”, &c); }
delta = b*b–4*a*c;
if (delta < 0) n=0;
else if (delta == 0) {
x1 = -b / (2 * a);
n=1; }
else {
x1 = (-b + sqrt(delta)) / (2 * a);
x2 = (-b – sqrt(delta)) / (2 * a);
n=2;
} 71
CHAPITRE 3. LES FONCTIONS
72
LES FONCTIONS
• 1) Définition, déclaration et appels
Il existe 2 syntaxes pour le C : C original et C ANSI.
Définition d’une fonction en C ANSI
type ident(declaration ident,…, declaration ident)
instruction bloc protototype de la fonct
float puissance(float x, int n) {
int i; float p = 1;
Arguments formels
for (i = 0; i < n; i++)
p *= x;
return p;
}
73
LES FONCTIONS
Arguments effectifs
• Exemple d’appel : v = puissance(5,2);
v = 2 * puissance (4*u + 5, k) + 3;
74
LES FONCTIONS
#include <stdio.h>
float puissance(float x, int n) {
int i; float p = 1;
for (i = 0; i < n; i++)
p *= x;
return p;
}
void main() {
float k, v;
int m;
printf(‟Calcul de la puissance: Entrez le nombre et l’exposant ”);
scanf(‟%f %d”, &k,&m);
v = puissance(k,m);
printf(‟Resultat : %f”,v);
} 75
LES FONCTIONS
#include <stdio.h>
float puissance(float,int);
void main() {
float k, v;
int m;
printf(‟Calcul de la puissance: Entrez le nombre et l’exposant ”);
scanf(‟%f %n”, &k,&m);
v = puissance(k,m);
printf(‟Resultat : %f”,v);
}
float puissance(float x, int n) {
int i; float p = 1;
for (i = 0; i < n; i++)
p *= x;
return p; 76
}
LES FONCTIONS
2) Allocation et durée de vie des variables
– Les variables globales sont toujours statiques, i.e. permanentes : existent
pendant toute la durée de l’exécution
– Les variables locales et les arguments formels sont automatiques
80
LES FONCTIONS
int longueur(chaine de caracteres s) {
int i = 0;
while(s[i] != ‘\0’)
i++;
return i;
}
Peut être concrétisé par :
int longueur( char s[80] )
int longueur( char s[ ] )
int longueur ( char *s)
Si t est un tableau de char et p l’adresse d’un char, on peut avoir les 3 appels
l1 = longueur( t );
l2 = longueur( p );
l3 = longueur(“Bonjour“);
81
LES FONCTIONS
• Arguments par adresse
Les arguments de type simple (int, char, pointeur…) ou
bien des struct ou des unions sont toujours passés par
valeur.
C ne prévoit pas aucun mécanisme de passage par
adresse : le passage de l’adresse de l’argument doit être
programmé explicitement en utilisant comme argument
un pointeur vers la variable.
82
LES FONCTIONS
Pointeur : variable dont la valeur est l’adresse d’une cellule
de la mémoire
Exemple :
Soit A une variable contenant la valeur 10 et P un pointeur
qui contient l'adresse de A. En mémoire, A et P peuvent
se présenter comme suit:
P
… 5C26 …
3F04 3F06 3F08 A
… 10 …
5C24 5C26 5C28
83
LES FONCTIONS
Opérateur d’adressage &
P = &A;
*P -> A
Déclaration des pointeurs
Syntaxe : type * variable;
char *p;
Lorsque p aura été correctement initialisé, elle
contiendra l’adresse d’un caractère auquel on pourra
avoir accès par *p
84
LES FONCTIONS
int x, y, *px;
x = 10; y = 20;
px = &x;
y = *px + 4;
*px += 10;
85
LES FONCTIONS
#include <stdio.h>
int euclid(int, int, int*);
int main( ) {
int a, b, quotient, reste;
printf(‟ Entrez les coefficients a et b ”);
scanf(‟ %d %d ”, &a, &b);
quotient = euclid( a, b, &reste );
printf(‟ quotient : %d reste : %d ”, quotient,reste);
return(0);
}
int euclid( int num, int denum, int *adreste ) {
*adreste = num % denum;
return( num / denum );
}
Déduction : les tableaux sont passés par adresse
86
Fonction retournant
plusieurs résultats
- nombre de racines d’une équation du second degré (via return),
- racines de cette même équation (via transmission par adresse),
#include <stdio.h>
#include <math.h>
int racines(double a, double b, double c, double *r1, double *r2)
{
double delta; void main()
delta = b*b–4*a*c; { double a, b, c, x1, x2, n;
if (delta < 0) return(0); printf (“a = ? ”); scanf(‟%f”, &a);
if (delta == 0) { printf( “b = ? ”); scanf(‟%f” , &b);
*r1 = -b / (2 * a); printf( “c = ? ”); scanf((‟%f”, &c);
return(1); } n = racines(a, b, c, &x1, &x2);
*r1 = (-b + sqrt(delta)) / (2 * a); switch(n) {
*r2 = (-b – sqrt(delta)) / (2 * a); case 0 : printf(“Aucune racine”); break;
return(2); case 1 : printf(“Une racine double: %f“, x1);break;
} case 2 : printf(“Deux racines: %f %f“, x1,x2);break;
}
}
87
Exemple de fonction
manipulant un tableau
#include <stdio.h>
// Prototype de la fonction d'affichage
void affiche(int *tableau, int tailleTableau);
int main()
{
int tableau[4] = {10, 15, 3, 8};
return 0;
}
88
Exemple de fonction
manipulant un tableau
void affiche(int *tableau, int tailleTableau)
{
int i;
for (i = 0 ; i < tailleTableau ; i++)
{
printf("%d\n", tableau[i]);
}
}
Exercice : 1) rajouter la fonction suivante, 2) rajouter une fonction de
saisie du tableau 3) reprendre l’exercice de la page 78
int chercher(int x, int t[], int N) {
int i;
for(i = 0; i < N; i++)
if ( x == t[i]) return i;
return -1;
}
89
4) rajouter ici la fonction « echange » 5) fonction de tri du tableau
LES FONCTIONS
• 4) Arguments en nombre variable
C permet de définir des fonctions dont le nombre
d’arguments n’est pas fixé et peut ne pas être le même
d’un appel à l’autre.
Une fonction avec un nombre variable d’arguments est
déclarée en explicitant quelques arguments fixes, au
moins, suivis d’une virgule et trois points.
Exple int max( short n, int x1, … )
La fonction peut être appelée avec un nombre
quelconque d’arguments effectifs, mais il faut qu’il y en
ait au moins autant qu’il y a d’arguments formels
nommés.
90
LES FONCTIONS
On utilise des macros définis dans <stdarg.h>
• va_list parcours
déclaration de la variable parcours, qui sera utilisé
comme argument dans les appels des macros va_start
et va_arg.
• va_start(parcours, dernier argument)
Initialisation de la variable parcours; dernier argument –
dernier des arguments explicitement nommés
• va _arg(parcours, type)
Parcours des arguments anonymes : le premier appel
donne le premier argument anonyme,…
91
LES FONCTIONS
#include <stdarg.h>
int max ( short n, int x1,…) {
va_list p;
int m, x, i;
m = x1;
va_start(p, x1);
for( i = 1; i < n; i++) {
x = va_arg(p, int);
if ( x > m ) m = x;
}
return m;
}
92
LES FONCTIONS
Appels de cette fonction :
a = max( 3, p, q, r);
b = max( 8, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]);
93
CHAPITRE 4. OBJETS
STRUCTURES
94
OBJETS STRUCTURES
1) Tableaux
• Définition : type identificateur [taille]
la taille doit être calculable pendant la compilation
ex : int table[100];
int x, t[4], y;
t[i] = 0 ( affectation )
Remarques
1) le premier indice vaut toujours 0 (t[0])
2) taille = nombre de composantes
3) Il n’y a pas de contrôle de débordement
t = & t[0] t = adresse de t[0]
95
OBJETS STRUCTURES
• Tableaux à plusieurs dimensions
Définition : type identificateur[nb_lignes][nb_colones]
Accès identificateur[i][j]
Exemple
#define N 10
float m [N][N+2]
m[i][j]
96
OBJETS STRUCTURES
• Initialisation des tableaux
Une variable de type tableau peut être initialisée lors de sa déclaration
Syntaxe : { expression, expression, expression }
Ex : int t[5] = {21,13,45,3,34};
int t[] = {21,13,45,3,34};
int t1[4][4] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int t2[4][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
1230 1234
4560 5678
7890 9000
0000 0000
t1 t2
97
OBJETS STRUCTURES
• Indexation
Soit exp une expression quelconque de type adresse et
ind une expression entière. Par définition, l’expression :
exp[ind] * (exp + ind)
Si on a : type t[100] ou type *t;
on peut écrire : t[0] ou *t
t[i] ou *(t+i)
En C, l’identificateur d’un tableau, lorsqu’il est employé
seul, est considérée comme un pointeur (constant) sur le
début du tableau
98
OBJETS STRUCTURES
• Cas des tableaux à un indice
soit la déclaration : int t[10]
t &t[0]
t + 1 &t[1]
t + i &t[ i]
99
OBJETS STRUCTURES
2) Chaînes de caractères
• Pas de type chaîne de caractères,
• Tableau de caractères qui se termine par ‘\0’
char s[] = "Bonjour " ; -> B o n j o u r \0
char *s = "Bonjour " ;
Manipulation des chaînes
<stdio.h> printf, scanf, gets, puts
Ex :
char lieu[25];
int jour, mois, annee;
printf(" Entrez lieu et date de naissance : \n " );
scanf(" %s %d %d %d ",lieu, &jour, &mois, &annee);
100
OBJETS STRUCTURES
Les fonctions printf et scanf permettent de lire ou d’afficher
simultanément plusieurs informations de type quelconque. En
revanche, gets et puts ne traitent qu’une chaîne à la fois.
De plus, la délimitation de la chaîne lue ne s’effectue pas de la même
façon avec scanf et gets. Plus précisément :
● avec le code %s de scanf, on utilise les délimiteurs habituels (l’espace
ou la fin de ligne). Cela interdit donc la lecture d’une chaîne contenant des
espaces. De plus, le caractère délimiteur n’est pas consommé : il reste
disponible pour une prochaine lecture ;
● avec gets, seule la fin de ligne sert de délimiteur. De plus, contrairement
à ce qui se produit avec scanf, ce caractère est effectivement consommé :
il ne risque pas d’être pris en compte lors d’une nouvelle lecture.
101
OBJETS STRUCTURES
#include <stdio.h>
void main() {
char nom[20], prenom[20], ville[25] ;
printf (”Donnez la ville de residence : ") ;
gets (ville) ;
printf (”Donnez votre nom et votre prénom : ") ;
scanf ("%s %s", nom, prenom) ;
printf ("Bonjour %s %s habitant à ", prenom, nom) ;
puts (ville) ;
}
104
OBJETS STRUCTURES
#include <stdio.h>
donnez un entier et un caractère : abc
#define LG 80
donnez un entier et un caractère : a 125
main()
donnez un entier et un caractère : 12
{
bonjour
int n, compte ;
merci pour 12 b
char c ;
char ligne [LG+1] ;
do
{ printf ("donnez un entier et un caractère : ") ;
gets (ligne) ;
compte = sscanf (ligne, "%d %c", &n, &c) ;
}
while (compte < 2 ) ;
printf ("merci pour %d %c\n", n, c) ;
}
105
OBJETS STRUCTURES
Dans <string.h>, les plus utilisées
s1 = s2 ne copie pas la chaîne s2 dans s1;
on utilise la fonction char* strcpy(char *s1, char*s2)
char a[12];
char b[ ] = Hello;
strcpy(a, b);
strncpy(dest, source, lg) – analogue à strcpy sur lg
caractères
Comparaison : int strcmp(char *s1, char *s2)
0 si s1 = s2
= < 0 si s1 < s2
> 0 si s1 > s2
106
OBJETS STRUCTURES
strncmp(<s>,<t>,lg) – comme strcmp mais sur lg caractères
concaténation : strcat(<s>,<t>) – ajoute <t> à la fin de <s>
strncat(<s>,<t>,n) – ajoute au plus caractères de <t> à la
fin de <s>
int strlen(char *s1) – nbre de caractères de la chaîne sans
le caractère nul
107
OBJETS STRUCTURES
• <stdlib> -> fonctions pour la conversion de nombres en
chaînes de caractères et vice-versa
Chaîne -> nombre
atoi(<s>) - retourne la valeur numérique représentée par <s>
comme int
atol(<s>) - retourne la valeur numérique représentée par <s>
comme long
atof(<s>) - retourne la valeur numérique représentée par <s>
comme double
Nombre chaîne
108
OBJETS STRUCTURES
• Fonctions de classification et de conversion : <ctype.h>
Les fonctions de classification suivantes fournissent un résultat du
type int différent de zéro, si la condition respective est remplie, sinon
zéro.
La fonction : retourne une valeur différente de zéro,
isupper(<c>) si <c> est une majuscule ('A'...'Z')
islower(<c>) si <c> est une minuscule ('a'...'z')
isdigit(<c>) si <c> est un chiffre décimal ('0'...'9')
isalpha(<c>) si islower(<c>) ou isupper(<c>)
isalnum(<c>) si isalpha(<c>) ou isdigit(<c>)
isxdigit(<c>) si <c> est un chiffre hexadécimal
('0'...'9' ou 'A'...'F' ou 'a'...'f')
isspace(<c>) si <c> est un signe d'espacement
(' ', '\t', '\n', '\r', '\f')
109
OBJETS STRUCTURES
Les fonctions de conversion suivantes fournissent une valeur du
type int qui peut être représentée comme caractère; la valeur originale
de <c> reste inchangée:
tolower(<c>) retourne <c> converti en minuscule si <c> est une
majuscule
toupper(<c>) retourne <c> converti en majuscule si <c> est une
minuscule
110
Exemple
#include <stdio.h>
#include <string.h>
void copier(char* ch) {
char chaine[100];
int longueur = strlen(ch);
if (longueur > 99) {
printf( " la chaine est trop longue\n");
return;
}
strcpy(chaine, ch);
chaine[longueur – 1] = ‘2’;
printf( " %s\n ", chaine);
}
void main() {
copier( "Voici la chaine numero 1 ");
}
111
OBJETS STRUCTURES
3) Structures
Variables composées de types différents
Syntaxe : struct nomopt {
declaration
…
declaration
} (ident,…, ident)opt;
Par la suite, struct nom pourra être employé comme type
struct Article {
int numero ;
int qte ;
float prix ;
} art1, art2 ;
112
struct Article art3, art4;
OBJETS STRUCTURES
• Utilisation
art1.numero = 24;
printf( " %d\n ", art1.numero);
scanf(" %f ", &art1.prix);
art1.numero++;
• Affectation globale
Il est possible de faire une affectation globale entre structures de
mêmes types et de mêmes noms
art1 = art2; remplace
art1.numero = art2.numero ;
art1.qte = art2.qte ;
art1.prix = art2.prix ;
//se méfier avec de telles affectation lorsque les champs d’un structure
sont de types pointeur.
113
OBJETS STRUCTURES
Remarque
L’affectation globale n’est pas possible entre tableaux. Elle l’est, par
contre, entre structures. Aussi est-il possible, en créant artificiellement
une structure contenant un seul champ qui est un tableau, de réaliser
une affectation globale entre tableaux.
struct etudiant {
int numero;
char nom[30], prenom[30];
} a, b, c;
struct etudiant d, *p;
a.numero = 7;
p->numero =15;
strcpy(a.nom, “Demba“);
114
OBJETS STRUCTURES
Exercice : Affectation globale (vérification)
Ecrire un programme qui déclare deux étudiants, saisit l’un et ensuite
effectue une affectation globale à l’autre. Ensuite, le programme
affiche l’autre étudiant
• Initialisation
struct Article art1 = { 100, 200, 3000 };
115
OBJETS STRUCTURES
• Structures imbriquées
– struct Point1 {
float x;
float y;
};
struct Point1 p1;
Autres exemples de structures, imbriquées ou avec tableaux
p2.x[0] = 1.8;
r1.phg.x = 1.7;
r2.p[1].x[0] = 3.5;
p2.couleur = 2;
117
OBJETS STRUCTURES
• Tableau de structures
struct date { int jour, mois, annee; }
struct date *p;
struct date d[4];
d[0].jour = 25;
d[2].mois = 12;
p = &d[2];
p -> jour = 25;
p++;
p -> mois = 12;
118
OBJETS STRUCTURES
• Initialisation d’un tableau de structures
struct date {
int jour,
int mois,
int annee;
} DATE [ ] = { { 31, 1, 90}, {27, 2, 91}, {29, 3, 93},
{ 28, 4, 94} };
taille d’un élément du tableau : sizeof (struct date)
taille du tableau : sizeof(DATE);
nbre d’élements du tableau : sizeof(DATE) / sizeof(struct date)
119
OBJETS STRUCTURES
• Passage d’une structure par adresse
struct S {
char nom[20];
int age;
};
void f(struct S *);
main() {
struct S st; void f (struct S *s)
strcpy(st.nom, “FALL“);
{
st.age = 60;
f(&st); strcpy(s ->nom, “DIAW“);
printf(“%s “, st.nom); } 120
}
OBJETS STRUCTURES
• Déclaration « typedef »
homologue de la déclaration type du Pascal
Syntaxe : typedef declaration
typedef float MATRICE[10][10];
MATRICE mat; float mat[10][10];
typedef char TAMPON [80];
typedef long * PTR;
typedef struct pers {
char nom[20];
char prenom[20];
int age;
} PERSONNE;
PERSONNE p; 121
OBJETS STRUCTURES
Une fonction peut rendre des structures comme valeur
typedef struct point {
int x, y;
} POINT;
POINT milieu ( POINT X, POINT Y) {
POINT M;
M.x = (X.x + Y.x) / 2;
M.y = (X.y + Y.y) / 2;
return M;
}
Rq : il est possible de faire l’affectation entre 2 structures
122
OBJETS STRUCTURES
int main( ) {
POINT point_courant;
POINT A = {1, 2};
POINT B = {3, 4};
point_courant = milieu(A, B);
printf(“%d %d”, point_courant.x, point_courant.y);
return 0;
}
Exercice : rajouter la fonction distance qui calcule la
distance euclidienne entre deux points
123
OBJETS STRUCTURES
• 4) Champs de bits
C permet d’utiliser des structures dont les champs, tous
ou seulement certains, sont faits d ’ un nombre
quelconque de bits.
Syntaxe : { { unsigned } { int } identificateur } : entier;
124
OBJETS STRUCTURES
struct etat {
unsigned pret : 1;
unsigned ok1 : 1;
int donnee1 : 5;
int : 3;
unsigned ok2 : 1;
int donnee2 : 4;
};
struct etat mot;
mot.donnee1 -> entier signé avec valeurs comprises entre -24 et 24-1
125
OBJETS STRUCTURES
• 5) Les unions
Alors que les champs des structures se suivent, les
champs d’une union commencent tous au même endroit,
et donc se superposent
Syntaxe : même que celle de struct avec union à la place
union {
unsigned long m;
char *ptr;
} mot;
mot pourra être vue tantôt comme un long, tantôt comme
l’adresse d’un char
126
OBJETS STRUCTURES
Les unions peuvent être utiles pour :
• pour économiser des emplacements mémoire, en utilisant un même
emplacement pendant des phases différentes d’un même
programme;
• pour interpréter de plusieurs façons différentes un même motif
binaire. Dans ce cas, il sera alors fréquent que l’union soit elle-
même associée à des champs de bits.
Exemple
#include <stdio.h>
main() {
union essai {
long n ;
float x ;
} u;
printf ("donnez un nombre réel : ") ; 127
OBJETS STRUCTURES
scanf ("%f", &u.x) ;
printf (" en entier, cela fait : %ld", u.n) ;
}
Exemple d’exécution
donnez un nombre réel : 1.23e4
en entier, cela fait : 1178611712
128
OBJETS STRUCTURES
• Exemple d’association entre l’union et le champ de bits
union {
int valeur;
struct etat bits;
} mot;
Si m est de type int
mot.valeur = m;
Pour accéder aux différentes parties du mot m
mot.bits.pret, mot.bits.ok1, mot.bits.donnee1
129
OBJETS STRUCTURES
• 5) Enumérations
Les énumérations ne constituent pas un type structuré mais la
syntaxe de leur déclaration est similaire à celle des structures
Syntaxe : enum nomopt { id_valeur, …, id_valeur} {nom,…, nom}
130
CHAPITRE 5. POINTEURS ET
TABLEAUX
131
POINTEURS ET TABLEAUX
Pointeur : variable dont la valeur est l’adresse d’une
cellule de la mémoire
Principal intérêt :
possibilité de réaliser des structures de données
récursives (listes, arbres)
moyen en C d’améliorer l’accès aux éléments des
tableaux
132
POINTEURS ET TABLEAUX
• 1) Déclaration et initialisation de pointeurs
Syntaxe : type * variable;
char *p; int *pi;
float *pf;
• Que contient un pointeur ?
– un pointeur contient une adresse
– Ex : les pointeurs pi et pf contiennent des adresses
de variables de type int et float.
– l’opérateur unaire & permet d’obtenir l’adresse d’une
variable
int i, *pi; float f, *pf;
pi = &i;
pf = &f; 133
POINTEURS ET TABLEAUX
134
POINTEURS ET TABLEAUX
– Prendre l’adresse d’une variable existant par ailleurs
type x, *p;
initialisation p = &x;
– Allocation dynamique d’un nouvel espace
type *p;
p = (type *) malloc(sizeof(type));
…
char * adr;
adr = (char *) malloc (20);
for (i = 0; i< 20; i++)
*(adr + i) = ‘x’;
135
POINTEURS ET TABLEAUX
long *adr;
adr = (long *) malloc( 100 * sizeof(long));
for (i = 0; i < 100; i++) *(adr + i) = i;
136
POINTEURS ET TABLEAUX
– Obtenir une valeur par des calculs légitimes sur des pointeurs
type t[10], *p, *q;
p = &t[0]; p = t;
q = p + 3;
Pointeurs et adresses
int x, y, *px;
x = 10; y = 20;
px = &x;
y = *px + 4;
*px += 10;
137
POINTEURS ET TABLEAUX
• Comment utiliser un pointeur ?
4. *p = 2;
139
POINTEURS ET TABLEAUX
• 3) Les pointeurs et les tableaux
• a) Opérations sur les pointeurs
On peut effectuer la comparaison, l’addition avec un
entier, la soustraction et les affectations de pointeurs,
mais ceux-ci doivent être de même type
Pour les affectations, exception pour le pointeur null et le
pointeur générique
142
POINTEURS ET TABLEAUX
• Cas des tableaux à un indice
soit la déclaration : int t[10]
t &t[0]
t + 1 &t[1]
t + i &t[ i]
143
POINTEURS ET TABLEAUX
• Cas des tableaux à une dimension
int notes[4], x, *p;
1. notes[0] = 1;
2. notes[1] = notes[0] + 2;
3. notes[3] = notes[0] + notes[1];
4. p = ¬es[0];