Vous êtes sur la page 1sur 173

Algorithmique et programmation C

Plan du cours
- Introduction
- Notions d'algorithmes
- Concepts de base du langage c
- Etapes et démarches de résolution algorithmique
- Les tableaux
- Les pointeurs
- Les fonctions

Pr. Oumayma BANOUAR Année universitaire: 2018-2019


oumayma.banouar@gmail.com
Filière: STID
Chapitre I: Introduction

• Architecture et composants matériels de l’ordinateur


• Composants logiciels de l’ordinateur
• Scenario d’un traitement automatique
• Langage de programmation
• Compilation et exécution d’un programme en C

• L'informatique est la science du traitement automatique (moyennant l'ordinateur) de l'information.


• Elle a pour objet
• d'élaborer et de formuler l'ensemble de commandes, d'ordres ou d'instructions permettant de commander
l'ordinateur et de l'orienter lors du traitement.

2
Architecture et composants matériels de l’ordinateur

1- L'unité centrale constituée de :


• L'unité de traitement (UT) qui commande tout traitement fait
par l'ordinateur.
• L'unité de calcul (UC) qui effectue les opérations
(arithmétiques, logiques…) commandées par l'UT.
• L'ensemble UT, UC est appelé processeur.
• La mémoire centrale qui sert de support de stockage de
données. On signale ici qu’il s’agit d’une mémoire volatile.

3
Architecture et composants matériels de l’ordinateur

2- L'unité d'échange constituée de :


• Les périphériques d'entrée/sortie comme le clavier, la souris,
l'écran et l’imprimante.
• La mémoire secondaire qui sert également de support de
stockage de données. Elle est permanente et se caractérise par
une capacité supérieure à celle de la mémoire centrale.

4
Architecture et composants matériels de l’ordinateur

• Le composant mémoire est physiquement un ensemble


de cellules mémoire (octets) contenant des données
sous forme binaire.
• Un octet est constitué de 8 bits (digits contenant les
chiffres 0 ou 1).
• Un kilooctet (KOctet) est composé de 1024 (210)
octets.

5
Composantes logiciels de l’ordinateur

• Tout traitement automatique peut être réalisé au moyen d'un ou de plusieurs programmes.
• Un programme est une série d'instructions (opérations) que la machine peut exécuter pour effectuer des
traitements donnés.
• Un logiciel est en général un ensemble de programmes visant à effectuer automatiquement un traitement
ou une tâche complexe.
• Une machine peut héberger plusieurs logiciels au choix de son utilisateur.
• Un système d'exploitation dit aussi système opératoire est un logiciel de base qui doit faire l'objet de la
première installation.

6
Composantes logiciels de l’ordinateur

• Un système d'exploitation fut un ensemble de programmes assurant d'une part, le fonctionnement de


toutes les composantes matérielles d'un ordinateur et d'autre part, la communication Homme/Machine.
• Il a pour exemples de fonctions :
- La gestion de la mémoire.
- La gestion des périphériques.
- La gestion de partage de ressources entre plusieurs utilisateurs.
- Système de fichiers.
- Interface utilisateur.
• Comme exemples de systèmes opératoires, nous citons Windows, Unix, Linux, Ms Dos, MacOs...

7
Scénario d’un traitement automatique

• Faire effectuer un traitement automatique par la machine nécessite de lui indiquer :


• la source de données (sur quoi porte le traitement),
• les opérations ou actions élémentaires à effectuer pour atteindre l'objectif visé
• la destination où elle doit renvoyer les résultats.

• L’ensemble de ces informations constitue ce qu’on appelle un algorithme que le programmeur doit encore
traduire en programme exécutable par la machine.

Actions

8
Scénario d’un traitement automatique

Extraction des données à traiter par le processeur à partir de la


mémoire secondaire ou centrale ou à partir des utilisateurs en
utilisant un périphérique d’entrée

Exécution des opérations Résultats affichés sur le


élémentaires d’une manière périphérique de sortie
séquentielle selon l’ordre prévu
par le programme

Mémorisation des résultats


intermédiaires Renvoie des résultats attendus

9
Scénario d’un traitement automatique

Exemple :
Pour calculer le montant total d’une facture de téléphone pour des appels locaux effectués le soir, le
programmeur doit préciser au processeur :

• les données (les entrées consommation, prix_unitaire, la TVA et le prix_d_abonnement) à


demander à l'utilisateur.
• l'ordre des opérations à faire et les résultats intermédiaires à mémoriser : il s'agit de calculer
respectivement le prix hors taxe (PHT) et le prix total (PT).
• Le résultat final (PT) à afficher

10
Scénario d’un traitement automatique

• les données (les entrées consommation, prix_unitaire, la TVA et le prix_d_abonnement) à demander à


l'utilisateur.

Lire (consommation, prix_unitaire,TVA, prix_d_abonnement)


• l'ordre des opérations à faire et les résultats intermédiaires à mémoriser : il s'agit de calculer respectivement
le prix hors taxe (PHT) et le prix total (PT).

PHT(consommation * prix_unitaire) + prix_d_abonnement


PT PHT * (1+TVA)

• Le résultat final (PT) à afficher


Ecrire PT

11
Scénario d’un traitement automatique

Exemple d’application:
Dans le cas où on donne:
• une consommation de 100 unités
• avec 0.50 Dh comme prix unitaire
• 0.2 comme taux de la TVA
• et 70 Dh comme prix d’abonnement,

Le processeur:
• demandera les données (100, 0.50, 0.2 et 70) à l'utilisateur
• calculera dans l'ordre indiqué chaque expression élémentaire et mémorise son résultat :
PHT=(100*0.5)+70=120 PT=120*(1+0.2)=144
• Affichera enfin le résultat final PT (144).

12
Langage de programmation

• On vient de voir que pour pouvoir effectuer un traitement donné, la machine doit disposer du programme
exécutable correspondant.

• Ce programme doit se trouver en mémoire et doit alors être codé en binaire (langage machine).

