Vous êtes sur la page 1sur 178

Algorithmique et Programmation

MIP : Sections A, B et C

Pr. Arsalane ZARGHILI


Pr. Abdelali BOUSHABA
Pr. Khalid ABBAD
Département d’Informatique

1
Plan du cours
 Rappel : Outils de base .. Structures alternatives et
structures itératives

 Les pointeurs

 Les fonctions

 Les tableaux et chaines de caractères

 Les structures et énumérations

2
Plan de la séance 1
 Définition et structure d’un programme en langage C

 Variables et types de données

 Opérateurs, opérandes et expressions

 Priorité des opérateurs

 Structures Alternatives

 Structures itératives

3
Structure d’un programme C
 Un programme C est structuré de la façon suivante :

Directives de préprocesseur
Déclaration de variables externes (globales)
Déclaration ou définition de fonctions secondaires
main()
{
Déclaration des variables internes (locales)
Instructions
}
4
Identificateurs
 Rôle : donner un nom à toute entité du programme.

 Un identificateur est une suite de lettres (non accentués), de chiffres


et le caractère « _ »

 Il ne doit pas commencer par un chiffre

 Les majuscules et minuscules sont différenciées

 Remarque : il est déconseillé de commencer un identificateur par « _ »,


parce que cette notation est souvent employée pour définir les
variables globales de l’environnement C.

5
Les types prédéfinis
 Avant d’utiliser une variable, nous devons nous intéresser à deux
caractéristiques de son type numérique :

Le domaine des valeurs admissibles


Le nombre d’octets qui est réservé pour une variable

 Les types prédéfinis du langage C sont :

Les caractères (signé ou non signé): char (signed, unsigned)


Les entiers : int, short, long (signed, unsigned)
Les réels : float, double, long double

6
Les types prédéfinis
 Types caractères et entiers :

Nombre
Déf Description Valeur min Valeur max
d’octet(s)

char caractère -128 127 1

short entier court -32768 32767 2

-32768 32767
2 (proc 16 bits)
entier / /
int /
standard -2147483648 2147483647
4 (proc 32 bits)

long entier long -2147483648 2147483647 4

7
Les types prédéfinis
 Types caractères et entiers avec modificateur signed/unsigned :

Nombre
Déf Description Valeur min Valeur max
d’octet(s)

unsigned char caractère 0 255 1

unsigned short entier court 0 65535 2

65535
2
entier /
unsigned int 0 /
standard 4294967295
4

unsigned long entier long 0 2147483647 4

8
Les types prédéfinis
 Type réel :

Nombre
Déf precision Valeur min Valeur max
d’octet(s)

float Simple 6 3.4 * 10-38 3.4 * 1038 4

double Double 15 1.7 * 10-308 1.7 * 10308 8

Long double Suppl 19 1.1 * 10-4932 1.1 * 104932 10

Remarque : un réel s’écrit sous <+/-> mantisse * e <exposant>


La mantisse est un décimal positif avec un seul chiffre avant la virgule.

9
Déclaration et initialisation
Déclaration et initialisation des variables simples:
 Syntaxe :
<type> <Nom_Var_1>, <Nom_Var_2>, …., <Nom_Var_n> ;

 Initialisation :
<type> <Nom_Var> = valeur;
 Exemples:
int max = 10234, a = 5, X, Y;
char tabulation = ‘\t’, valide = ‘O’, Apte;
float X = 1.05 e-4; Y = 0.0001675, Z;

10
Les opérateurs
L’opérateur d’affectation :
 En langage C l’opérateur d’affectation est représenté par le symbole =

 La syntaxe d’utilisation de l’opérateur d’affectation est la suivante :


<variable> = <expression>
 L’élément de gauche doit être absolument une variable (simple ou
structurée).

 Le traitement consiste à évaluer l’expression de droite et d’affecter sa


valeur à la variable de gauche

11
Les opérateurs
Les opérateurs arithmétiques:
 En langage C les opérateurs arithmétiques classiques sont représentés
par les mêmes symboles utilisés en algorithmique à savoir :
 Pour le changement de signe (unaire)
+ Addition
 Soustraction
* Multiplication
/ Division (réelle et entière : en fonction des opérandes)
% reste de la division entière

12
Les opérateurs
Les opérateurs de comparaisons :
 Mêmes symboles en langage C qu’en algorithmique :
> strictement supérieur, >= supérieur ou égal
< strictement inférieur, <= inférieur ou égal
== égal, != différent
 Ce sont des opérateurs binaires dont la syntaxe est :
experssion1 op expression2
 Les deux expressions sont évaluées puis comparées. Le résultat est de
type entier (pas de type booléen en C).
 0 (zéro) si la condition est fausse
 1 (ou n’importe quelle autre valeur différente de 0) si la condition est
vraie
13
Les opérateurs
Les opérateurs logiques :
 Ils sont représentés par les symboles suivants :
&& représente le ET logique
| | représente le OU logique
! représente le NON logique
 La syntaxe d’utilisation est :
expression1 op1 expression2 ….. opN-1 expressionN
 L’évaluation se fait suivant la priorité des opérateurs de gauche à droite.
Le résultat vaut :
 0 si toute l’expression est fausse
 1 (ou n’importe quelle autre valeur différente de 0) si l’expression est
vraie
14
Les opérateurs
Les opérateurs d’affectation composée :
+= -= *= /= %=
 La syntaxe d’utilisation est :
variable op= expression
 Ce qui est équivalent à :
variable = variable op expression

Exemple:
x+=1 est équivalent à x=x+1

15
Les opérateurs
Les opérateurs ++ et -- :
 Les opérateurs unaires ++ et -- sont des opérateurs particuliers qui
peuvent avoir jusqu’à deux effets de bord:
 En dehors de toute affectation, ils incrémente ou décrémente
l’opérande associée, par exemple :
 i++ et ++i sont équivalents à i=i+1
 Lorsqu’ils sont utilisés dans une affectation, tout dépend de la position
de l’opérateur par rapport à l’opérande, par exemple :
 j = i++ ; est équivalent à { j = i; i = i + 1; }
 j = ++i ; est équivalent à { i = i + 1; j = i; }

16
Priorité des opérateurs
1. () []
2. ! ++ -- -(unaire)
3. * / %
4. + -(binaire)
5. < <= > >=
6. == !=
7. &&
8. ||
9. = += -= *= /= %=
17
Les instructions
Il existe deux types d’instructions en C :
 Les instructions simples (expression, appel de fonction, etc.)
 Elles finissent toujours par un ’;’
 Exemple : i = j + k;

 Les instructions composées qui permettent de considérer une


succession d’instructions comme étant une seule instruction (un block
d’instruction).
 Elles commencent par “{” et finissent par “}”
 Exemple : {
x = y+z;
A = 5+D;
}
18
La fonction de lecture
 L’instruction scanf (du module stdio.h) permet à l’utilisateur de
saisir des informations au clavier

 La syntaxe est la suivante :


scanf (suite de n formats, &V1 , . . ., &Vn)

 %d pour les entiers (int, short, long)


 %f pour les réels (float, double)
 %c pour les caractères
 %s pour les chaînes de caractères

19
La fonction de lecture
 Exemples:
scanf (%d%f%c, &A1 , &A2, &A3)

 Le format %d correspond à la variable &A1 qui est de type entier.


 Le format %f correspond à la variable &A2 qui est de type réel.
 Le format %c correspond à la variable &A3 qui est de type caractère.

20
La fonction d’écriture
 L’instruction printf (du module stdio.h) permet d’afficher des
informations à l’écran
 La syntaxe est la suivante :
printf( chaines de caractères avec n formats , suite de n variable(s))
 %d pour les entiers (int, short, long)
 %f pour les réels (float, double)
 %c pour les caractères
 %s pour les chaînes de caractères

 La chaîne de caractères peut contenir des caractères spéciaux :


\n \t …

21
La fonction d’écriture
 Exemple :