• Un langage de programmation permet au programmeur d'écrire son programme suivant une


grammaire qui peut être, soit celle du langage machine même, soit une grammaire facilement interprétable
par la machine ou pouvant être traduite en langage machine au moyen d'un outil logiciel dit compilateur du
langage.

Trois catégories de langages


1- Le langage binaire 2- Les langages de bas niveau 3- Les langages évolués

13
Langage de programmation

• Le langage binaire
Il s'agit du langage machine exprimé par des chiffres (0 ou 1).
Ce langage produit des programmes automatiquement consommables (compréhensibles) par la machine
mais qui sont illisibles et non portables.

• Les langages de bas niveau (comme l'assembleur)


Ces langages produisent des programmes facilement interprétables par la machine mais d'utilisation lourde
pour les programmeurs.

• Les langages évolués


Ils sont, d'utilisation, souples et produisent des programmes clairs et lisibles mais ils doivent encore être
compilés (traduits en langage machine par un compilateur du langage) pour générer des programmes
exécutables. Nous en citons: Fortran, Basic, Pascal, C, C++, Visual Basic, Visual C++, Java...

14
Langage de programmation

15
Compilation et exécution d’un programme

Générer un programme exécutable à partir d’un programme source (écrit en C et dont le nom de fichier
se termine nécessairement par l'extension .c) consiste à faire appel au compilateur et éditeur de lien du
langage moyennant la commande Unix cc.
• Le compilateur traduit le programme source en un fichier objet (qui porte l'extension.o).
• L'éditeur de liens génère pour les différents fichiers objet composant le programme un fichier
exécutable.

Pour exécuter un programme, il suffit de taper le nom de son exécutable.

16
Chapitre II: Qu’est ce qu’un algorithme?
• Qu’est ce qu’un algorithme
• Opérations de base
• Exemple

17
Qu’est ce qu’un algorithme?

• Le terme algorithme est employé en informatique pour décrire une méthode de résolution de problème
programmable sur machine.
• Un algorithme est une suite finie et ordonnée d'opérations (actions) élémentaires finies (en temps et
moyens).
• Il est régie par un ensemble de règles ou d'instructions de contrôle (séquencement, sélection et
itération) permettant d'aboutir à un résultat déterminé d'un problème donné.

Un problème donné pourraient correspondre plusieurs algorithmes.

18
Qu’est ce qu’un algorithme?

• Plusieurs opérations de base peuvent composer un algorithme.

• Elles sont décrites en pseudocode (pseudolangage).

• Un pseudolangage est un langage informel:


• proche du langage naturel
• indépendant de tout langage de programmation.

• Les données manipulées dans un algorithme sont appelées des variables.

19
Opérations de base

• L'affectation, notée par le symbole , est l'opération qui évalue une expression (constante ou une
expression arithmétique ou logique) et attribue la valeur obtenue à une variable.

20
Opérations de base

• La lecture permet d'attribuer à une variable une valeur introduite au moyen d'un organe d'entrée
(généralement le clavier).

21
Opérations de base

• L’écriture communique une valeur donnée ou un résultat d'une expression à l'organe de sortie.

22
Opérations de base

• Instructions de contrôle
• Instructions sélectives
• Instruction Si
Indique le traitement à faire selon qu’une condition (expression logique) donnée est satisfaite
ou non. Il est possible d’omettre début et fin si le bloc d’instructions à exécuter est constitué
d’une seule instruction.

23
Opérations de base

• Instructions de contrôle
• Instructions sélectives
• Instruction Si

24
Opérations de base

• Instructions de contrôle
• Instructions sélectives
• Instruction Si

Une instruction de contrôle peut se réduire à :

On peut avoir plusieurs si imbriqués comme:

25
Opérations de base

26
Opérations de base

• Instructions de contrôle
• Instructions sélectives
• Instruction Selon

Elle indique le traitement à faire selon la valeur d'une variable.

27
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Pour

Elle permet de répéter un traitement un nombre de fois précis et connu en utilisant un compteur (variable
à incrémenter d'une itération à l'autre).

28
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Pour

29
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Tant que
Elle permet de répéter un traitement tant qu'une condition est satisfaite.

30
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Tant que

31
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Faire Tant que
Elle permet de répéter un traitement tant qu'une condition est satisfaite.

32
Opérations de base

• Instructions de contrôle
• Instructions itératives
• Instruction Faire Tant que

33
Exemple d’application

Conversion dans une base


Réaliser un algorithme qui affiche le résultat de conversion d’un nombre entier positif
strictement dans une base quelconque (comprise entre 2 et 10).

Entrées : Le nombre n et la base b.


Sorties : Le résultat de conversion r.
Traitement : Convertir le nombre n en base b.
Cas particuliers : n ≤ 0, b < 2 et b > 10.

34
Exemple d’application

Analyse par exemple


n=11 et b=2

35
Exemple d’application

36
Exemple d’application

37
Exemple d’application

Multiplication à la russe

Ecrire l’algorithme de la multiplication russe qui consiste à calculer le produit de deux entiers a et b en
procédant par une succession parallèle du calcul du double de b et la moitié de a jusqu’à ce que la
moitié devient égale à 1.
Le produit résultant est la somme des doubles obtenus correspondant à des moitiés impaires.

38
Chapitre III: Concepts de base du langage C

• Structure d’un programme C


• Les directives de compilation
• Les commentaires
• Les variables et constantes
• L’affectation (Assignation)
• Les entrées/sorties
• Les operateurs
• Les instructions sélectives
• Les instructions itératives

39
Introduction

En 1970, Dennis RITCHIE a créé le langage C, un langage de haut niveau, pour écrire le système
d'exploitation Unix. La conception de ce langage a été régie par les pré requis suivants :

• la souplesse
• la fiabilité
• la portabilité

40
Structure d’un programme en C

• Un premier programme en C

41
Structure d’un programme en C

• Structure générale d’un programme en C


Un programme en C se présente en général sous la forme suivante :

42
Structure d’un programme en C

• Structure générale d’un programme en C


Un programme en C se présente en général sous la forme suivante :

Un programme en C doit contenir au moins le


programme principal (la partie main).

Etude des directives de compilation et différents


éléments de base composant le corps du
programme.

43
Les directives de compilation

• include et define

44
Les directives de compilation

• include et define

45
Les commentaires

Un commentaire est un texte placé entre les signes /* et */. Il permet de commenter une ou
plusieurs lignes de commandes en vue d'éclairer le lecteur.

46
Les variables et constantes

• Déclaration des variables

▪ A toute variable utilisée dans un programme C doivent être associés d'abord (avant toute utilisation)
un nom dit identificateur et un type de données (entier, réel ou caractère…).
▪ Lors de l'exécution, une zone mémoire (dont la taille dépend du type) sera réservée pour contenir la
variable

47
Les variables et constantes

• Déclaration des variables

▪ A toute variable utilisée dans un programme C doivent être associés d'abord (avant toute utilisation)
un nom dit identificateur et un type de données (entier, réel ou caractère…).
▪ Lors de l'exécution, une zone mémoire (dont la taille dépend du type) sera réservée pour contenir la
variable

48
Les variables et constantes

• Déclaration des variables


• Identificateurs

L'emploi des identificateurs doit répondre à un certain nombre d'exigences :

• Un identificateur doit être composé indifféremment de lettres et chiffres ainsi que du caractère de
soulignement ( _ ) qui peut remplacer des espaces.
• Un identificateur doit commencer par une lettre ou le caractère de soulignement. Néanmoins, celui-ci est
souvent utilisé pour désigner des variables du système.
• Seuls les 32 premiers caractères (parfois, uniquement les 8 premiers) sont significatifs (pris en compte par
le compilateur).
• Majuscules et minuscules donnent lieu à des identificateurs différents.
• Un identificateur ne doit pas être un mot réservé (utilisé dans le langage C comme int, char, … ).

49
Les variables et constantes

• Déclaration des variables


• Identificateurs

50
Les variables et constantes

• Déclaration des variables


• Types de données
Un type est un ensemble de valeurs que peut prendre une variable.
Il y a des types prédéfinis et des types qui peuvent être définis par le programmeur.

51
Les variables et constantes

• Déclaration des variables


• Types de données

La fonction sizeof retourne la taille en octets d'un objet.

52
Les variables et constantes

• Fonctions prédéfinies sur les types simples

Des fonctions appliquées au différents types de données sont prédéfinies dans des fichiers de
bibliothèque C.

• Fonctions mathématiques

53
Les variables et constantes

54
Les variables et constantes

• Fonctions sur les caractères

55
Les variables et constantes

• Fonctions sur les caractères

56
Les variables et constantes

• Déclaration des constantes

Une constante est une donnée dont la valeur ne varie pas lors de l'exécution du programme. Elle
doit être déclarée sous forme :

57
Les variables et constantes

58
Les variables et constantes

• Initialisation des variables


Une valeur initiale peut être affectée à une variable dès la déclaration sous forme :

59
Les variables et constantes

• Initialisation des variables

Une valeur initiale peut être affectée à une variable dès la déclaration sous forme :

60
Les variables et constantes

• Initialisation des variables

Les caractères spéciaux sont représentés à l'aide du métacaractère \.

61
Les variables et constantes

• Initialisation des variables

62
L’affectation(Assignation)

L'affectation est l'opération qui attribue à une variable, au moyen de l'opérateur =, une valeur
constante ou résultat d'une expression.

63
L’affectation(Assignation)

64
L’affectation(Assignation)

Le langage C permet de faire des assignations entre des variables de types différents.
Des conversions de types sont alors automatiquement réalisées.

65
Les entrées/sorties

• Affichage de données
L’instruction printf permet d'obtenir un affichage formaté à l'écran.

66
67
Les entrées/sorties

• Affichage de données

• Un caractère de contrôle est précédé de \ comme \n qui provoque un).


• Chaque format d'affichage est introduite par le caractère % suivi d'un caractère qui indique le
type de conversion.
• Des indications peuvent être rajoutées entre le % et le caractère comme le nombre minimum de
caractères réservés à l'affichage de la mantisse d'un nombre et le nombre de décimales.

68
Les entrées/sorties

• Affichage de données

69
Les entrées/sorties

• Lecture de données

L’instruction scanf effectue la lecture des variables.

70
Les entrées/sorties

• Lecture de données

L’instruction scanf effectue la lecture des variables.

71
Les entrées/sorties

• Lecture de données

• La notation &variable est utilisée pour indiquer l'adresse mémoire de la variable en question.

• Les données tapées au clavier sont d'abord placées dans un tampon interne. Scanf va chercher ces
données dans ce tampon, sans nécessairement le vider entièrement.

• La fonction scanf est malheureusement une source permanente de problèmes (tampon associé au
clavier encombré de résidus de lectures précédentes). Elle n'est, en général, acceptable qu'à condition
de se limiter à des lectures d'entiers ou de réels.

72
Les opérateurs

• Les opérateurs arithmétiques


Les opérateurs arithmétiques traditionnels sont :

73
Les opérateurs

• Les opérateurs arithmétiques

• L'opérateur / effectue, en fonction du type des opérandes, une division entière (euclidienne) ou réelle.
• L'ordre des priorités des opérateurs est important.
• Il est possible de forcer la conversion du type d'une variable ou d'une expression en les préfixant d'un
type au choix.

74
Les opérateurs

• Les opérateurs arithmétiques

Les opérateurs +=, -=, *=, /= Ils sont utilisés pour faciliter l'écriture.

75
Les opérateurs

• Les opérateurs logiques

Les opérateurs logiques sont,


par ordre décroissant de priorité :

76
Les opérateurs

• Les opérateurs ++ ET --

• Ils permettent d'incrémenter ou de décrémenter une variable.