inst 1 : printf( Saisir deux entiers : ) ;
inst 2 : scanf( %d %d, &A, &B);
inst 3 : printf( La somme de %d et %d est : %d \n, A, B, A+B);

 L’instruction 1 «inst 1» demande à l’utilisateur de saisir deux entiers.


 L’instruction 2 «inst 2» permet de saisir les deux entiers à partir du
clavier et les stocker (enregistrer) respectivement dans les variables A
et B.
 L’instruction 3 «inst 3» affiche le résultat : (pour A=2 et B=5)
La somme de 2 et 5 est 7
22
Structures alternatives
 Première forme:
if (condition)
instruction

 L’instruction peut être simple ou composée

Exemple :
Valeur_Absolue_A = A;
if (A < 0)
Valeur_Absolue_A = - A;

23
Structures alternatives
 Deuxième forme:
if (condition)
instruction_1
else
instruction_2

 Les instructions (instruction_1 et instructions_2) peuvent être simples


ou composées
Exemple :
if (A>B)
printf(%d est plus grande que %d\n, A, B);
else
printf(%d est plus grande que %d\n, B, A);
24
Structures alternatives
 Troisième forme:
switch (expression)
{
case V_1 : instruction_1
break ;
case V_2 : instruction_2
break;
. . .
. . .
case V_N : instruction_N
break;
default : instruction par défaut
}
25
Structures alternatives
 Troisième forme: Exemple
switch (choix)
{
case ‘T’ : printf(“Vous voulez un Triangle\n”);
break ;
case ‘C’ : printf(“Vous voulez un Carre\n”);
break;
case ‘R’ : printf(“Vous voulez un Rectangle\n”);
break;
default : printf(“ERREUR !!\n”);
}

26
Structures itératives
 Les structures itératives sont des instructions qui permettent de réaliser (répéter)
un traitement plusieurs fois

 Pour réaliser et mettre en place une structure itérative on doit connaître :

 Soit le nombre de répétition (itération)


 Soit la condition d’arrêt qui est une expression logique qu’on vérifie avant ou après
chaque itération.

27
Structures itératives
 Première forme : la boucle pour
for(inst_intialisation ; condition ; inst_incrém_ou_décrem)
{
instruction(s)
}
for( i=val_ini ; i<=val_fin ; i++ )
{
instruction(s)
}
 Le nombre de répétition est connu à l’avance|(val_fin – val_ini)|+1

 i est initialisée par val_ini et à chaque répétition, on incrémente i jusqu’à ce qu’il soit égale
à val_fin
28
Structures itératives
Exemple de la première forme : la boucle pour

Donner l’algorithme qui calcule la somme de la suite :

1 1 1
Sn  1      2
4 9 n

29
Structures itératives
#include <stdio.h>
#include <stdlib.h>
main()
{
int i, n;
float Sn = 0;
printf(" saisir la valeur de n ");
scanf("%d",&n);
if(n>0)
{
for( i=1 ; i <= n ; i++)
Sn = Sn + (float)1/(i*i);
printf ("Le résultat est %f\n" ,Sn);
}
else
printf("Erreur ! N doit être positif\n");
system("pause");
}
30
Structures itératives
 Deuxième forme : la boucle while
while (condition)
{
instruction(s)
}
 Le nombre de répétition n’est pas connu à l’avance, mais on connaît la condition d’arrêt
(quand l’expression logique devient fausse)
 L’exécution du traitement dépend de la vérification de la condition
 La condition d’arrêt se trouve au début de la boucle. Ce qui veut dire que le traitement
peut ne jamais être exécuter

31
Structures itératives
Exemple de la deuxième forme : la boucle while

Ecrire un programme qui détermine le plus petit entier e tel que e! >= n.
(n est un entier strictement positif saisi au clavier)

32
Structures itératives
#include <stdio.h>
#include <stdlib.h>
main(){
int e, fact, n;
printf(" saisir la valeur de n : ");
scanf("%d",&n);
if(n<=1)
printf("le plus petit entier dont le factoriel est >= %d est 0",n);
else
{
e = 0; fact = 1;
while (fact < n )
{
e = e + 1;
fact = fact * e;
}
printf("le plus petit entier dont le factoriel est >= %d est %d",n,e);
}

system("pause");
}
33
Structures itératives
 Troisième forme : la boucle do … while
do {
instruction(s)
} while (condition);

 Comme la boucle while, on ne connaît pas le nombre de répétition, mais on connaît la


condition d’arrêt

 L’exécution du traitement dépend de la vérification de la condition

 La condition d’arrêt se trouve à la fin de la boucle. Ce qui veut dire que le traitement va
être exécuter au moins une fois et tant que la condition est vraie

34
Structures itératives
Exemple de la troisième forme : la boucle do …. while

Ecrire un programme qui saisit un réel strictement postif r et un entier n tel que
(n > r) et qui affiche le plus grand multiple de r inférieur à n2 .

35
Structures itératives
#include <stdio.h>
#include <stdlib.h>
main()
{
int n; float r, multiple_r;

do{
printf(" saisir la valeur de r : ");
scanf("%f",&r); Contrôle de
printf(" saisir la valeur de n : "); saisie de n et r
scanf("%d",&n);
}while ((r<=0) || (r>=n));

multiple_r = r;
do {
multiple_r = multiple_r + r;
}while(multiple_r <= n*n);

multiple_r = multiple_r - r;

printf(" le multiple de %f est %f",r,multiple_r);


system("pause");
}
36
Structures itératives (récapitulatif)
 La structure for :
for (inst_intialisation ; condition ; inst_incrém_ou_décrem)
instruction

 La structure while :
while (condition)
instruction

 La structure do .. while :
do
{
instruction
}while(condition ) ;
37
Opérateur conditionnel : .. ? .. : ..
 Le langage C possède un opérateur un peu exotique qui peut être utilisé comme
alternative à l’opérateur if .. else.. et qui a l’avantage de pouvoir être intégré dans
une expression.

 La syntaxe de cet opérateur est :


expression_condition ? instruction1 : instruction2 ;

 Ce qui est équivalent à :


if (expression_condition)
instruction1
else
instruction2
38
Opérateur conditionnel : .. ? .. : ..
Exemple 1:

(A>B) ?printf( A est plus grande que B ) : printf( B est plus grande que A ) ;

Exemple 2 :

((A>B)&&(A>C)) ? Max = A : (B>C) ? Max = B : Max = C ;

39
Opérateur : break
 L’opérateur break est, généralement, utilisé dans des traitements itératifs (dans des
boucles)

 Son rôle est d’interrompre le déroulement de la boucle.

 c.-à-d. que break dans une boucle provoque l’arrêt du traitement itératif sans que
la condition du traitement ne soit vérifier.

 En cas de boucles imbriquées l’utilisation du break fait sortir de la boucle la plus


interne.

 Cet opérateur n’a d’intérêt que s’il est conditionné par un choix.
40
Opérateur : break
 Exemple 1:
int i; À l’ exécution de ce bout de
programme on aura :
for( i=1 ; i <= 5 ; i++)
{ i=1
printf(i = %d \n ,i); i=2
if ( i == 3) i=3
{ la valeur de i a la sortie est : 3
break;
}
}
printf( la valeur de i a la sortie est : %d\n ,i);

41
Opérateur : break
 Exemple 2 :
int i;
int code_secret = 1234;
int code;
for (i=1; i<=3; i++)
{
printf("Essai N° %d. Tapez le code :", i);
scanf("%d", &code);
if(code == code_secret)
break;
else
printf("Mauvais code ! ! \n");
}
42
Opérateur : continue
 L’opérateur continue est, également, utilisé dans des traitements itératifs (dans des
boucles)

 Son rôle est de passer directement à l’itération suivante sans exécuter les autres
instructions de la boucle.

 c.à.d. que continue dans une boucle provoque l’arrêt de l’itération en cours et le passage
à l’itération suivante (en exécutant l’instruction d’incrémentation dans le cas de for).

 En cas de boucles imbriquées l’utilisation du continue ne concerne que la boucle la plus