• L'opérateur ++ (--) effectue une pré-incrémentation (pré-décrémentation) ou une post-
incrémentation (postdécrémentation) selon son emplacement après ou avant la variable.
• Dans une opération d'affectation qui met en jeu l'opérateur de :
• pré-incrémentation (pré-décrémentation), la variable est d'abord incrémentée
(décrémentée) de 1. L'affectation est ensuite effectuée.
• post-incrémentation (post-décrémentation), L'affectation (sans les ++ (--)) est
effectuée avant l'incrémentation (décrémentation).

77
Les opérateurs

• Les opérateurs ++ ET --

78
Les opérateurs

• Les opérateurs ++ ET --

79
Les opérateurs

• Les opérateurs de traitement des bits

Les opérateurs de traitement de bits en C s'appliquent


uniquement à des entiers ou des caractères. Ils ne
s'appliquent, donc, pas à des opérandes réels (de type
float ou double).

80
Les opérateurs

• Les opérateurs de traitement des bits

81
Exercice d’application

Réalisez le programme C qui permet de:


• Lire deux valeurs A et B
• Calculer A exposant B
• Calculer l’hypoténuse d’un triangle rectangle

82
Les instructions sélectives

• Les instructions sélectives


• L’instruction Si → IF

83
Les instructions sélectives

84
Les instructions sélectives

• Les instructions sélectives


• L’instruction Si → IF
Lorsque if est utilisée avec else, elle indique également le traitement à faire si la condition n'est pas
vérifiée.

85
Les instructions sélectives

• Les instructions sélectives


• L’instruction Si → IF

86
Les instructions sélectives

• Les instructions sélectives


• L’instruction Si → IF

87
Les instructions sélectives

• Les instructions sélectives


• L’instruction Switch
Elle réalise un aiguillage vers différentes instructions en fonction du contenu d'une variable de contrôle.
Le sélecteur de switch (la variable de contrôle) doit être un entier ou un caractère.

88
Les instructions sélectives

• Les instructions sélectives


• L’instruction Switch

L'instruction break fait sortir de switch.

89
Les instructions sélectives

• Les instructions itératives


• L’instruction tant que (while)
L'instruction while permet de répéter un traitement autant de fois qu'une condition est vérifiée.
Les instructions en question sont alors exécutées tant que la condition est vraie.

90
Les instructions sélectives

• Les instructions itératives Lors de l'utilisation de l'instruction while, à chaque


• L’instruction tant que (while) itération, la condition est évaluée en premier, avant
l'exécution du traitement.

91
Les instructions sélectives

• Les instructions itératives


• L’instruction faire tant que (do while)
L'instruction do while permet de répéter un traitement jusqu'à ce qu'une condition ne soit plus vérifiée.
Elle joue le même rôle que while.
Lors de l'utilisation de l'instruction while, à chaque itération (fois), le traitement est exécuté en premier,
avant que la condition ne soit évaluée.

92
Les instructions sélectives

• Les instructions itératives Lors de l'utilisation de l'instruction do while, le


• L’instruction faire tant que (do while) traitement sera exécuté au moins une fois quelle que soit
la condition.

93
Les instructions sélectives

94
Les instructions sélectives

• Les instructions itératives


• L’instruction pour (for)
L'instruction for permet de répéter un traitement donné un nombre de fois précis.

95
Les instructions sélectives

• Les instructions itératives


• L’instruction pour (for)

96
Les instructions sélectives

• Les instructions itératives


• Les instructions de sorties de boucles (break et continue)
Break permet de sortir directement de la boucle (for, while ou do while) la plus interne.
Continue permet de passer directement à l'itération suivante de la boucle la plus interne.

97
Les instructions sélectives

• Les instructions itératives


• L’instruction aller a (goto)
L'instruction goto permet de brancher (inconditionnellement) à une ligne du programme. Celle-ci doit avoir
été étiquetée (précédée d'une étiquette constituée d'un identificateur suivi de :)

98
Les instructions sélectives

• Les instructions itératives


• L’instruction aller a (goto)

99
Exemple d’application: Multiplication russe

Multiplication à la russe

Ecrire l’algorithme de la multiplication russe qui consiste à calculer le produit de deux entiers a et b en
procédant par une succession parallèle du calcul du double de b et la moitié de a jusqu’à ce que la moitié devient
égale à 1.
Le produit résultant est la somme des doubles obtenus correspondant à des moitiés impaires.

100
Chapitre IV: Les types composés

• Les tableaux à une dimension (vecteurs)


• Les chaines de caractères
• Les tableaux à plusieurs dimensions

A partir des types prédéfinis du C (caractères, entiers, flottants), on peut créer de nouveaux types,
appelés types composés, qui permettent de représenter des ensembles de données organisées.

101
Les tableaux

• Définition

- Une collection homogène de données, ordonnée et de taille précise.


- Un ensemble d'octets permettant de représenter une liste d'éléments de même type.
- Chaque élément est repéré par un indice (son rang dans le tableau).

102
Les tableaux

• Tableau à une dimension

Un tableau est un ensemble fini d’éléments de même type, stockés en mémoire à des adresses
contiguës.
La déclaration d’un tableau à une dimension se fait de la façon suivante :

103
Les tableaux

• Tableau à une dimension


• Le nombre d’éléments d’un tableau est une expression constante entière positive.

• Par exemple, la déclaration int tab[10] indique que tab est un tableau de 10 éléments de type int.
• Cette déclaration alloue donc en mémoire pour l’objet tab un espace de 10 × 2 octets consécutifs.

• Pour plus de clarté, il est recommandé de donner un nom à la constante taille ou nombre d’éléments
par une directive au préprocesseur, par exemple:
#define nombre_elements 10.

• On accède à un élément du tableau en lui appliquant l’opérateur [].


• Les éléments d’un tableau sont toujours numérotés de 0 à taille-1 ou nombre_elements-1

104
Les tableaux

• Tableau à une dimension

105
Les tableaux