interne.

 Cet opérateur n’a d’intérêt que s’il est conditionné par un choix.
43
Opérateur : continue
 Exemple 1 : À l’ exécution on aura :
int i;
for( i=1 ; i <= 5 ; i++) i=1
{ i=2
i=3
printf("i = %d \n", i );
i=4
if ( i <= 3) la valeur de i est : 4
{ i=5
continue; la valeur de i est : 5
}
printf("la valeur de i est : %d\n", i);
}

44
Opérateur : goto
 L’opérateur goto permet le branchement directement à l’instruction étiquette.
Goto etiquette ;

 Le rôle de l’étiquette est de marquer un emplacement spécifique dans le


programme.

 Une étiquette peut être placée n’importe où dans un programme

 Une étiquette est un identificateur suivie de ‘:’

45
Opérateur : goto
 Exemple 1 :
À l’ exécution on aura :
int i;
for( i=1 ; i <= 5 ; i++) i=1
{ i=2
printf("i = %d \n ", i ); i=3
if ( i == 3) la valeur de i est : 3
{
goto fin;
}
}
fin : printf("la valeur de i est : %d\n");
46
Plan de la séance 2

Les pointeurs

Les fonctions et procédures


 Règles d’utilisation

 Variables locales et globales

 Fonctions récursives

47
Les pointeurs

48
Pointeurs : Définition

 Lorsqu’on déclare une variable, par exemple un entier i,


l’ordinateur réserve un espace mémoire pour y stocker les
valeurs de i
 L’emplacement de cet espace dans la mémoire est nommé
adresse.
 Un pointeur est une variable qui permet de stocker l’adresse
d’une autre variable.
 Par exemple si on déclare une variable entière i (initialisée à 10) et qu’on
déclare un pointeur p dans lequel on range l’adresse de i

i p
Mémoire 10 120
Adresse  120 245
49
Pointeurs : Définition

 En langage C, chaque pointeur est limité à un type de données


(simple ou composé).

 Si Ptr est un pointeur qui contient l’adresse de A, on dit que Ptr


pointe sur A.

Remarque :
 Accès direct : accès au contenu d’une variable par le nom de la variable.
 Accès indirect : accès au contenu d’une variable en passant par un
pointeur contenant l’adresse de la variable.

50
Pointeurs : Opérations de base

 Syntaxe de déclaration d’un pointeur :

<type> *<identificateur_pointeur>;

<indetificateur_pointeur>: est un pointeur qui peut recevoir


l’adresse de toute variable de type <type>

 Exemple :
int *Ptr_entier;
float *Ptr_reel;
char *Ptr_caractere;
51
Pointeurs : Opérations de base
 Lorsqu’on travaille avec des pointeurs, on a besoin de:
 Opérateur « adresse de » : symbolisé par &
 Opérateur « contenu de » : symbolisé par *

 & : permet d’obtenir l’adresse d’une variable. Elle permet donc à un


pointeur de pointer sur une variable, par exemple :
int i,*Ptr;
Ptr = &i ; // Ptr pointe sur i

 * : permet de dé-référencer un pointeur, c’est-à-dire d’accéder à la


valeur de la variable pointée, par exemple:
Ptr=&i; //Ptr pointe sur i
*Ptr = *Ptr + 2 ; // ajoute 2 à i
j = *Ptr ; // met la valeur de i dans j
52
Pointeurs : Opérations de base

0. int A, B, *p; p p
1. p = &A; 0 1
2. *p = 12 ;
3. p = &B ;
4. *p = 15 ; A B A B

p p p
2 3 4

A B A B A B
12 12 12 15

53
Pointeur — Accès à l’espace pointé
• Sur la variable *ptr, on peut effectuer toutes les
opérations permises sur le type t:

Lecture : scanf(’’%car’’, ptr);


Affichage : printf(’’%car’’, *ptr);
Opérateurs : =,+,*, /, ==, Etc.

• Avec car un spécificateur de type (d, f, s, c, etc.)

54
Pointeur — Accès à l’espace pointé
 Exemple
#include<stdio.h>
void main()
{
int * ptr_int;
int x;
ptr_int =(int*) malloc(sizeof(int));
scanf(’’%d’’, ptr_int);
x = *ptr_int*2;
*ptr_int = x;
printf(’’%d’’, *ptr_int);

} 55
Pointeurs : Opérations de base

 Par défaut lorsqu’on déclare un pointeur, on ne sait pas sur quoi il


pointe.
 Comme toute variable, il faut qu’il ait une valeur avant qu’il soit
utiliser.
 On peut dire qu’un pointeur ne pointe sur rien en lui affectant la
valeur NULL. Par exemple :
int i;
int *Ptr_1 , *Ptr_2 ;
Ptr_1 = &i ;
Ptr_2 = NULL ;
int *p = &x ; /* Juste*/
Int *p = 10 ; /* Faux*/ 56
Pointeurs : Opérations de base

 Remarque:
si ptr_1 et ptr_2 sont des pointeurs vers des entiers, la
multiplication des deux valeurs pointées s'écrit : *ptr_1* *ptr_2

 Exercice:
Ecrire un programme qui permet de :
1. Déclarer un entier i et un pointeur p vers un entier.
2. Initialiser l'entier à une valeur arbitraire et faire pointer p vers i.
3. Imprimer la valeur de i.
4. Modifier l'entier pointé par p (en utilisant p et non pas i).
5. Imprimer la valeur de i.
57
Pointeurs : Opérations de base

 Exemple

Ecrire un programme qui permet de :


1. Déclarer deux entiers A et B et deux pointeurs ptr_A et ptr_B.
2. Saisir les entiers A et B et faire pointer ptr_A vers A et ptr_B vers B
3. Afficher A et B.
4. Modifier A et B en utilisant ptr_A et ptr_B et afficher le résultat.
5. Permuter A et B en utilisant A et ptr_B et afficher le résultat.

58
Pointeurs : incompatibilité de types

 On ne peut pas affecter un pointeur de type T1 à un pointeur de


type T2
int i = 3;
char *Ptr_C;
Ptr_C = &i; // ERREUR

 On peut forcer la conversion


int i = 3;
char *Ptr_C;
Ptr_C = (char *) &i;

59
Pointeurs : type void

 Les pointeurs void sont un type particulier de pointeurs :


pointeurs génériques.
 Ils peuvent pointer sur une variable de n’importe quel type.
 On ne peut pas utiliser * sur un pointeur void avant de le
convertir en un type donné.

int a = 4, b=5; Ptr_1 = &a;


int *Ptr_1; Ptr_2 = &b;
void *Ptr_2; Ptr_2 = Ptr_1;
Ptr_1 = Ptr_2; //ERREUR
Ptr_1 = (int *) Ptr_2;
60
Pointeurs : incrémentation / décrémentation

 Soit Ptr un pointeur de type T.


 Soit t la taille en octets du type T.
 Soit Adr la valeur de Ptr (adresse contenue dans Ptr)
 Après Ptr++ la valeur de Ptr sera égale à Adr + t

int i=5, *Ptr ;


Ptr = &i;
printf("la valeur avant incrémentation%p",Ptr); // 0012FF78
Ptr++;
printf("la valeur après incrémentation%p",Ptr); // 0012FF7C

 Le même principe pour Ptr--


61
Pointeurs : addition / soustraction

 Soit Ptr un pointeur de type T


Exemple : la taille du type int est 4 Octets

Ptr-- Ptr++

Ptr - 2 Ptr + 2

Ptr

62
Pointeurs : Allocation de mémoire

 Allocation (réservation) de mémoire se fait par le


programmeur pour optimiser l’utilisation de la mémoire.
 toute utilisation avant allocation rend le programme instable
(blocage au niveau d’exécution).
Intérêt de l’allocation de mémoire:
 Permet une gestion plus flexible de la mémoire.
 Un programme n’utilise que la mémoire dont il a besoin au
moment où il en a besoin.
 On évite de monopoliser de l’espace mémoire aux instants où
on n’en a pas besoin.
 Par contre, on doit libérer la mémoire sinon l’allocation de
mémoire perd son intérêt.
63
Pointeurs : Allocation de mémoire

 Allocation de la mémoire pour un pointeur :


 On utilise la fonction malloc( )
 Soit T un pointeur sur un entier, l’allocation de la mémoire se
fait comme suit:

int * T;
T = (int*)malloc(sizeof(int));

Nom du pointeur

Fonction de calcul
Fonction d’allocation automatique de la taille
de la mémoire d'un entier en octet 64
Pointeur —Initialisation à l’aide de malloc
Exemple

void main(){
int *ptr_X ;

/* allocation mémoire pour une 1000


variable entière X */
1001
ptr_X = (int *) malloc (siezof(int)) ;
1002

/* on suppose que la fonction


malloc a retourné l’adresse
ptr_X 1000 1020
1000*/
}

65
Pointeurs : Allocation de mémoire

 Libération de la mémoire allouée par un

pointeur

On utilise la fonction free( ) comme suit :


free(T);
Pointeur —Initialisation à l’aide de &
Exemple
void main()
{
/* X contient la valeur 25 */
1000
int X = 25; X 25 1001

int *ptr_X ; 1002

ptr_X = &X ;
ptr_X 1001 1020

/* ici ptr_X contient l’adresse de X */


}

67
Resumé : malloc et &

Avec operateur & Avec malloc

int *Ptr int *Ptr

int Y; Ptr=malloc( sizeof(int));

Ptr = &Y;
*Ptr= 100 *Ptr=100;

68
Les fonctions

69
Les fonctions
 Parfois on est obligé d'utiliser des calculs ou des
traitements plusieurs fois à des endroits différents, ou
avec des informations variables.

 On est alors obligé de répéter la séquence d'instructions


qui se rapportent à ces calculs ou traitements, en ne
faisant varier que le paramétrage des informations à
traiter.
70
Les fonctions
 Pour résoudre ce problème, on adopte un mode de
programmation appelé : programmation modulaire
 Consiste à diviser un problème en plusieurs sous problèmes
ou modules.
 Chaque sous problème ou module est résolu
indépendamment des autres.
 La résolution de tous les sous problèmes nous permet de
résoudre le problème final.

71
Les fonctions
 Écrire un programme qui résout un problème revient toujours à
écrire des sous-programmes qui résolvent des sous parties du
problème initial.

 Il existe deux types de sous-programmes :


Les fonctions.
Les procédures.

 Un sous-programme est obligatoirement caractérisé par un nom


(un identifiant) unique.

72
Les fonctions
 Définition d’une fonction/Procédure
Ensemble d'instructions pouvant être appelées de manière
répétitive par un nom
 Déclaration et définition
type nom_f( type arg1, type arg2, …, type argn)
{
ensemble instructions
}
 nom_f : Nom de la fonction
 arg1 …argn : les arguments de la fonction

73
Les fonctions
 Fonction: Renvoie une valeur qu’on peut utiliser:
Afficher.
Affecter dans une variable.
Comparer à une autre variable…..etc
Le retour des variables se fait à l’aide de l’instruction return

 Procédure:
Ne renvoie pas de valeur: on ne peut ni afficher, ni affecter, ni
comparer.

74
Les fonctions
 Remarque:

 Dans la suite, nous utiliserons le terme fonction pour désigner


indifféremment une procédure ou une fonction.

 On distinguera entre fonction qui retourne des valeurs et une


fonction qui ne retourne pas de valeurs(procédure)

75
Les fonctions
 Règles d'utilisation

L'ordre, le type et le nombre des arguments doivent être


respectés lors de l'appel de la fonction.

L'appel d'une fonction doit être situé après sa déclaration ou


celle de son prototype (voir exemple suivant)

Pour la fonction qui ne renvoie rien, on doit lui spécifier le


type void

76
Les fonctions
Prototype d’une fonction :
Le prototype d’une fonction est une déclaration
de la fonction en tête du programme sans la
définition de la fonction.

77
Les fonctions
 Exemple1: Fonction qui retourne des valeurs (déclaration du prototype)

int min(int a, int b); Prototype de la fonction min

main()
{
int x,y,c;
Programme principal
printf("Saisir deux entiers");
scanf("%d%d",&x,&y);
c=min(x,y); Appel de la fonction min
printf("le minimum est %d",c);
}
int min(int a, int b)
{
if (a <b) Définition de la fonction min et
return a; son bloc d'instructions
else
return b;
}
78
Les fonctions
 Exemple2: Fonction qui retourne des valeurs (sans déclarer le prototype)

int min(int a, int b)


{
if (a <b) Définition de la fonction min
return a; et son bloc d'instructions
else
return b;
}

main()
{
int a,b,c;
printf("Saisir deux entiers"); Programme principal
scanf("%d%d",&a,&b);
c=min(a,b); Appel de la fonction min
printf("le minimum est %d",c);
}
79
Les fonctions
 Exemple3: Fonction qui ne retourne pas des valeurs
(Procédure) (déclaration de prototype)

void affichage(int a,int b); Prototype de la fonction


main() affichage

{
int a=3;int b =5;
affichage(a,b); Appel de la fonction
} affichage
void affichage(int a,int b)
{ Définition de la fonction
printf("%d%d",a,b); affichage
}
80
Les fonctions
 Exemple4: Fonction qui ne retourne pas des valeurs
(Procédure) (sans prototype)

void affichage(int a,int b)


{ Définition de la fonction
printf("%d%d",a,b); affichage
}

main()
{
int a=3;int b =5;
affichage(a,b); Appel de la fonction
} affichage

81
Les fonctions
 Variables locales:

Se déclarent au début de la fonction juste après le {

Conservent les résultats intermédiaires nécessaires à


l’exécution de la fonction.

La portée des variables: Les variables locales sont détruites à


la sortie de la fonction.

82
Les fonctions
 Variables globales:

Se déclarent au début du programme et en dehors de toute


fonction (même le main).

La portée des variables: les variables vivent dans tous le


programme c-à-d toute fonction du programme principal peut
utiliser cette variable.

83
Les fonctions
 Remarque:

Lorsque le nom d’une variable locale est identique à une variable


globale, la variable globale est localement masquée.

 Dans la fonction la variable globale devient inaccessible.

84
Récursivité — Illustrations
• La récursivité est un principe de pensée qui n’est
pas propre à l’informatique.
l'art en fait usage pour créer des œuvres d’art

85
• La définition récursive d’un problème
– trouve son formalise dans le raisonnement par
récurrence.

– met en jeu deux parties:


• des cas de base
définissent des sous problèmes triviaux.

• une équation de récurrence


exprime le problème en fonction des
sous problèmes avec une difficulté
inférieure 86
Les fonctions récursives
Problème récursif 1 :
– le problème P(n) consiste à calculer l’expression
suivante:
n
P ( n)   i
i 1

– la définition récursive de P(n) est :


• Un cas de base :
P ( 0)  1

• Une équation de récurrence :


n
P(n)   i  P(n  1) * n
i 1
87
Les fonctions récursives
Problème récursif 2 :
– le problème P(n) consiste à calculer le nombre de
Fibonacci par la suite définie par:
U (n)  U (n-1)  U (n-2) n  2

 U (0)  1
 U (1)  1

– la définition récursive de P(n) est :


• Deux cas de base :
U (0)  1, U (1)  1

• Une équation de récurrence :


U (n)  U (n-1)  U (n-2)
Les fonctions récursives
 Une fonction récursive est une fonction qui appelle elle-même.

Exemple : la fonction factorielle


int factorielle(int n)
{
if (n = = 0)
return 1;
else
return n * factorielle (n-1);
}

89
Les fonctions récursives
• Exemple 1 : Exécution avec 4!

4! fin
décomposition

4
* 3!
4*6 = 24

6
3 * 2!
3*2 =

* 2*1 = 2
2 1!
Evaluation
1
1 * 0! 1*1 = 1
arrêt
Pointeurs et fonctions

 Passage d’arguments par valeur :


 Recopie en mémoire des paramètres dans des paramètres
temporaires.

 Toute modification des paramètres dans la fonction


est sans effet sur les paramètres originaux

 Quand on quitte la fonction, les paramètres


temporaires sont effacés de la mémoire

91
Pointeurs et fonctions

 Passage d’arguments par valeur


Exemple:
void permutter(int a, int b)
{
int temp; Aucune
temp = a; action sur
a = b; les paramètres
b= temp; x et y
}

void main()
{
int x=3; int y =5;
permutter(x, y);
printf("x = %d et y = %d\n",x ,y); //affiche x=3 et y=5
}
92
Pointeurs et fonctions

 Passage d'arguments par adresse :

 On ne passe pas la valeur de la variable mais son adresse

 Il est donc possible par les pointeurs de modifier le contenu de


l'adresse, donc la variable originale

 Permet de modifier plusieurs arguments à la fois dans une


fonction

 Permet de passer des tableaux en argument

93
Pointeurs et fonctions

 Passage d'arguments par adresse


Exemple
void permutter(int *a, int *b)
{
int temp;
temp = *a; Action sur
*a = *b; les paramètres
*b= temp; x et y
}

void main()
{
int x=3; int y =5;
permutter(&x, &y);
printf("x = %d et y = %d\n",x ,y); // affiche x = 5 et y = 3
} 94
Pointeurs et fonctions
 Exercice: main()
#include <stdio.h> {
int n,m=0;
void init0(int *m)
{ printf("\n %d",m);
*m=1; init0(&n);
printf("\n %d",*m);
} printf("\n %d",m);
n=m;
void init1(int *t)
{ init1(&m);
*t=3; printf("\n %d",n);
printf("\n %d" ,*t);
} init2(&m);
printf("\n %d",m);
void init2(int *p)
{ init1(&m);
int m; printf("\n %d",m);
m=*p+3;
*p+=2; }
} 95
Plan de la séance 3
 Tableaux à une dimension