• Tableau à une dimension


• Sur le plan physique

• Lors de la déclaration d'un tableau, une zone mémoire lui sera réservée.
• Elle sera utilisée pour le stockage de ses données.
• La taille de cette zone en octets est la multiplication de la taille du tableau par la taille du
type de ses éléments (un tableau de trois entiers sera représenté par six octets : chaque
entier est codé sur deux octets).
• Un tableau T correspond à l'adresse mémoire de son premier élément (T=&T[0]).
• Il s'agit de la première cellule de la zone mémoire qui lui est réservé.

106
Les tableaux

• Tableau à une dimension


• Sur le plan physique

107
Les tableaux

• Tableau à une dimension

• Un tableau correspond à l’adresse de la première case allouée pour son premier élément.
• Ainsi:
• un tableau ne peut pas figurer à gauche d’un opérateur d’affectation.
• Par exemple, on ne peut pas écrire « tab1 = tab2; ».
• Il faut effectuer l’affectation pour chacun des éléments du tableau.

• Les opérations en général ne peuvent pas être exécutées d’une manière globale sur un
tableau mais plutôt sur chaque élément de ce dernier.

108
Les tableaux

• Tableau à une dimension

• Initialisation d’un tableau

On peut initialiser un tableau lors de sa déclaration par une liste de constantes de la façon suivante:

type nom-du-tableau[N] = {constante-1,constante-2,...,constante-N};

109
Les tableaux

• Tableau à une dimension

• Initialisation d’un tableau


Si le nombre de données dans la liste d’initialisation est inferieur à la dimension du tableau, seuls
les premiers éléments seront initialisés. Les autres éléments seront mis à:
• 0 si se sont des valeurs numériques.
• \0 si se sont des caractères. (null)
Lors d’une initialisation, il est également possible de ne pas spécifier le nombre d’éléments du tableau.
Par défaut, il correspondra au nombre de constantes de la liste d’initialisation.

Voir test6.c

110
Les tableaux

• Tableau à une dimension

• Affichage d’un tableau

• L’affichage des éléments d’un tableau se fait


élément par élément.

111
Les tableaux

• Tableau à une dimension

• Affichage et lecture d’un tableau • La lecture et l’affichage des éléments d’un


tableau se font élément par élément.

112
Les tableaux

• Tableau à une dimension

• Affectation d’un tableau

• L'affectation de valeurs aux éléments d'un tableau se fait également individuellement.


• L'affectation d'un tableau B à un autre tableau A se fait élément par élément.
• Une affectation "brutale" de B à A (A=B) n'est pas possible.
• L'affectation élément par élément d'un tableau B à un autre tableau A (A[i]=B[i]) réalise une copie de
B dans A.

113
Les tableaux

• Tableau à deux dimensions

• De manière similaire, on peut déclarer un tableau à deux dimensions.

• En fait, un tableau à deux dimensions est un tableau unidimensionnel dont chaque élément est lui-
même un tableau.
• On accède à un élément du tableau par l’expression “tableau[i][j]”.
• Pour initialiser un tableau à deux dimensions à la compilation, on utilise une liste dont chaque élément
est une liste de constantes.

114
Les tableaux

• Tableau à deux dimensions

115
Les tableaux

• Tableau à plusieurs dimensions

116
Les tableaux: Exercices d’application

Réalisez un programme C qui permet de:


1- Remplir un tableau de réels
2- Afficher son contenu
3- Chercher une valeur donnée par l’utilisateur dans le tableau crée
• Si la valeur existe dans le tableau, affichez son indice
• Si non afficher le message: La valeur n’existe pas

Réalisez un programme C qui permet d’insérer une valeur donnée par l’utilisateur à une position
précisée pas ce dernier dans un tableau.

117
Exercices d’application

118
Les chaines de caractères

Déclarer une chaîne de caractère: un tableau de char

• Une chaine de caractère est un tableau de caractères.

• Pour délimiter la fin de la chaîne dans le tableau, le caractère fin de chaîne sera placé par défaut
après le dernier caractère de la chaîne.

• Pour afficher la chaîne initialisée dans tab, il faut la parcourir caractère par caractère jusqu’à
rencontrer le caractère de fin de chaîne ‘\0’.

119
Les chaines de caractères

Déclarer une chaîne de caractère: un tableau de char

120
Les chaines de caractères

Fonctions d’entrées/sorties liées aux chaînes

Ecriture de chaînes avec puts

Prototype : int puts (const char [] s)

• Cette fonction appartient à la librairie <stdio.h>


• Elle renvoie les différents caractères de la chaîne sur l’écran aussi appelé unité de sortie standard stdout.
• Ensuite, elle transmet un caractère de fin de ligne (‘\n’).
On obtient sur la sortie standard :
essai de puts :Bonjour
monsieur

Si la chaîne ch1 avait contenu l’information ″Bonjour\n″ au lieu de ″Bonjour″, on obtiendrait une ligne
vide supplémentaire :
essai de puts :Bonjour

monsieur 121
Les chaines de caractères

Fonctions d’entrées/sorties liées aux chaînes

Ecriture de chaînes avec %s dans printf

• Puts et printf avec un %s permettent d’afficher une chaîne de caractère à la sortie standard.
• Contrairement à la fonction puts, printf avec un %s affiche la chaîne de caractères sans caractère de fin de chaîne
et de retour à la ligne. Les deux instructions suivantes sont équivalentes :

122
Les chaines de caractères

Fonctions d’entrées/sorties liées aux chaînes

Lecture de chaînes avec gets

Prototype : char * gets(char[] s)

• Cette fonction permet de lire une chaîne de caractère depuis l’entrée standard stdin.
• La lecture s’arrête à la lecture d’un caractère de retour à la ligne.
• Il ne sera, cependant, pas enregistré en mémoire à la fin de chaine de caractères lue.
• Par contre le caractère de fin de chaîne est enregistré en mémoire.

123
Les chaines de caractères

Le comportement de gets diffère de scanf avec un %s sur les points suivants :


- Pour gets, seule la fin de ligne sert de délimiteur alors que pour %s, il existe 5 caractères délimiteurs qu’on nomme
des espaces blancs ; la chaine lue par gets peut donc contenir n’importe quel caractère espace blanc (excepté \n), en
particulier des espaces.
- Ce caractère fin de ligne est consommé par la lecture, c’est-à-dire que le pointeur ne reste pas placé dessus comme
il le ferait avec le code %s dans scanf. Cela signifie qu’une prochaine lecture, en particulier par gets, accédera bien
au caractère de la ligne suivante.

La fonction gets fournit comme valeur de retour l’adresse de la chaine lue lorsque l’opération s’est bien déroulée, le
pointeur NULL en cas d’erreur.

124
Les chaines de caractères

Fonctions de manipulation de chaîne

Fonction strlen

Prototype: size_t strlen( const char[] s)

• La fonction strlen fournit la longueur de la chaine dont on lui a transmis l’adresse en argument.
• Cette longueur correspond au nombre de caractères trouvés depuis l’adresse indiquée jusqu’au premier caractère de
code nul. Ce dernier n’étant pas pris en compte.

Remarque : le type ,size_t, de la valeur de retour de strlen() correspond à un


type entier non signé.

125
Les chaines de caractères

Fonctions de manipulation de chaîne

Fonction strcpy

Prototype: Char* strcpy( char[] but, const char[] source)

Cette fonction recopie à l’adresse d’une première chaine, l’adresse d’une seconde chaine de caractères avec son
caractère de fin de chaine (‘\0’).

126
Les chaines de caractères

Les risques de la fonction strcpy

- aucun contrôle de longueur n’est effectué par cette fonction, il est donc nécessaire que l’emplacement réservé à
but soit suffisant pour y recevoir la chaine située à l’adresse source.

- Exemple :
char ch[5] ; … strcpy(ch, ″bonjour″) ; /* le caractère ‘r’ va écraser la valeur de l’emplacement mémoire ch[5] */

- Pour recopier seulement les 5 premiers caractères de ″bonjour″ dans ch ; il faut utiliser la fonction strncpy qui
permet de préciser le nombre de caractères à recopier.
- Elle ne s’assure pas de la présence du caractère de fin de chaine avant la copie.

- L’utilisation de la fonction strncpy() permettrait de limiter le nombre de caractères à recopier ce qui évitera tout
débordement.

127
Les chaines de caractères

Fonctions de manipulation de chaîne

La fonction strncpy

Prototype char* strncpy( char[] but, conct chr[] source, size_t longueur)

• Cette fonction recopie aussi à l’adresse d’une première chaine, l’adresse d’une seconde chaine de caractères mais en
limitant la copie à un nombre de caractères précis.
• Ce nombre est donné en argument

128
Les chaines de caractères

Comment faire des copies fiables?

• L’inconvénient de stncpy est de ne pas toujours mettre le caractère de fin de chaine dans la chaine retournée en
résultat (but).
• Pour éviter cela voici un exemple d’une façon de procéder pour remédier à ce défaut :

129
Les chaines de caractères

Fonctions de concaténation

• Les fonctions de concaténation permettent de mettre bout à bout deux chaines de caractères afin de
n’en former qu’une seule.

• Il existe en C deux fonctions pour réaliser ce travail : - strcat - strncat


• Ces deux fonctions sont très similaires, la seule différence réside dans le fait que strncat possède un
troisième argument qui permet de limiter le nombre de caractères à concaténer (identiquement à
strncpy).

130
Les chaines de caractères

Fonctions de concaténation

La fonction strcat

Prototype char* strcat(char[] but, char[] source)

Cette fonction recopie à la fin d’une première chaine une seconde chaine.

Cette fonction recopie la chaine située à l’adresse source à la fin de la chaine d’adresse but, c’est-à dire à partir
de son zéro de fin ; ce dernier se trouve donc remplacé par le premier caractère de la chaine d’adresse source.

131
Les chaines de caractères

Fonctions de concaténation

La fonction stnrcat

Prototype char* strncat(char[] but, char[] source, size_t longueur)

Cette fonction recopie à la fin d’une première chaine n caractère d’ une seconde chaine.

Cette fonction recopie la chaine située à l’adresse source à la fin de la chaine d’adresse but, c’est-à dire à partir
de son zéro de fin ; ce dernier se trouve donc remplacé par le premier caractère de la chaine d’adresse source. Le
nombre de caractères recopiés est limité à longueur.

132
Les chaines de caractères

Fonctions de concaténation
La fonction strncat
A la différence de strncpy, strncat place un caractère de fin de chaine même si aucun caractère de fin de chaine n’a
été trouvé parmi les caractères à concaténer.

133
Les chaines de caractères

Fonctions de concaténation

Le risque de la fonction strcat est le même que pour strcpy à savoir qu’elle ne s’assure pas de la présence du
caractère de fin de chaine
Comment faire une concaténation sans risques?

134
Les chaines de caractères

Fonctions de comparaison

• Pour comparer des chaines de caractères, nous devons utiliser des fonctions spécifiques car contrairement
aux données de type de base les opérateurs relationnels classiques ne peuvent être employés.

• Les fonctions que nous décrivons ci-dessous permettent de comparer des chaines de caractères selon leur
ordre alphabétique (ordre de la table ASCII).

• Ces fonctions sont les suivantes : - strcmp - strncmp

135
Les chaines de caractères

Fonctions de comparaison

La fonction strcmp

Prototype: int strcmp (const char[] chaine1, const char[] chaine2);

Cette fonction compare la première chaine à la seconde et retourne une valeur entière en retour qui indique l’ordre
des deux chaines.

136
Les chaines de caractères

Fonctions de comparaison

La fonction strcmp

137
Les chaines de caractères

Fonctions de comparaison

La fonction strncmp

Prototype: int strncmp (const char[] chaine1, const char[] chaine2, size_t longueur);