o Initialisation
o Saisie d’un Tableau
o Affichage d’un Tableau
o Taille maximale et Taille réelle
o Tableaux & pointeurs
o Tableaux statiques
o Tableaux dynamiques
 Allocation de mémoire
 Désallocation de mémoire

o Tableaux- paramètres de fonction

96
Les tableaux : introduction
 Un tableau est une variable structurée formée d’un nombre N
(entier ) de variables simples de même type.
 Les différents éléments d’un tableau sont appelés les
composantes du tableau.
 Le nombre de composantes N est appelé la dimension du
tableau
 L’accès et la modification des différentes composantes d’un
tableau se fait directement via un indice

…………….

N composantes 97
Les tableaux : en langage C
 Syntaxe de déclaration
type Nom_Tableau[dimesion];
 Le nom d’un tableau est un identificateur qui doit correspondre
aux restrictions définies précédemment
Exemple :
int T[25]; float moyenne[250]; char Prenom[20];
 Le premier élément d’un tableau est l’élément d’indice 0.
Exemple :
int T[20];
T[0] est le 1er élément du tableau et T[6] est le 7ème élément
du tableau .
98
Les tableaux : initialisation
 Lors de la déclaration d’un tableau, on peut initialiser ces
composantes en indiquant la liste des valeurs respectives entre
accolades.
 Exemple :
int A[5] = { 7, 786, 98, 45, 911 };
float B[4] = { 3.987, -6.32, 776.28, 123.456 };
char Nom[20] = {‘D’, ‘U’, ‘P’, ‘O’, ‘N’};

Remarque:
Si le nombre de valeurs dans la liste est inférieur à la dimension
du tableau, les composantes restantes sont initialisées par 0
(zéro) pour le type numérique et ‘\0’ pour les caractères.
99
Les tableaux : La saisie

 La saisie d’un tableau se fait élément par élément en utilisant


une boucle.

 Exemple :
int i; float moy[5];
for(i=0 ; i<5 ; i++)
{
printf( \n moyenne [%d] = , i);
scanf(% f ,&moy[i]);
}

100
Les tableaux : Affichage

 L’affichage d’un tableau se fait élément par élément en utilisant une


boucle.

 Exemple
int i; float moy[5];
for(i=0 ; i<5 ; i++)
{
printf( \n La moyenne de l’étudiant %d est %f \n , i+1, moy[i]);
}

101
Les tableaux : taille maximale et taille réelle

 La taille maximale d’un tableau est spécifiée lors de la déclaration


(une zone mémoire de la taille correspondante lui est réservée).

 La taille réelle d’un tableau est le nombre d’élément réellement


utilisés par le programme. Elle n’est déterminée que lors de
l’exécution.

 La taille réelle d’un tableau est inférieure ou égale à la taille


maximale.
• Par exemple, on peut déclarer un tableau de 10 éléments et n’utiliser
que les 6 premiers éléments

102
Les tableaux : Application1

 La saisie d’un tableau ordonné (les éléments de ce tableau suivent


un ordre croissant ou décroissant)

 Croissant : quand chaque élément est plus grand que ceux d’indice
inférieur et plus petit que ceux d’indice supérieur
………………
5 9 15 98 176 876

 Décroissant : quand chaque élément est plus petit que ceux d’indice
inférieur et plus grand que ceux d’indice supérieur

………………
998 345 134 98 55 32
103
Les tableaux : Application2

 Un programme permettant le calcul de la moyenne des notes des


matières d’un étudiant.
Remarque
Le nombre de matières est à saisir.
Les notes sont comprises entre 0 et 20.

104
Tableaux et Pointeurs
 Les identificateurs de Tableaux et de pointeurs sont très similaires.

 L’identificateur d’un pointeur désigne l’adresse de la première case


mémoire de la variable sur laquelle il pointe
 L’identificateur d’un tableau désigne l’adresse de la première case
mémoire du tableau

 Il existe une différence majeure:


 La valeur du pointeur peut être modifiée.
 L’adresse du tableau ne peut être modifiée.

 L’identificateur d’un tableau est considéré comme un pointeur.

105
Tableaux et Pointeurs: exemple
 Soit T un tableau de 4 entiers initialisé par {1, 2, 3, 4}.
La représentation de ce tableau en mémoire est la suivante :

T[0] T[1] T[2] T[3] T

 Comme on le voit clairement sur la figure ci-dessus, un tableau est


une constante de type pointeur, qui pointe sur le premier élément
d'une suite d'éléments contigus de même type.

106
Tableaux et Pointeurs

 Soit T l’identificateur d’un tableau

 T = adresse du premier élément du tableau

 T[i] = *(T+ i) ;

 Exemple:
char T[80] ;
*T = ‘C‘ ; /* accès au premier caractère */
*(T + 5) = ‘V‘ ; /* accès au 6ème caractère */
107
Tableaux et Pointeurs: exemple
 Les deux programmes sont parfaitement identiques

#include <stdio.h> #include <stdio.h>


#include <stdlib.h> #include <stdlib.h>
main() main()
{ {
int i = 0; int i = 0;
int T[4]; int T[4];
T[0] = 1; *(T+0) = 1;
T[1] = 2; *(T+1) = 2;
T[2] = 3; équivalente *(T+2) = 3;
T[3] = 4; *(T+3) = 4;
for (i = 0 ; i < 4 ; i++) for (i = 0 ; i < 4 ; i++)
{ {
printf("%d\t", T[i]); printf("%d\t", *(T+i));
} }
} }

108
Tableaux et Pointeurs

 Le nom d’un tableau est une adresse constante et non pas un


pointeur qui est une variable.

 Exemple
int Tab[10], *Ptr ;
Ptr = Tab ; /* Correcte */
Tab = Ptr ; /* ERREUR */
0 1 2 3 4 5 6 7 8 9 10
Tab

Ptr
109
Tableaux et Pointeurs

 Les Tableaux Statiques

 Exemple