Même comportement que strcmp mais en limitant la comparaison des deux chaines à un nombre maximal de caractères.

138
Les chaines de caractères

Fonctions de recherche

La bibliothèque standard propose:


• des fonctions de recherche de la première occurrence d’un caractère ou sous-chaine dans une chaine de caractères et
qui sont :
- Recherche d’un caractère : strchr et strrchr
- Recherche d’une sous-chaine : strstr
- Recherche d’un des caractères appartenant à un ensemble de caractères : strpbrk

Toutes ces fonctions retournent en résultat l’adresse de l’information cherchée si elle est trouvée, le pointeur nul
autrement.

• des fonctions qui permettent d’éclater une chaine en plusieurs parties. Exemple : strtok.

139
Les chaines de caractères

Fonctions de recherche

La fonction strchr

Prototype: char* strchr(const char[] chaine, int c)

Recherche la première occurrence d’un caractère dans une chaine de caractères.

140
Les chaines de caractères

Fonctions de recherche

La fonction strrchr

Prototype: char* strrchr(const char[] chaine, int c);

Même comportement que strchr mais en effectuant la recherche à partir de la fin de la chaine et non à partir
du début.

141
Les chaines de caractères

Fonctions de recherche

La fonction strstr

Prototype: char* strstr(const char[] chaine1, const char[] chaine2);

Recherche la première occurrence d’une sous chaine dans une chaine de caractères.

142
Les chaines de caractères

Fonctions de recherche

La fonction strtok

Prototype: char* strstok(const char[] chaine1, const char[] chaine2);

Eclate une chaine en plusieurs sous-chaines, sachant que ces dernières sont séparées par un ou plusieurs
délimiteurs.

143
Les chaines de caractères

Pour retrouver les autres sous-chaines il faut rappeler la fonction strtok mais avec la valeur NULL en premier
argument de strtok. Le second argument correspond toujours aux caractères délimiteurs mais ils peuvent différer d’un
appel au suivant. Avec un tel appel, la fonction strtok reprend son exploration non plus au début de la chaine, mais à la
suite du caractère de fin de chaine qui vient d’être placé par le précédent appel.

144
Les chaines de caractères

Fonctions de conversion de chaîne en nombre

• Ces fonctions permettent de convertir une chaine ou une partie de la chaine en un nombre.

145
Les chaines de caractères: Exemples d’application

146
Chapitre IV: Les pointeurs

• Adresse et valeur d’un objet


• Notion de pointeur
• Arithmétique des pointeurs
• Allocation dynamique
• Pointeur et tableaux
• Pointeurs et tableaux à une dimension
• Pointeurs et tableaux à plusieurs dimensions
• Pointeurs et chaines de caractères

147
Introduction

• Toute variable manipulée dans un programme est stockée quelque part en mémoire centrale.
• Cette mémoire est constituée d’octets qui sont identifiés de manière univoque par un numéro qu’on
appelle adresse.
• Pour retrouver une variable, il suffit donc de connaître l’adresse de l’octet ou` elle est stockée (ou, s’il
s’agit d’une variable qui recouvre plusieurs octets contigus, l’adresse du premier de ces octets).
• Pour des raisons évidentes de lisibilité, on désigne souvent les variables par des identificateurs, et non
par leur adresse.
• C’est le compilateur qui fait alors le lien entre l’identificateur d’une variable et son adresse en
mémoire.
• Toutefois, il est parfois très pratique de manipuler directement une variable par son adresse.

148
Adresse et valeur d’un objet

• On appelle Lvalue (left value) tout objet pouvant être placé à gauche d’un opérateur d’affectation.
• Une Lvalue est caractérisée par:
• son adresse, c’est-à-dire l’adresse-mémoire à partir de laquelle l’objet est stocké;
• sa valeur, c’est-à-dire ce qui est stocké à cette adresse.

Si le compilateur a placé la variable i à l’adresse 4831836000 en


mémoire, et la variable j à l’adresse 4831836004, on a:

149
Adresse et valeur d’objet

• Deux variables différentes ont des adresses différentes.


• L’affectation i = j; n’opère que sur les valeurs des variables.
• Les variables i et j étant de type int, elles sont stockées sur 4 octets.
• Ainsi la valeur de i est stockée sur les octets d’adresse 4831836000 à 4831836003.
• L’adresse d’un objet étant un numéro d’octet en mémoire, il s’agit d’un entier quelque soit le type de l’objet considéré.
• Le format interne de cet entier (16 bits, 32 bits ou 64 bits) dépend des architectures.

• L’opérateur & permet d’accéder à l’adresse d’une variable.


• Toutefois &i n’est pas une Lvalue mais une constante: on ne peut pas faire figurer &i à gauche d’un opérateur d’affectation.
• Pour pouvoir manipuler des adresses, on doit donc recourir un nouveau type d’objets, les pointeurs.

150
Notion de pointeur

• Un pointeur est un objet (Lvalue) dont la valeur est égale à l’adresse d’un autre objet.

L’opérateur unaire d’indirection * permet d’accéder directement à la valeur de l’objet pointé. Ainsi, si p est un pointeur
vers un entier i, *p désigne la valeur de i.

151
Notion de pointeur

152
Notion de pointeur

• On peut donc dans un programme manipuler à la fois les objets p et *p.


• Ces deux manipulations sont très différentes.

153
Arithmétique des pointeurs

• La valeur d’un pointeur étant un entier, on peut lui appliquer un certain nombre d’opérateurs arithmétiques
classiques.
• Les seules opérateurs arithmétiques valides sur les pointeurs sont:
– l’addition d’un entier à un pointeur. Le résultat est un pointeur de même type que le pointeur de départ;
– la soustraction d’un entier à un pointeur. Le résultat est un pointeur de même type que le pointeur de départ;
– la différence de deux pointeurs pointant tous deux vers des objets de même type. Le résultat est un entier.

• Notons que la somme de deux pointeurs n’est pas autorisée.

• Si i est un entier et p est un pointeur sur un objet de type type


• l’expression p + i désigne un pointeur sur un objet de type type dont la valeur est égale à la valeur de p
incrémentée de i * sizeof(type).
• Il en va de même pour la soustraction d’un entier à un pointeur, et pour les opérateurs d’incrémentation
et de décrémentation ++ et --

154
Arithmétique des pointeurs

Si p et q sont deux pointeurs sur des objets de type type, l’expression p - q désigne un entier dont la valeur est égale à
(p - q)/sizeof(type) .

155
Allocation dynamique

• Avant de manipuler un pointeur, et notamment de lui appliquer l’opérateur d’indirection *, il faut l’initialiser.
• Sinon, par défaut, la valeur du pointeur est égale à une constante symbolique notée NULL définie dans stdio.h.
• En général, cette constante vaut 0. Le test p == NULL permet de savoir si le pointeur p pointe vers un objet.

• On peut initialiser un pointeur p par une affectation sur p.


• Par exemple, on peut affecter à p l’adresse d’une autre variable.
• Il est également possible d’affecter directement une valeur à *p. Mais pour cela, il faut d’abord réserver à *p un
espace-mémoire de taille adéquate.
• L’adresse de cet espace-mémoire sera la valeur de p. Cette opération consistant à réserver un espace-mémoire pour
stocker l’objet pointé s’appelle allocation dynamique.
• Elle se fait en C par la fonction malloc de la librairie standard stdlib.h. Sa syntaxe est:

156
Allocation dynamique

• Cette fonction retourne un pointeur de type char * pointant vers un objet de taille nombre-octets octets.
• Pour initialiser des pointeurs vers des objets qui ne sont pas de type char, il faut convertir le type de la sortie de
la fonction malloc à l’aide d’un cast.
• L’argument nombre-octets est souvent donné à l’aide de la fonction sizeof() qui renvoie le nombre d’octets
utilisés pour stocker un objet.

157
Allocation dynamique

On définit un pointeur p sur un objet *p de type int, et affecte à *p la valeur de la variable i

Avant l’allocation dynamique


Après l’allocation dynamique Fin du programme

158
Allocation dynamique

C’est quoi la différence?

Fin du programme
Fin du programme

159
Allocation dynamique

• La fonction calloc de la librairie stdlib.h a le même rôle que la fonction malloc mais elle initialise en plus l’objet
pointé *p à zéro. Sa syntaxe est:

160
Allocation dynamique

Lorsque l’on n’a plus besoin de l’espace-mémoire alloué dynamiquement (c’est-`a-dire quand on n’utilise
plus le pointeur p), il faut libérer cette place en mémoire.