char texte[20];
int valeurs[100];

 Sont alloués (réservés) en mémoire par le compilateur d’une façon


automatique dés la déclaration

 Disparaissent automatiquement quand le programme qui les a créés


finit son exécution.
110
Tableaux et Pointeurs

 les Tableaux Dynamiques


 Exemple:
char * texte;
int * valeurs;

 Allocation (réservation) en mémoire se fait manuellement par le


programmeur pour optimiser l’utilisation de la mémoire.

 Toute utilisation avant allocation rend le programme instable


(blocage au niveau d’exécution).

111
Tableaux et Pointeurs

 Intérêt de l’allocation dynamique

 Permet une gestion plus flexible de la mémoire.

 Un programme n’utilise que la mémoire dont il a besoin au moment


où il en a besoin.

 On évite de monopoliser de l’espace mémoire aux instants où on en


a pas besoin.

 Par contre, on doit libérer la mémoire sinon l’allocation de mémoire


perd son intérêt.
112
Tableaux et Pointeurs

 Allocation dynamique de la mémoire pour un tableau


 On utilise la fonction malloc( ) comme suit :
 Soit T un tableau à une dimension
int * T;
T = (int*)malloc(20*sizeof(int));

Nom du pointeur Nombre d’éléments du Fonction de calcul


Tableau automatique de la taille
d'un entier en octet
Fonction d’allocation
de la mémoire 113
Tableaux et Pointeurs

 Désallocation de la mémoire allouées pour les


tableaux :

 On utilise la fonction free( ) comme suit :

pour un Tableau à une dimension:


free(T);

114
Tableaux —Paramètres d’une fonction
• Déclaration de la fonction
– Si on ne veut pas modifier la taille du tableau
type nom_fonc1 ( type tab[CAP], int taille) ;
type nom_fonc2 ( type tab[ ], int taille) ;
type nom_fonc3 ( type *tab, int taille) ;

– Si on veut modifier la taille du tableau


type nom_fonc11 ( type tab[CAP], int *taille) ;
type nom_fonc22 ( type tab[ ], int *taille) ;
type nom_fonc33 ( type *tab, int *taille) ;

• Appel de la fonction
type tab[10] ;
int n ; /* taille du tableau */
nom_fonc1(tab,n) ;
nom_fonc11(tab,&n) ;

115
Plan de la séance 4
 Tri d’un tableau
 Tri par sélection

 Tri à bulle

116
Le tri d’un tableau

117
Notion de tri d’un tableau
 Les tableaux permettent de stocker plusieurs éléments de même
type au sein d’une seule entité

 Lorsque les éléments du tableau ne possède pas un ordre total,


on peut donc les ranger en ordre croissant ou décroissant

 Trier un tableau c’est donc ranger ses éléments en ordre


croissant ou décroissant

 Dans cette partie de cours on ne fera que des tris en ordre


croissant. c.à.d. les éléments des tableaux seront rangés de la
plus petite valeur à la plus grande

118
Tri par sélection
 Principe :
 Pour chaque indice d’élément dans le tableau, on sélectionne
l’élément du tableau qui doit y être et on le place à cet indice
 On sélectionne la bonne valeur qu’on place au bon
emplacement.

 Ainsi, en faisant un tri dans un ordre croissant,


 On parcourt le tableau de gauche vers droite, pour chaque
emplacement (indice),
 On sélectionne la plus petite valeur dans le sous tableau de
droite et on la met à cet emplacement.

119
Tri par sélection : Exemple
 Soit le tableau suivant

50 12 86 3 954 20 124

3 12 86 50 954 20 124

3 12 86 50 954 20 124

120
Tri par sélection : Exemple

3 12 20 50 954 86 124

3 12 20 50 954 86 124

3 12 20 50 86 954 124

3 12 20 50 86 124 954
121
Tri par sélection : Algorithme
 Soit T[N] un tableau de N éléments :

Pour i allant de 0 à N-2 faire

Chercher la plus petite valeur dans le sous tableaux de droite

Placer cette valeur dans T[i]

finpour

122
Tri par sélection : Algorithme
Pour i allant de 0 à N-2 faire
indice_min  i
pour j allant de i+1 à N-1 faire
si (T[j] < T[indice_min]) alors
indice_min  j
finsi
finpour
si ( i ≠ indice_min) alors
Aide  T[indice_min]
T[indice_min]  T[i]
T[i]  Aide
finsi
finpour
123
Tri à bulle
 Principe :

 Parcourir tout le tableau en comparant successivement les


éléments du tableau deux à deux. Permuter les deux
éléments comparés s’ils ne sont pas dans l’ordre.

 Cette opération est répétée plusieurs fois jusqu’à ce que le


tableau soit entièrement parcouru sans réaliser aucune
permutation

124
Tri à bulle : Exemple
 Soit le tableau suivant

50 12 86 3 954 20 124

12 50 86 3 954 20 124

12 50 86 3 954 20 124

12 50 3 86 954 20 124

125
Tri à bulle : Exemple

12 50 3 86 954 20 124

12 50 3 86 20 954 124

12 50 3 86 20 124 954

126
Tri à bulle : Exemple

12 50 3 86 20 124 954

12 50 3 86 20 124 954

12 3 50 86 20 124 954

12 3 50 86 20 124 954

127
Tri à bulle : Exemple

12 3 50 20 86 124 954

12 3 50 20 86 124 954

128
Tri à bulle : Exemple

12 3 50 20 86 124 954

3 12 50 20 86 124 954

3 12 50 20 86 124 954

3 12 20 50 86 124 954

129
Tri à bulle : Exemple

3 12 20 50 86 124 954

3 12 20 50 86 124 954

3 12 20 50 86 124 954

En parcourant tout le tableau (jusqu’au dernier élément bien


placé) sans faire aucune permutation, cela signifie que :
 Tableau est dans l’ordre (le tableau est trié)
130
Tri à bulle : Algorithme
terme_tri  N-2
Répéter
ordre  vrai
pour i allant de 0 à terme_tri faire
si (T[i] > T[i+1]) alors
Aide  T[i]
T[i]  T[i+1]
T[i+1] Aide
ordre  faux
finsi
finpour
si (ordre = faux) alors
terme_tri  terme_tri -1
finsi
Jusqu’à (ordre = vrai)
131
Plan de la séance 5
 Recherche d’un élément dans un tableau
Recherche simple

Recherche dichotomique

 Tableaux à plusieurs dimensions


Cas des tableaux 2D

Pointeurs et Tableaux 2D

132
Recherche d’un élément
dans un tableau

133
Recherche d’élément dans un tableau
 On distingue deux types de recherches d’éléments dans un
tableau :
 Recherche simple : consiste à chercher une valeur dans un
tableau (trié/ non trié) et de fournir comme résultat :
 L’indice de la première apparition de cette valeur,
 Les indices de toutes les apparitions de cette valeur,
 Le nombre d’apparition de cette valeur.
 Recherche dichotomique : consiste à chercher un élément
dans un tableau trié et de fournir comme résultat :
 L’indice de la première occurrence, C’est une technique de
recherche extrêmement rapide et efficace
134
Recherche d’élément dans un tableau
 Soit le tableau suivant :
0 1 2 3 4 5 6 7
12 50 3 86 954 20 124 86

 Si on cherche la valeur 86, on aura comme résultat :


 Soit l’indice de la première occurrence de la valeur 86 qui est
«3»
 Soit les indices de toutes les occurrences de la valeur 86 qui
sont « 3, 7 »
 Soit le nombre des occurrences de la valeur 86 qui est « 2 »

135
Recherche simple : Algorithme
 Recherche simple dans un tableau trié ou non trié.
Soit x l’élément recherché

i0
Tant que (i<N) et (T[i] ≠x) faire
i  i+1
Fintantque
Si i=N alors
ecrire(" la valeur", x, "n’existe pas ")
Sinon
ecrire(" la valeur " , x , "est dans la position ",i)
Finsi 136
Recherche dichotomique : Algorithme
deb  0
fin  N-1
milieu  (deb + fin) div 2
Tant que ( (V ≠ T[milieu]) et (fin > deb) ) faire
si (T[milieu] < v) alors
deb  milieu + 1
sinon
fin  milieu - 1
finsi
milieu  (deb + fin) div 2
Fintantque
si ( T[milieu] = V) alors
Ecrire (" La valeur « , V, " existe à l’indice :", milieu)
sinon
Ecrire (" La valeur, " V " ,n’existe pas dans le tableau")
finsi
137
Recherche dichotomique : exemple
Soit le tableau suivant :
0 1 2 3 4 5 6 7
3 12 20 50 86 124 954
Si on recherche la valeur 86, on aura les étapes suivantes :
deb = 0 fin = 6  milieu = 3
T[3] = 50 ≠ 86 et 6 > 0
50 < 86  deb milieu + 1 = 4
milieu  (6 + 4) div 2 = 5
T[5] = 124 ≠ 86 et 6 > 4
124 > 86  fin milieu - 1 = 4
milieu (4 + 4) div 2 = 4
T[4] = 86 = 86  fin de la boucle tant que
T[4] = 86 valeur existe au tableau à l’indice 4.
138
Les tableaux à plusieurs dimensions

139
Tableaux à plusieurs dimensions
 Le langage C permet l’utilisation des tableaux à plusieurs
dimensions

 Concerne principalement, le traitement matriciel.

 Une matrice est souvent représentée comme un tableau à deux


dimensions.

 On peut facilement imaginer un traitement cubique sur des


tableaux à 3 dimensions.

 Par exemple : calculer et sauvegarder les valeurs d’une fonctions


f(x, y, z) définie sur IR3
140
Tableaux à plusieurs dimensions
 Déclaration : La déclaration d’un tableau à plusieurs dimensions
se fait de la même façon qu’un tableau unidimensionnel suivant
la syntaxe :
type Nom_Tableau[dimesion1][dimension2] .. [dimensionN];

 Exemple :
float matrice[5][6];
int courbe[20][20];
float représentation_spatiale[10][5][8];
int projection_3D[50][50][50];

141
Le cas de tableaux 2D : initialisation
 initialisation (à deux dimensions) :
 Initialisation de tout le tableau (matrice) :
 1ère méthode : on spécifie les valeurs de chaque ligne entre { }
et toute la matrice entre { }
Exemple : int T[3][5] = { { 5, 4, 9, 2, 6 },
{ 76, 14, 39, 82, 56 },
{ 512, 467, 982, 209, 634 } };
 2ème méthode : on spécifie les valeurs de toute la matrice (par
ligne) entre { }
Exemple : int T[3][5] = { 5, 4, 9, 2, 6, 76, 14, 39, 82, 56, 512,
467, 982, 209, 634 };

142
Le cas de tableaux 2D : initialisation

T[0][0] T[0][1] T[0][2] T[0][3] T[0][4]

5 4 9 2 6
T[1][0] T[1][1] T[1][2] T[1][3] T[1][4]

76 14 39 82 56
T[2][0] T[2][1] T[2][2] T[2][3] T[2][4]

512 467 982 209 634


143
Le cas de tableaux 2D : initialisation
 initialisation (à deux dimensions) :
 Initialisation partielle d’un tableau 2D (matrice) :
 On spécifie les valeurs de chaque ligne entre { } et toute la
matrice entre { }
Exemple : int T[3][5] = { { 5 },
{ 76, 14},
{ 512, 467, 982 } };

Ce qui n’est pas équivalent à :


int T[3][5] = { 5, 76, 14, 512, 467, 982 };

144
Le cas de tableaux 2D : initialisation
int T[3][5] = { { 5 }, { 76, 14}, { 512, 467, 982 } }

T[0][0] T[0][1] T[0][2] T[0][3] T[0][4]

5 0 0 0 0
T[1][0] T[1][1] T[1][2] T[1][3] T[1][4]

76 14 0 0 0
T[2][0] T[2][1] T[2][2] T[2][3] T[2][4]

512 467 982 0 0


145
Le cas de tableaux 2D : initialisation
int T[3][5] = { 5 , 76, 14, 512, 467, 982 }

T[0][0] T[0][1] T[0][2] T[0][3] T[0][4]

5 76 14 512 467
T[1][0] T[1][1] T[1][2] T[1][3] T[1][4]

982 0 0 0 0
T[2][0] T[2][1] T[2][2] T[2][3] T[2][4]

0 0 0 0 0
146
Tableaux 2D : Exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int T[50][50];
int i, j, NL, NC ;
/* Saisir les éléments d’un tableau 2D */
do{
printf("Saisir les dimensions de T (NL,NC) : ");
scanf(" %d %d", &NL, &NC);
}
while(NL>50 || NL<=0 || NC>50 || NC<=0);
for (i = 0 ; i < NL ; i++)
{
for (j = 0 ; j < NC ; j++)
{
printf("T[%d][%d] = " , i,j);
scanf("%d", &T[i][j]);
}
} 147
}
Tableaux 2D : Exemple
#include <stdio.h>
#include <stdlib.h>
main()
{
int T[2][2] = {1, 2, 3, 4};
int i, j ; /* Afficher les éléments d’un tableau 2D */

for (i = 0 ; i < 2 ; i++)


{
for (j = 0 ; j < 2 ; j++)
{
printf("T[%d][%d] = %d \t" , i, j, T[i][j] );
}
printf("\n");
}
}

148
Pointeurs et tableaux 2D

149
Pointeurs et Tableaux 2D
 Un tableau 2D est considéré comme un tableau de tableaux de
dimension 1 (chaque élément est un tableau de dimension 1)

 On peut donc dire que le nom d'un tableau 2D est l'adresse d'un
tableau d'adresse de tableaux de dimension 1

 On dit aussi qu'il s'agit d'un pointeur de pointeur

 Exemple:
int TAB[6][7];
int **Ptr; /* déclaration d'un pointeur de pointeur */
Ptr = TAB; /* initialisation du pointeur de pointeur */

150
Pointeurs et Tableaux 2D
 Lien entre le nom d’un tableau 2D et les pointeurs
TAB

Tableau de pointeurs vers des tableaux


d‘un type prédéfini

0 1 2 3 4 5 6

5
151
Pointeurs et Tableaux 2D
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
main() main()
{ {
int TAB[2][2]; int TAB [2][2];
int i, j ; int i, j;
TAB[0][0] = 1; est *(*(TAB+0) + 0) = 1;
TAB[0][1] = 2; équivalent à *(*(TAB+0) + 1) = 2;
TAB[1][0] = 3; *(*(TAB+1) + 0) = 3;
TAB[1][1] = 4; *(*(TAB+1) + 1) = 4;
for (i = 0 ; i < 2 ; i++) for (i = 0 ; i < 2 ; i++)
{ {
for (j = 0 ; j < 2 ; j++) for (j = 0 ; j < 2 ; j++)
printf("%d\t", TAB[i][j]); printf("%d\t", *(*(TAB+i)+j));
printf("\n"); printf("\n");
} }
} }
152
Pointeurs et Tableaux 2D : Tableau dynamique

 Allocation dynamique de la mémoire pour un tableau de deux


dimensions :
 On utilise la fonction malloc( ) comme suit :
 Soit TAB un tableau de 2 dimensions de NL ligne et NC colonne.

int ** TAB, i, NL, NC;


TAB = (int**)malloc( NL * sizeof(int*) );
for (i=0; i<NL; i++)
TAB[i] = (int*)malloc( NC*sizeof(int) );

153
Pointeurs et Tableaux 2D : Tableau dynamique

 Libération de la mémoire allouée pour les tableaux :

 On utilise la fonction free( ) comme suit :


 Tableau à 2 dimensions :

for (i=0;i<NL;i++)
free(TAB[i]) ;
free(TAB);

154
Plan de la séance 6
 Chaînes de caractères

 Les structures

 Les énumérations