A toute instruction de type malloc ou calloc doit être associée une instruction de type free.

161
Pointeurs et tableaux

L’usage des pointeurs en C est, en grande partie, orienté vers la manipulation des tableaux.

int tab[10];
• tab est un pointeur constant (non modifiable) dont la valeur est l’adresse du premier élément du tableau.
• Autrement dit, tab a pour valeur &tab[0].
• On peut donc utiliser un pointeur initialisé à tab pour parcourir les éléments du tableau.

162
Pointeurs et tableaux

Toutefois, la manipulation des tableaux et non des pointeurs, possède certains inconvénients dus au fait qu’un
tableau est un pointeur constant. Ainsi :
• on ne peut pas créer de tableaux dont la taille est une variable du programme,
• on ne peut pas créer de tableaux bidimensionnels dont les lignes n’ont pas toutes le même nombre
d’éléments.
Ces opérations deviennent possibles dès que l’on manipule des pointeurs alloués dynamiquement.

Si on veut en plus que tous les éléments du tableau tab soient


initialisés à zéro, on remplace l’allocation dynamique avec
malloc par :

163
Pointeurs et tableaux

• Les éléments de tab sont manipulés avec l’opérateur d’indexation [], exactement comme pour les tableaux.
• Les deux différences principales entre un tableau et un pointeur sont:
• un pointeur doit toujours être initialisé, soit par une allocation dynamique, soit par affectation d’une expression
adresse, par exemple p = &i;
• un tableau n’est pas une Lvalue; il ne peut donc pas figurer à gauche d’un opérateur d’affectation. En
particulier, un tableau ne supporte pas l’arithmétique (on ne peut pas écrire tab++;).

164
Pointeurs et tableaux

• 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 à 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].

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

165
Pointeurs et tableaux

• 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.

166
Pointeurs et tableaux

• 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:

• Contrairement aux tableaux à deux dimensions, on peut choisir des tailles différentes pour chacune des lignes
tab[i]. Par exemple, si l’on veut que tab[i] contienne exactement i+1 éléments, on écrit:

167
Pointeurs et tableaux

• une chaîne de caractères est un tableau à une dimension d’objets de type char, se terminant par le
caractère nul ’\0’.
• On peut donc manipuler toute chaîne de caractères à l’aide d’un pointeur sur un objet de type char.
• On peut faire subir à une chaîne définie par:

char *chaine;

des affectations comme

chaine = "ceci est une chaine";


et toute opération valide sur les pointeur.

168
Pointeurs et tableaux

L’utilisation de pointeurs de caractère et non de tableaux permet par exemple de créer une chaîne correspondant à la
concaténation de deux chaînes de caractères:

169
Pointeurs et tableaux

On remarquera l’utilisation d’un pointeur intermédiaire p qui est indispensable dès que l’on fait des opérations de type
incrémentation.
En effet, si on avait incrémenté directement la valeur de res, on aurait évidemment “perdu” la référence sur le premier
caractère de la chaîne. Par exemple:

170
Exercice d’application

171
Exercice d’application

172
Exercice d’application

Ecrire un programme qui lit deux tableaux d'entiers A et B et leurs dimensions N et M au clavier et
qui ajoute les éléments de B à la fin de A. Utiliser deux pointeurs PA et PB pour le transfert et
afficher le tableau résultant A.

173