155
Les chaines de caratères

156
Chaînes de caractère: déclaration
 Définition
Une chaîne de caractères en langage C est un tableau de caractères.

 Déclaration
char <Nom_chaine> [Longueur];

Exemples
char NOM [20], char PRENOM [20], char PHRASE [300];
La représentation interne d'une chaîne de caractères est terminée par
le symbole '\0' .
Ainsi, pour une chaine de N caractères, nous devons prévoir une taille
N+1
157
Chaînes de caractère: Initialisation
 Initialisation caractère par caractère :
Exemple : char mot[]={‘S’, ‘a’, ‘l’, ‘u’, ‘t’, ‘\0’} ;
Pour cette chaine le compilateur réserve
6 * taille(caractère) = 6* 1octet = 6 octets

 Initialisation par suite de caractères :


Exemple : char mot[] = "Salut" ;
Cette chaine est composée de 5 caractères mais le compilateur
réserve une place mémoire de 6 octets parce qu’il ajoute le
caractère ‘\0’ pour marquer la fin de la chaine.

158
Chaînes de caractère : Initialisation
 Remarque :
on peut reprendre les deux initialisations précédentes en
spécifiant la taille de la chaine entre crochés (comme pour les
tableaux).

Exemple : char mot[6]={‘S’, ‘a’, ‘l’, ‘u’, ‘t’, ‘\0’} ;


char mot[6] = "Salut" ;

Il faut vérifier que la taille du tableau de caractères est


supérieure au nombre de caractères dans la chaîne
d’initialisation.
159
Chaînes de caractère : Saisie
Pour saisir une chaîne de caractères, on utilise les deux fonctions
suivantes :
 La fonction scanf( ) avec le format %s
Exemple : char mot[40] ;
scanf("%s", mot) ;
Remarque :
en utilisant la fonction scanf( ), le compilateur va saisir la suite de
caractères (caractère par caractère) jusqu’au premier « espace »
rencontré. C'est-à-dire que le caractère « espace » est considéré
comme un séparateur et interprété comme la fin de la chaine.
scanf( ) est idéale pour saisir plusieurs chaines sur la même ligne.
160
Chaînes de caractère : Saisie

 La fonction gets( )

Exemple : char mot[40] ;


gets(mot) ;

Remarque :
en utilisant la fonction gets( ), le compilateur va saisir toute la
suite de caractères jusqu’au « retour à la ligne ».

161
Chaînes de caractère : Affichage
Pour afficher une chaîne de caractères, on utilise les deux fonctions
suivantes :

 La fonction printf( ) avec le format %s

Exemple :
char chaine[40] ;
/* saisir la chaine avec scanf ou gets */
printf("la chaine saisie est : %s", chaine) ;

162
Chaînes de caractère : Affichage

 La fonction puts( )

Exemple :
char chaine[40] ;
/* saisir la chaine avec scanf ou gets */
puts(chaine) ;

Remarque :
puts(chaine) est équivalente à printf("%s\n",chaine)
163
Chaînes de caractère
Fonctions pour le traitement des chaînes de caractères <string.h>

 strlen(s):
fournit la longueur de la chaine s sans compter le caractère ‘\0’.

 strcpy(s, t) :
copie t dans s

 strcat(s, t) :
ajoute t à la fin de s
164
Chaînes de caractère
Fonctions pour le traitement des chaînes de caractères (suite)
 strcmp(s, t) :
compare s et t lexicographiquement et fournit un résultat :
-1 si s précède t
0 si s égale à t
1 si s suit t
 strncpy(s, t, n) :
copie au plus n caractères de t dans s.

 strncat(s, t, n) :
ajoute au plus n caractères de t à la fin de s.
165
Chaînes de caractère
Fonctions de classification et de conversion
 isupper(c) :
Vérifie si c est une majuscule ('A'...'Z'). Fournit une valeur:
 différente de zéro si c est une majuscule
 et zéro sinon.

 islower(c) :
Vérifie si c est une minuscule ('a'...'z'). Fournit une valeur:
 différente de zéro si c est une minuscule
 et zéro sinon

 isdigit(c) :
Vérifie si c est un chiffre décimal ('0'...'9'). Fournit une valeur:
 différente de zéro si c est un chiffre
 et zéro sinon 166
Chaînes de caractère
Fonctions de classification et de conversion (suite)
 isalpha(c) :
vérifie si islower(c) ou isupper(c). Fournit une valeur:
 différente de zéro si c est une majuscule ou c est une minuscule
 et zéro sinon

 isalnum(c):
vérifie si isalpha(c) ou isdigit(c). Fournit une valeur:
 différente de zéro si c est une lettre ou chiffre
 et zéro sinon.

 isspace(c):
vérifie si c est un signe d'espacement (' ', '\t', '\n', '\r', '\f'). Fournit une valeur:
 différente de zéro si c est un caractère d’espacement
 et zéro sinon. 167
Les structures et énumérations

168
Les structures

 Intérêt
 Rassembler des données hétérogènes caractérisant une
entité pour en faire un type utilisateur.

 Exemple
 point dans l'espace 3 entiers
 nœud d'un arbre binaire 2 adresses vers les fils, 3 entiers
pour les données du nœud
 Une personne ayant un nom, un prénom, un âge et une
adresse.
169
Les structures

 Déclaration
struct nom_structure {

type1 nomchamps1;

type2 nomchamps2;

typeN nomchampsN;

};

170
Les structures
 Exemple et utilisation
struct point {
int x;
int y;
int z;
char nom;
};

main() {
struct point p;
}
171
typedef: création d’un type de donnée
 Il est possible en C de définir un nouveau type de données grâce au
mot clé typedef

typedef <Caracteristiques_du_type> <Nom_du_type>

 Caracteristiques_du_type:

représente un type de données existant (par exemple float, short int,...)

 Nom_du_type:

définit le nom que vous donnez au nouveau type de donnée

Exemple typedef char TAB[ 50] Chaine

On crée un type de donnée Chaine calqué sur le type char TAB[50]

char T1[ 50], T2[ 50], T3[ 50]  Chaine T1,T2,T3 172
Les structures: utilisation de typedef
 Simplification de l'écriture
struct pt {
int x; typedef struct pt
int y; {
int z; int x;
Notations
char nom; équivalentes
int y;
}; int z;
char nom;
typedef struct pt point;
} point;
main()
{
point p;
} 173
Les structures
 Accès aux données
 Deux cas:
1°/ On dispose du nom de la variable
Accès par: NomVariable.NomChamps
Exemple
main()
{
point p1;
p1.x = 8;
p1.y = 9;
p1.z = 10;
printf("%d",p1.z);
174
}
Les structures
 2°/ On dispose de l'adresse de la variable (pointeur)
Accès par: NomVariable->NomChamps
Identique à (*NomVariable).NomChamps (lourde à manipuler)
Exemple
main()
{
point *pp1, p1;
pp1 = &p1;
pp1->x = 8;
pp1->y = 9;
pp1->z = 10;
printf("%d",pp1->z);
175
}
Les Enumérations
 Définition :

Les énumérations sont des entités qui permettent de définir un


type par la liste des valeurs qu’il peut prendre.

 Déclaration :

Syntaxe de déclaration :

enum nom_enum {valeur_1, valeur_2, .., valeur_n};

176
Les Enumérations: Exemple
1°/enum booleen {faux, vrai} ;

/* déclaration du type énumération booleen */

enum booleen ordre ;

/* déclaration de la variable qui s’appelle ordre de type enum booleen */

ordre = vrai ;
/* affectation de la valeur « vrai » à la variable « ordre » */

2°/enum jour {Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi,


Dimanche} ;

177
Les Enumérations

Remarque:

Les différentes valeurs d’un type énumération sont représentées

comme des entiers.

Les valeurs possibles {valeur_1, valeur_2, ..,valeur_n}

sont codées par les entiers {0, 1, .., n-1}

178

Vous aimerez peut-être aussi