Vous êtes sur la page 1sur 176

Année académique 2021-2022

THEME : Programmation C

Enseignant : COULIBALY Moussa


Ingénieur de Conception en SI
Ch0 : Rappel
Présentation et Généralité sur le langage C
Outils de l’algorithmie en langage C
Fonction en langage C
les tableaux
Chapitre 1 : les pointeurs
Chapitre 2 : les structures
Chapitre 3 : les fichiers
Chapitre 4 : les listes et les arbres
Chapitre 5 : la gestion dynamique
Bibliographie
Claude Delannoy : programmer en langage C,
EYROLLES, 2002
J. Léry : Algorithme Application en C, PEARSON
EDUCATION, 2005
Présentation et Généralité sur le
langage C
Outils de l’algorithmie en langage C
Fonction en langage C
les tableaux
I- Historique et évolution
 Avant 1940 les langages étaient des
simples codes.
En 1801 utilisation des cartes perforées (Jacquard).
Entre 1842 et 1843 traduction par Ada Lovelace de la
méthode de Bernouilli sur une machine analytique de
Charles Babbage.
 Les années 1940 les langages étaient en
assembleur ou en machine.
1943 : le Plankalkül et Le langage de programmation de
l’ENIAC.
1948 : premier langage enregistré (jeu d’instruction
SEEM)
Les années 1950 et 1966.
1954 : FORTRAN, le traducteur de
formules(FORmula TRANslator) par John
Backus.
1958 : LISP Traitement de listes (LISt Processor)
par John McCarthy.
1959 : COBOL programmation d’application de
gestion (COmmon, Business Oriented
Language) par Grace Hopper.
1964 : BASIC (Beginner’s All purpose Symbolic
Instruction Code) par microsoft.
Les années 1967 et 1978 (structuration).
1970 : PASCAL
1972 : C est le premier langage de
programmation système (années 70 par
Dennis Ritchie aux laboratoires Bell).
1972 : Smaltalk premier langage de
programmation à disposer d’un
environnement de développement intégré
complètement graphique par Dennis Ritchie
et Ken Thompson et les laboratoires Bell.
1978 : SQL (Structured Query Language).
 Les années 1980 (objet).
1983 : Ada
1983 : C++.
1985 :Eiffel.
1987 : Perl.
 Les années 1990 (internet).
1991 : Visual Basic
1991 : Java
1995 : JavaScript
1995 : PHP
2000 : C#
 Tendances actuelles.
(sécurité, intégration xml,…)
Le développement basé sur les trois tiers
- Client
- Application
- Serveur
Implémentation de ces 3 tiers est MVC (modèle
Vue Contrôleur) ie le design pattern.
II- les familles de langages(1)

On distingue habituellement deux grandes familles


de langages de programmation :
- Les langages orientés procédures (fonctionnels);
- Les langages orientés objets ;
- Les langages impératifs (premiers langages).
II.1- Un langage fonctionnel
C’est un langage dans lequel le programme est
construit par fonctions, retournant un nouvel état en
sortie et prenant en entrée la sortie d’autres
fonctions par exemple. Ce langage permet de
diviser un problème complexe en sous problèmes
simples. L’auto-appel d’une fonction est la
récursivité. Exemple langage c.
II.2- Un langage objet
c’est une manière de programmer qui part du
principe que des choses peuvent avoir des points
communs, des similarités en elles-mêmes ou en
leur façon d’agir. L’idée de la programmation objet
est donc de regrouper de tels éléments afin d’en
simplifier leur utilisation.
Un regroupement est appelé classe, les entités qu’il
regroupe sont appelées objets.
Exemple C++, Java
Les langages informatiques peuvent être soit :
- Des langages interprétés ;
- Des langages compilés.
II.3- Un langage interprété
Différent d’un langage machine, ce langage a
besoin d’un programme auxiliaire (l’interpréteur)
pour traduire au fur et à mesure les instructions du
programme. Les langages interprétés sont moins
rapides que les compilés mais plus souples.
Exemple : le langage script
II.4- Un langage compilé
Un programme écrit dans un langage dit
« compilé » va être traduit une fois pour toutes par
un programme annexe, appelé compilateur, afin de
générer un nouveau fichier qui sera autonome,
c’est-à-dire qui n’aura plus besoin d’un programme
autre que lui pour s’exécuter ; on dit d’ailleurs ce
fichier est exécutable. Exemple : C.
II.5- Un langage intermédiaire
Certains langages appartiennent en quelque sorte
aux deux catégories (java) dont leur compilation a
besoin d’un interpréteur du fichier compilé. (la
machine virtuelle).
III- Principe de développement d’un
programme C(1)
Les bons principes de développer d’un programme C
sont :
 ne jamais placer plusieurs instructions sur une
même ligne ;

 utiliser des identificateurs significatifs ;

 grâce à l’indentation des lignes, faire ressortir la


structure syntaxique du programme ;
III- Principe de développement d’un
programme C(2)
 laisser une ligne blanche entre la dernière ligne
des déclarations et la première ligne des
instructions ;

 aérer les lignes de programme en entourant par


exemple les opérateurs avec des espaces ;

 bien commenter les listings tout en évitant les


commentaires triviaux.
III- Principe de développement d’un
programme : commentaire C(3)
/* Ceci est un commentaire qui peut s’étaler sur
plusieurs lignes */
// Ceci est un commentaire qui ne peut s’étaler
que sur une ligne.
Principe de commenter un programme C :
1. le fichier : pour indiquer le nom de l’auteur,
du fichier, les droits de copyright,
la date de création, les dates et auteurs des
modifications ainsi que la raison d’être du
fichier ;
2. la procédure : pour indiquer les paramètres et
la raison d’être de la procédure;
III- Principe de développement d’un
programme : commentaire C(4)
3. groupe d’instruction : pour exprimer ce que
réalise une fraction significative d’une
procédure.
4. déclaration ou instruction : le plus bas niveau
de commentaire.
IV- Structure d’un programme C (1)
De manière générale, un programme C consiste
en la construction de blocs individuels
appelées fonctions qui peuvent s’invoquer l’un
l’autre. Pour pouvoir s’exécuter, un programme
C doit contenir une fonction spéciale appelée
« main » qui sera le point d’entrée de
l’exécution. La Structure de C se fait selon les
points suivantes :
1. les directives du préprocesseur : représentées
par le caractère # marquant le début d’un
programme C(#include <stdio.h> :
bibliothèque, #define TVA 18 : constante);
IV- Structure d’un programme C (2)
2. les déclarations des variables : Ces déclarations
sont de la forme :
type nom variable [= <valeur>] ;
Exemple : float produit ;
3. La Définition de Fonctions : Ce sont des sous-
programmes dont les instructions vont définir un
traitement sur des variables.
Syntaxe :
type_resultat nom fonction (type1 arg1, . . . ,Typen
argn) {
<déclaration de variables locales >
<liste d’instructions >
}
IV- Structure d’un programme C (3)
une ligne déclarative qui contient :
– type_resultat : le type du résultat de la fonction.
– nom fonction : le nom qui identifie la fonction.
– type1 arg1 . . . typen argn : les types et les noms
des paramètres de la fonction.
un bloc d’instructions délimité par des accolades {
... }, contenant :
– <déclaration de variables locales > : les
déclarations des données locales (c’est à dire des
données qui sont uniquement connues à l’intérieur
de la fonction)
– <liste d’instructions > : la liste des instructions
qui définit l’action qui doit être exécutée.
IV- Structure : Exemple C (4)
#include <stdio.h> // Directive de préprocesseur
#define TVA 15 // idem - la TVA au Luxembourg
float prix_TTC; //déclaration d’une variable externe
/* Exemple de déclaration d’une fonction secondaire */
/* ajoute la TVA au prix HT; renvoie le prix TTC */
float ajoute_TVA(float prix_HT) {
return prix_HT*(1 + (TVA/100));}
/* Fonction main: point d’entrée de l’exécution*/
void main() {
float HT; //déclaration d’une variable interne
puts("Entrer le prix H.T. : "); // appel de fonctions
scanf("%f",&HT); // définies dans stdio.h
prix_TTC = ajoute_TVA(HT); //appel de notre fonction
printf("prix T.T.C. : %f\n",prix_TTC);
}
V- les directives de compilation (1)
1. Le traitement par le préprocesseur : le fichier
source (portant l’extension .c) est analysé par le
préprocesseur qui effectue des transformations
purement textuelles (préprocesseur) ;
2. La compilation : la compilation proprement dite
traduit le fichier généré par le préprocesseur
(d’extension .i) en assembleur (microprocesseur
mnémonique) ;
3. L’assemblage : cette opération transforme le
code assembleur (extension .s) en un fichier binaire
(objet .o), c’est-à-dire en instructions directement
compréhensibles par le processeur.
V- les directives de compilation (2)
4. L’édition de liens : un programme est souvent
séparé en plusieurs fichiers sources. pour
des raisons de clarté mais aussi parce qu’il fait
généralement appel à des librairies de fonctions
standards déjà écrites. Une fois chaque fichier de
code source assemblé, il faut donc lier entre eux les
différents fichiers objets. L’édition de liens produit
alors un fichier dit exécutable.
VI- l’entrée – sortie(1)
Il s’agit des fonctions de la librairie standard
stdio.h utilisées avec les unités classiques
d’entrées-sorties, qui sont respectivement
le clavier et l’écran. Sur certains compilateurs,
l’appel à la librairie stdio.h par la directive au
préprocesseur #include <stdio.h> n’est pas
nécessaire pour utiliser les fonctions présentées ici,
notamment printf et scanf.

VI.1- la fonction printf


La fonction printf est une fonction d’impression
formatée,
VI- l’entrée – sortie(2)
ce qui signifie que les données sont converties
selon le format particulier choisi. Sa syntaxe est la
suivante :

printf("chaîne de contrôle [%type1%type2,..]",


[expression1, . . . , expressionn]);
%type sont :
VI- l’entrée – sortie(4)

 %d int décimale signée,


 %ld long int décimale signée,
 %u unsigned int décimale non signée,
 %lu unsigned long décimale non signée,
 %o unsigned int octale non signée,
 %lo unsigned long octale non signée,
 %x unsigned int hexadécimale non signée,
 %lx unsigned long hexadécimale non signée,
VI- l’entrée – sortie(5)

 %f double décimale virgule fixe,


 %lf long double décimale virgule fixe,
 %e double décimale notation exponentielle,
 %le long double décimale notation exponentielle,
 %g double décimale, représentation la plus courte
parmi %f et %e,
 %lg long double décimale, représentation la plus
courte parmi %lf et %le,
 %c unsigned char caractère,
 %s char* chaîne de caractères.
VI- l’entrée – sortie(6)

Exemples
Int nb_entier;
printf(”l’entier entré est : %d”,nb_entier);
VI- l’entrée – sortie(7)

VI.2- la fonction scanf


La fonction scanf permet de récupérer les données
saisies au clavier, dans le format spécifié. Ces
données sont stockées aux adresses spécifiées par
les arguments de la fonction scanf (on utilise donc
l’opérateur d’adressage & pour les variables
scalaires).

Syntaxe :
scanf("chaîne de contrôle type1 type2..", &arg1, . . .
, &argn);
VI- l’entrée – sortie(8)

type spécifiant le type de donnée lue et comment il


faut le lire est représenté dans le tableau suivant :
VI- l’entrée – sortie(9)
Type Description Argument
requis
c caractère simple (espace inclu) char *
d entier : nombre optionnellement Int *
précédé par un signe
e,E, Floating point : nombre décimal précédé float *
f,g,G éventuellement d’un signe et suivi
éventuellement du caractère
e ou E et d’un nombre décimal. Exemple
:-732.103
ou 7.12e4
O entier en notation octale Int *
s Chaîne de caractères (jusqu’à la lecture Char *
d’un espace)
u entier non signé unsigned int *
x entier hexadecimal Int *
VI- l’entrée – sortie(10)
Exemple :
#include <stdio.h>
int main() {
int i;
printf("entrez un entier sous forme hexadecimale i
= ");
scanf("%x",&i);
printf("i = %d\n",i);
return 0;
}
I- Les types de données (1)

I.1- Le type caractère


On désigne par le mot char pour déclarer le type
caractère en C. Ce caractère est codé sur un
octet. Exemple : char c;
Caractères particuliers :
Caractère ‘\n’ ‘\t’ ‘\b’ ‘\’’ ‘\"' \?
sémantique Retour à Tabulati backspace ‘ " ?
la ligne on

NB : pour déclarer une chaîne de caractères on a :


char[longueur] nom_chaine; (char[20] nom;).
I- Les types de données(2)

I.2- Le type entier


On désigne par le mot int pour déclarer le type
entier en C.
Les types sont représentés dans le tableau :
Type Taille mémoire Intervalle de valeurs
char 1 Octet [-128, 127] ou [0,255]

int 2 ou 4 Octets [-215,215 – 1] ou [−231; 231 − 1]


unsigned int 2 ou 4 octets [0 ;216 − 1] ou [0 ;232 − 1]
short int 2 octets [-215,215 – 1]
long 4 octets [-2 31,231 – 1]

Cas des constantes entières : décimal 109, Octal


o1047, Hexadecimal ox109AB.
I- Les types de données(3)
I.3- Le type réel (les flottants)
On désigne par le mot float ou double pour déclarer
le type réel en C.
La représentation interne dépend du compilateur (la
plupart utilise le standard IEEE 754-1985[Ste90]).
Un nombre flottant x est ainsi composée d’un signe s
(s = 1 pour un nombre négatif, 0 sinon) , d’une
mantisse m et un exposant exp en base 2 tels que :
x = s ∗ m ∗ 2exp (avec 1.0 ≤ m < 2 ou m = 0).
Type Taille mémoire Intervalle de valeur Précision
float 4 octets [1, 2 ∗ 10−38 ; 3, 4 ∗ 1038] 6 chiffres décimaux
doub 8 octets [ 2,3 ∗ 10−308 ; 1,7 ∗ 10308] 15 chiffres
le décimaux
I- Les types de données(3)
I.3- Le type réel (les flottants)
Quelques exemples de notation :

Notation C correspondance
2. 2
1.4 1.4
2.e4 2*104
1.4e-4 1.4*10-4
.3 0.3
2e4 2*104
.3e4 0.3*104
I- Les types de données(4)
I.4- Le type void
On a vu que toute variable C était typée, de même
que toute valeur de retour d’une fonction. Mais il
peut arriver qu’aucune valeur ne soit disponible.
Pour exprimer l’idée de ”aucune valeur”, on utilise
le mot-clé void. Ce type est utilisé dans deux
situations :
 principalement dans la déclaration de fonctions
qui n’ont pas de valeur de retour;
 le prototype de fonctions sans paramètres : int
rand(void).
II- Variable et Affectation(1)
II.1- notion les variables
Une variable est désignée par un identificateur (il s'agit de
son nom). Une variable correspond à un réceptacle d'une
certaine taille qui permet de stocker un type d'information.
Le réceptacle contient une valeur (la valeur de la variable)
qui est susceptible de changer au cours de l'exécution de
l'algorithme.
Le couple ( identificateur, réceptacle) définit une variable.
Les variables sont identifiées par un nom significatif auquel
on associe un type de donnée.
Syntaxe :
<type_données> <nom_variable> ;
exemple :
char[20] nom ;
II- Variable et Affectation(2)
II.2- notion d’affectation
L’affectation se fait par l’utilisation du signe égal (=).
Syntaxe :
<variable>=<expression_retournant_type_variable> ;

Exemple :
Produit = (diviseur * resultat) + reste ;
III- Les constantes
Une constante est une valeur affectée lors de la
programmation. Elle ne peut changer lors de
l'exécution du programme. Il est préférable de
désigner une constante par un nom
(identificateur) si elle doit être utilisée souvent.
Syntaxe :
1- # define <nom_constant> <valeur>
Exemple : #define Pi 3.14

2- const <type_var> <nom_const> = valeur ;


Ou <type_var> const <nom_const> = <valeur> ;
Exemple : int const a=12;
IV- Les opérateurs et expression (1)
IV.1- Opérateurs arithmétiques
Opérateurs Traduction Exemple Résultat
+ Addition a+b Addition de a et b
- Soustraction a - b Soustrait b dans a
* Multiplicatio a * b Produit de a et b
n
/ Division a /b Quotient de a et b
+(unaire) Signe positif +a La valeur de a
-(unaire) Signe -a La valeur contraire de a
négatif
% reste a%b Reste de la division euclidienne
de a par b
++(unaire) Incrément ++a ou a est incrémenté (a=a+1) .
a++ L’operateur préfixe ++a (resp.
suffixe a++) incrémente a
avant (resp. après) de l’évaluer.
--(unaire)
III- Les opérateurs et expression (3)
Supposons que la valeur de N soit égale à 5 :
– Incrémentation postfixe : X = N++ ; Résultat : N
= 6 et X = 5
– Incrémentation préfixe : X = ++N ; Résultat : N
= 6 et X = 6
IV- Les opérateurs et expression (4)
IV.2- Opérateurs d’affectation
Opérateurs Traduction Exemple Résultat
= Affectation a=b Affectation de b
simple dans a
(op)= Affectation a op= b a = a op b
composée

Les opérateurs d’affectation composés sont donc


:+=, -=, *=, /=, %=, &=, ^=.
IV- Les opérateurs et expression (5)
IV.3- Opérateurs relationnels
Toute comparaison est une expression de type int qui
renvoie la valeur 0 (false) ou 1 (true). Il faut que les
opérandes soient du même type arithmétique.
Opérateurs Traduction Exemple Résultat
< inférieur a < b 1 si a inférieur strictement à b
<= Inférieur ou a <= b 1 si a inférieur ou égal à b
égal
> supérieur a > b 1 si a supérieur strictement à b
>= Supérieur a >= b 1 si a supérieur ou égal à b
ou égal
== Égalité a == b 1 si a est égal à b
!= Diffence a != b 1 si a est diffèrent de b
IV- Les opérateurs et expression (6)
IV.4-Opérateurs logiques
Les opérateurs logiques permettent de combiner
le résultat de plusieurs expressions de
comparaison en une seule expression logique.
(!=0 est vrai et ==0 faux)
Opérateurs Traduction Exemple Résultat
&& ET logique a && b 1 si a et b différents
de 0
|| OU a || b 1 si a ou b différents
logique de 0
! Négation !a 1 si a==0
IV- Les opérateurs et expression (7)
IV.5- Opérateurs bit à bit
Opérateurs Traduction Exemple Résultat
& ET bit à bit a & b 1 si les bits de x et
y valent 1
| OU bit à bit a | b 1 si le bit de x
et/ou de y vaut 1
^ XOR a ^ b 1 si le bit de x ou
de y vaut 1
~ NON bit à bit ~ a 1 si le bit de x est 0
<< Décalage à a << b décale chaque bit
8 gauche de x de y positions
vers la gauche
>> décalage à a >> b décale chaque bit
droite de x de y positions
vers la droite
IV- Les opérateurs et expression (8)
IV.5- Opérateurs bit à bit (exemple)

x y Opération Résultat

14 9 x&y

14 9 x|y

14 9 x ^y

14 ~x

14 2 x << y

14 2 x >> y
III- Les opérateurs et expression (8)
III.5- Opérateurs bit à bit (exemple)

x y Opération Résultat

14 1110 9 1001 x & y 8 1000

14 1110 9 1001 x | y 15 1111

14 1110 9 1001 x ^ y 7 111

14 1110 ~x 1 1

14 1110 2 10 x << y 56 111000

14 1110 2 10 x >> y 3 11
IV- Les opérateurs et expression (7)

IV.6- Autres
Op. Traduction Exemple Résultat
Exécute la fonction f
() Appel de fonction f(x,y) avec les argument
la valeur de x avec le
(type) cast (long)x type spécifié
nombre de bits occupé
sizeof taille en bits sizeof(x) par x
Evaluation si x est différent de 0,
?: condionnelle x?y:z alors y sinon z

, séquencement x,y Evalue x puis y


V- Les structures de contrôle
Comme pour la plupart des langages de
programmation, le langage C définit un certain
nombre de structures de contrôle (boucles et
branchements).
V.1- Instruction if...else
Syntaxe :
1. if ( expression ) Instruction1
2. if ( expression ) Instruction1 else Instruction2
Exemple :
if (x > y) //Assigne la plus grande valeur
max = x;
else // entre x et y à la variable max.
max = y;
V- Les structures de contrôle (2)
V.2- Instruction for (pour)
Syntaxe :
– for (expression1 ; expression2 ; expression3)
Instruction;
expression1 et expression3 peuvent être
n’importe quelle expression. expression2
est une expression de contrôle et doit donc être
de type scalaire.
V- Les structures de contrôle (3)
V.2- Instruction for (pour)
Organigramme de for :

expression1 Expression2! Fin for


=0
non
oui

instructions

expression3
V- Les structures de contrôle (4)
V.2- Instruction for (pour)
exemple :
int i,MAX=14; //compteur
for (i=0; i < MAX ; i++) {
printf("Valeur de i : %d\n",i);
}

Exo : écrire un programme C permettant de


compter les multiples de 5 jusqu’à 103.
V- Les structures de contrôle (5)
V.3- Instruction while (tantque)
Syntaxe :
– while (expression) Instruction
Il s’agit d’une boucle : tant que expression est
vraie, Instruction est exécutée.
V- Les structures de contrôle (6)
V.3- Instruction while (tantque)
Organigramme de while:

non
Expression2! Fin
=0 while

oui

expression3
V- Les structures de contrôle (7)
V.3- Instruction while (tantque)
exemple :
#define MAX 14
int i=0;
while (i < MAX ) {
printf("Valeur de i : %d\n",i);
i++;
}

Exo : écrire un programme C permettant de


compter les multiples de 5 jusqu’à 103.
V- Les structures de contrôle (8)
V.4- Instruction do … while (répéter)
Syntaxe :
do instruction while (expression) ;
l’instruction do...while a un fonctionnement
globalement similaire à celui d’une boucle while
mise à part le fait que le corps de la boucle est
exécutée avant que l’expression de contrôle soit
évaluée.
V- Les structures de contrôle (9)
V.4- Instruction do … while (répéter)
Organigramme de do :

instruction

non
Expression2! Fin do
=0

oui
V- Les structures de contrôle (10)
V.4- Instruction do … while (répéter)
exemple :
#include <stdio.h>
#define MAX 14
int main() {
int i=0;

do {
printf("Valeur de i : %d\n",i);
i++;
} while (i < MAX);
return 0;
}
Exo : écrire un programme C permettant de calculer
la table de multiplication d’un nombre entier compris
entre 1 à 10.
V- Les structures de contrôle (11)
V.5- Instruction switch (décider entre)
Cette instruction est un if généralisée. Sa syntaxe
est la suivante :
switch (expression) {
case constante1 : liste d′instructions1 break ;
...
case constanten : liste d′instructionsn break ;
default : liste d′instructions
}
V- Les structures de contrôle (12)
V.5- Instruction switch (décider entre)
1. expression est évaluée, puis le résultat est
comparé avec constante1, constante2
etc...
2. A la première constantei dont la valeur est
égale à expression, la (ou les) liste d′instructions
correspondante(s) est exécutée jusqu’à la
rencontre d’une instruction break. La rencontre
d’un break termine l’instruction switch.
V- Les structures de contrôle (12)
V.5- Instruction switch (décider entre)
3. s’il n’existe aucune constantei dont la valeur
soit égale à celle de expression, on exécute la
liste d′instructions de l’alternative default si
celle-ci existe, sinon rien n’est fait.
ATTENTION : expression est nécessairement une
valeur entière.
Exo
Ecrire un programme qui permet de traduire un
nombre entier compris entre 0 à 100 en lettre ie
1=un, …, 100=cent.
IV- Les structures de contrôle (13)
V.6- Instruction goto
Syntaxe :
goto etiquette ;
La directive goto permet de brancher directement
à n’importe quel endroit de la fonction courante
identifiée par une étiquette. Une étiquette est un
identificateur suivi du signe ”:”.
V- Les structures de contrôle (14)
V.6- Instruction goto
Exemple :
for ( ... )
for ( ... )
if ( erreur )
goto TRAITEMENT_ERREUR;
...
TRAITEMENT_ERREUR: // le traitement d’erreur
printf("Erreur: ...."); // est effectué ici
...
V- Les structures de contrôle (15)
V.7- Instruction break
Syntaxe :
break;
On a vu le rôle de l’instruction break au sein de la
directive de branchement multiple switch. On
peut l’utiliser plus généralement au sein de
n’importe quelle boucle (instructions for, while ou
do...while) pour interrompre son déroulement et
passer directement à la première instruction qui
suit la boucle.
V- Les structures de contrôle (16)
V.8- Instruction continue
Syntaxe :
continue;
L’instruction continue ne peut être utilisée que
dans le corps d’une boucle(instruction for, while
ou do). Elle permet de passer directement à
l’itération suivante.
V- Les structures de contrôle (17)
V.8- Instruction continue
exemple :
for (i = -10; i < 10; i++) {
if (i == 0) continue; // passer à 1 sans exécuter 0
… //la suite
...
}
I- Déclaration de fonction(1)
On l’aura compris : comme dans la plupart des
langages, on peut (doit ?) en C découper un
programme en plusieurs fonctions. Il existe
une unique fonction obligatoire : la fonction
principale appelée main.
Syntaxe :
type_resultat nom_fonction (type1 arg1, . . . ,
typen argn) {
<déclaration de variables locales >
<liste d’instructions >
 }
I- Déclaration de fonction(2)

 type_resultat correspond au type du résultat


de la fonction.
 Nom_fonction est le nom qui identifie la
fonction.
 type1 arg1 . . . typen argn définit les types et
les noms des paramètres de la fonction.
Ces arguments sont appelés paramètres
formels, par opposition aux paramètres
effectifs qui sont les paramètres avec lesquels
la fonction est effectivement appelée.
I- Déclaration de fonction(3)

Remarques :
1. Une fonction peut fournir comme résultat :
– un type arithmétique,
– void.
Une fonction ne peut pas fournir comme
résultat des tableaux, des chaînes de
caractères ou des fonctions, mais il est
cependant possible de renvoyer un pointeur
sur le premier élément d’un tableau ou d’une
chaîne de caractères.
2. Si une fonction ne fournit pas de résultat, il
faut indiquer void comme type du résultat.
Ex : void print_liste(liste L){...}
I- Déclaration de fonction(4)

Remarques :
3. Si une fonction n’a pas de paramètres, on
peut dèclarer la liste des paramètres comme
(void) ou simplement comme ().
Ex : int main(){...} // equivalent à int
main(void){...}
4. Il est interdit de définir des fonctions à
l’intérieur d’une autre fonction (comme en
Pascal).
5. En principe, l’ordre des définitions de
fonctions dans le texte du programme
ne joue pas de rôle, mais chaque fonction doit
être déclarée ou définie avant d’être appelée.
I- Déclaration de fonction(5)

Dans le cas où type_resultat est différent du


type void, le corps de la fonction doit
obligatoirement comporter une instruction
return, dite instruction de retour à la fonction
appelante. La syntaxe de cette instruction est :
return expression ;
Exo1 :
Ecrire une fonction produit de deux entiers a et b.
Ecrire une fonction somme de deux entiers a et b.
II- différent type de passage de paramètres (1)

En ce qui concerne le passage de paramètres à


une procédure, le programmeur a deux
besoins fondamentaux :
 soit il désire passer une valeur qui sera
exploitée par l’algorithme de la procédure
(c’est ce dont on a besoin quand on écrit par
exemple sin(x)). Une telle façon de passer un
paramètre s’appelle du passage par valeur ;
 soit il désire passer une référence à une
variable, de manière à permettre à la
procédure de modifier la valeur de cette
variable : echanger(&a,&b,&c).
II- différent type de passage de paramètres (2)
Exo1
Reprendre produit et somme et dites quel type de
passage avez-vous fait?
Ecrire la fonction Echange qui permet de changer la
valeur de a à celui de b. Quel type de passage de
variable doit on faire ?
II- différent type de passage de paramètres (2)
Corrigé
long produit(int a, int b)
{
return a * b;
}
void echange(int *a, int *b)
{
int x;
x=*a;
*a=*b;
*b=x;
}
III- Variable Locale, variable globale et variable
static (1)
III.1- Variable locale
Les variables déclarées dans un bloc
d’instructions sont uniquement visibles à
l’intérieur de ce bloc. On dit que ce sont des
variables locales à ce bloc.
Exemple : une variable déclarée dans une
fonction est locale à la fonction.
III- Variable Locale, variable globale et variable
static (2)
III.2- Variable globale
Les variables globale sont donc des variables
déclarée sen dehors de toute fonction, au
début du fichier, à l’extérieur de toutes les
fonctions et sont disponibles à toutes les
fonctions du programme. En général, les
variables globales sont déclarées
immédiatement derrière les instructions
#include au début du programme.
Elles sont systématiquement permanentes.
Remarque : Les variables déclarées au début de
la fonction principale main ne sont pas des
variables globales, mais locales à main !
III- Variable Locale, variable globale et variable
static (3)
III.2- Variable globale
Remarque : Je vous conseille donc d’écrire nos
programmes aussi ’localement’
que possible.
III- Variable Locale, variable globale et variable
static (4)
III.3- Variable static
Les variables permanentes (ou statiques)
occupe un emplacement en mémoire qui reste
le même durant toute l’exécution du
programme. Cet emplacement est alloué une
fois pour toutes lors de la compilation. La
partie de la mémoire contenant les variables
permanentes est appelée segment de données.
Par défaut, les variables permanentes
sont initialisées à zéro par le compilateur. Elles
sont caractérisées par le mot-clef static.
IV- la récursivité (1)

Comme pour beaucoup de langages, la


récursivité est possible en C. Qu’est ce que la
récursivité ? C’est la propriété qu’a une
fonction de s’auto-appeler, c’est-à-dire de se
rappeler elle-même plusieurs fois. La notion de
récurrence est largement présente dans le
domaine mathématique.
Considérons une suite
 u0 = 1

 un = 2un−1 + 1 ∀ n ≥ 1

écrire une fonction récursive permettant de calculer


le n terme de cette suite.
IV- la récursivité (2)

int ma_suite (unsigned int n) {


if (n == 0) return 1; //u_0 = 1
else return 2*ma_suite(n-1) + 1; //appel récursif
}
/* Fonction main: point d’entrée de l’exécution */
int main() {
unsigned int n;
puts("Entrer la valeur de n : ");
scanf("%u",&n);
printf("valeur de la suite : %u\n",ma_suite(n));
return 0;
}
IV- la récursivité (3)

Exo :
Ecrire une fonction permettant de calculer le factoriel
d’un nombre entier quelconque positif.
I- définition (1)
Les tableaux sont des paquets de données de
même type. Ils sont reconnus par la présence
de crochets ouvrants et fermants lors de la
déclaration ou de la définition de l’objet. La
taille du tableau est donnée entre les crochets
lors de la définition. Pour simplifier le travail du
compilateur, le rang des éléments du tableau
ne peut évoluer qu’entre 0 et la taille du
tableau -1.
I- définition (2)

Syntaxe :
Type_tab nom_tab[dimension];
Exemple :
int tab1[10];
Initialisation d’un tableau :
Int tab1[]={1,3,4,7,2,5,6,9,8,0}
Remarque :
la taille d’un tableau DOIT être connue
statiquement par le compilateur. Impossible
donc d’écrire int t[n] ou n est une variable.
I- définition (3)

Exo :
Écrire un programme c permettant de parcourir le
tableau ci-dessus déclaré.
II- dimension d’un tableau (1)
Les tableaux à deux dimensions sont des
tableaux de tableaux. Les indices de droite
sont les plus internes. Les tableaux à n
dimensions sont des tableaux d’indice variant
de 0 à n-1.
int tab1[10]; // est un tableau à une dimension
Int tab2[10][5]; // est un tableau à 2 dimensions
NB : pour accéder à l’adresse d’un élément on
utilise l’opérateur & : &tab1[5] est 4.
II- dimension d’un tableau (2)

Initialisation d’un tableau à double dimension.


int tab[3][4]={{1,5,8,3},{3,7,4,9},{2,6,3,0}}
Exo :
Ecrire un programme C permettant d’afficher les
éléments de ce tableau.
III- Tri(1)

II.1 tri par sélection


 Pour procéder à un tri par insertion, il suffit
de parcourir une liste : on prend les éléments
dans l'ordre. Ensuite, on les compare avec les
éléments précédents jusqu'à trouver la place
de l'élément qu'on considère. Il ne reste plus
qu'à décaler les éléments du tableau pour
insérer l'élément considéré à sa place dans la
partie déjà triée.
tri par sélection
void tri_selection(int *t, int n)
{
int i, min, j , tmp;
for (i =0; i < n -1; i++)
{
min = i;
for (j = i+1; j < n ; j++)
if (t[j] < t[min])
min = j;
if (min != i)
{
tmp = t[i];
t[i] = t[min];
t[min] = tmp;
}
}
}
II- Tri(2)

III.2 tri a bulle


Méthode de tri dans laquelle des paires de
valeurs adjacentes dans la liste à trier sont
comparées et échangées si elles ne sont pas
dans le bon ordre. Ainsi, les entrées de la liste
remontent comme des bulles jusqu'à ce
qu'elles rencontrent une valeur avec laquelle
elles sont bien rangées.
II- Tri(2)
III.2 tri a bulle
void tri_bulle(int tableau[],int longueur)
{
int i, inversion;
do
{
inversion=0;
for(i=0;i<longueur-1;i++)
{
if (tableau[i]>tableau[i+1]) x=tableau[i];
{
echanger(tableau,i,i+1); tableau[i]=tableau[i
inversion=1; +1];
} tableau[i+1]=x;
}
}
while(inversion);
}
II- Tri(3)

III.3 tri rapide


Le tri rapide (en anglais quicksort) est une
méthode de tri inventée par C.A.R. Hoare en
1961 et fondée sur la méthode de conception
diviser pour régner. Il peut être implémenté sur
un tableau (tri sur place) ou sur des listes ; son
utilisation la plus répandue concerne tout de
même les tableaux.
tri rapide

void tri_rapide_bis(int *t, int debut, int fin)


{
if(debut<fin)
{
int pivot=partition(t,debut,fin);
tri_rapide_bis(t,debut,pivot-1);
tri_rapide_bis(t,pivot+1,fin);
}
}
tri rapide
int partition(int *t, int deb, int fin)
{
int compt=deb;
int pivot=t[deb];
int i;
for (i=deb+1;i<=fin;i++)
{
if(t[i]<pivot)
{
compt++;
echanger(t,compt,i);
}
}
echanger(t,compt,deb);
return (compt);
}
tri rapide

void echanger(int *t, int i, int j)


{
int tmp;
tmp=t[i];
t[i]=t[j];
t[j]=tmp;
}
II- Tri(4)
III.4 recherche dichotomique
La recherche dichotomique est un algorithme
plus rapide que la recherche séquentielle. Il
consiste à diviser la structure de données en
deux parties égales : une partie contenant
forcément la valeur recherchée (si elle existe)
et l'autre partie pouvant être ignorée. Pour
cela, nous allons comparer l'élément recherché
à la valeur médiane de la structure de données
triée (pour cet exemple et pour les
implémentations qui vont suivre, considérons
les données triées par ordre croissant).
/* DECLARATION DES VARIABLES */
int iTableau[]={1,2,3,5,6,8,9}; /* Tableau TRIE
d’entiers */
int iRecherche; /* Elément recherché */
int iPremier; /* Indice du premier élément du
sous-tableau analysé */
int iDernier; /* Indice du dernier élément du
sous-tableau analysé */
int iMilieu; /* Indice de l'élément du milieu du
sous-tableau analysé */
int iTrouve;
iPremier=0;
iDernier=taille-1;
iTrouve=0;
while((iPremier <= iDernier)&&(iTrouve==0))
{
/* Calcul de la position de l'élément du milieu */
iMilieu=(iPremier+iDernier)/2;
/* Si l'élément du milieu est l'élément recherché */
if(iTableau[iMilieu]==iRecherche)
iTrouve =1;
else
{
/* Si la valeur recherchée est plus petite */
/* que la valeur du l'élément du milieu */
/* Alors on regarde le sous-tableau de gauche */
if(iTableau[iMilieu]>iRecherche)
iDernier = iMilieu -1;
/* sinon on regarde le sous-tableau de droite*/
else
iPremier = iMilieu +1;
}
}
Ecrire deux fonctions qui permettent de lire
et afficher une matrice dynamique (m et n
ne sont pas connus d’avance)
Ecrire des fonctions de manipulations des
opérations suivantes :
- Transposée
- Addition
- Multiplication.
NB : les conditions de calcul sont vérifiées
au niveau de main() avant l’appel de toute
opération.
I- Les notions d’adresse et de pointeurs
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.
En définitive un pointeur est une variable de type
adresse.
I- Les notions d’adresse et de pointeurs
I- Les notions d’adresse et de pointeurs
Avantages des pointeurs :
1. Manipulation des données de taille importante :
référence au premier élément du tableau,
2. Possibilité de créer des chaînes de caractères de
tailles diverses
3. Utilisation des listes chaînées.
II- La création d’un pointeur et l’opérateur *, l’opérateur
&
II.1- Déclaration d’un pointeur :
type_donnees *nompointeurs;
Exemples:
int *i; // i pointe vers un int
char *nom; // nom pointe vers un char
void *varqcq; // varqcq pointe vers n’importe quel objet
void *malloc(size_t size);//fonction pour allocation
mémoire à n’importe quel type
II- La création d’un pointeur et l’opérateur *, l’opérateur &
II.2- les opérateurs & et *
L’opérateur d’adresse & permet d’accéder à l’adresse d’une
variable. La syntaxe est la suivante :
 int *p; //étape (1): pointeur vers un entier non initialisé
 int i = 14; //étape (2): variable entière initialisée à 14
 p=&i; //étape (3): p pointe vers i
L’opérateur (de contenu) unaire d’indirection * permet
d’accéder directement de l’objet pointé (on dit qu’on fait
référence à un pointeur).
Exemple : int i, *p;
i=24;
p=&i;// et *p représente le contenu de i.
III- Le s pointeurs et les structures
III.1- les structures
Une structure est une suite finie d’objets de types différents. Ce
mécanisme permet de grouper un certain nombre de variables
de types différents au sein d’une même entité.
Syntaxe :
struct nom_structure {
type_1 membre1 ;
type_2 membre2 ;
...
type_n membren ;
};
Déclaration :
struct nom structure identificateur-objet ;
III- Le s pointeurs et les structures
III.1- les structures
Exemple :
struct complexe {
double reelle; //partie réelle
double imaginaire; //partie imaginaire
}; // ne pas oublier le ";"
struct complexe z; //déclaration d’un objet de type struct
complexe
z.reelle=1.453;
z.imaginaire=3.75;
Ou struct complexe z={1.453,3.75};
Struct complexe z1,z2; on peut z1=z2;
Struct complexe t[100];
NB : Pas de comparaison possible avec les structures
III- Le s pointeurs et les structures
III.2- les pointeurs , structures et opérateur ->
struct personne
{
char nom[20];
char prenom[20];
};
struct personne pers;
struct personne *p;
p=&pers;
Pour accéder aux membres on fait :
Pers.nom="toto";
Pers.prenom="tata";
(*p).nom="toto"; ou p->nom ="toto"; ou p=&pers;
III- Le s pointeurs et les structures
III.3- les listes chaînées
Il s’agit le cas particulier de structures dont un des
membres pointe vers une structure du même type. Cette
représentation permet en particulier de construire des
listes chaînées.
l’élément de base de la chaîne est une structure appelée
cellule qui contient la valeur d’un élément de la liste
et un pointeur sur l’élément suivant. Le dernier élément
pointe sur le pointeur NULL (défini dans stddef.h ou
<cstddef>). La liste est alors définie comme un pointeur
sur le premier élément de la chaîne.
III- Le s pointeurs et les structures
III.3- les listes chaînées
struct ientier
{
int data;
struct ientier *next;
};
Déclaration :
typdef struct ientier *liste;
III- Le s pointeurs et les structures
III.3- les listes chaînées
liste inserer(int element, liste Q) {
liste L;
L = (liste)malloc(sizeof(struct ientier)); // allocation de la
// zone mémoire necéssaire
L->data = element;
L->next = Q;
return L;
}
On appelle :
l1=NULL;
l1=inserer(6,l1);
III- Le s pointeurs et les structures
III.3- les listes chaînées
Pour supprimer le premier élément de la liste par
exemple, il est important de libérer l’espace mémoire
alloué :
liste supprime_tete(liste L) {
liste suivant = L;
if (L != NULL) { // pour etre sûr que L->next existe
suivant= L->next;
free(L); //libération de l’espace alloué pour une cellule
}
return suivant;
}
III- Le s pointeurs et les structures
III.3- les listes chaînées
III- Le s pointeurs et les structures
III.4- l’arithmétique des pointeurs
Les seules opérations arithmétiques valides sur les
pointeurs sont :
– l’addition d’un entier `a un pointeur → p + i
Le résultat est un pointeur de même type que le pointeur
de départ.
– la soustraction d’un entier `a un pointeur → p – i
Le résultat est un pointeur de même type que le pointeur
de départ.
– la différence de deux pointeurs −→ p1 – p2
Il faut absolument que les deux pointeurs pointent vers
des objets de même type T. Le résultat est un entier dont
la valeur est égale à (p1 - p2)/sizeof(T).
Attention : la somme de deux pointeurs n’est pas
autorisée !
III- Le s pointeurs et les structures
III.5(0)- allocation dynamique
Les fonctions pour la gestion dynamique de la mémoire
sont déclarées dans le fichier stdlib.h.
L’opération consistant à réserver un espace-mémoire est
réalisée par la fonction malloc. Sa syntaxe est :
 malloc(nb octets)
Ainsi, pour initialiser un pointeur vers un entier, on écrit :
 int *p;
 p = (int*)malloc(sizeof(int)); // allocation dynamique
 *p = 14;
 Free(p);//liberer la mémoire
 NB pour un tableau N taille (N constante) l’allocation :
tab=(int*)malloc(N*sizeof(int)); et tab =
(int*)calloc(N, sizeof(int)); initialisation de tous les
éléments à 0.
III- Le s pointeurs et les structures
III.6- les pointeurs de tableaux, les tableaux de pointeurs
Un tableau est un pointeur constant. Par exemple un
tableau int t[5] est un tableau dont les valeurs varient de 0
à 4. On a aussi t a pour valeur &t[0] donc int *p
Pour afficher les éléments de t en utilisant *p
p=t;
for (int i=0; i<5;i++)
{
printf("valeur n° %d est %d",i,*p);
p++;
}
III- Le s pointeurs et les structures
III.6- les pointeurs de tableaux, les tableaux de pointeurs
on a les équivalences suivantes :
t + 1 ⇐⇒ &(tab[1]) (adresse du 2ième élément);
*(t + 1) ⇐⇒ t[1] (valeur du 2ième élément);
*t ⇐⇒ t[0] (valeur du 1er élément);
*(t + k) ⇐⇒ t[k] (valeur du (k+1)ème élément);
t + k ⇐⇒ &(t[k]) (adresse du (k+1)ème élément).
NB : impossible de créer t[n] où n est une variable;
Impossible de créer un t[][] où on peut avoir t[1][nb1] et
t[2][nb2] et nb1#nb2.
III- Le s pointeurs et les structures
III.6- les pointeurs de tableaux, les tableaux de pointeurs
int n, *tab;
tab = (int*)malloc(n * sizeof(int));
tab[0]=5;// jusqu’à n-1
...
free(tab);
Aussi on peut déclarer un tableau à double dimension :
Int **tab.
III- Le s pointeurs et les structures
III.6- les pointeurs de tableaux, les tableaux de pointeurs
int k=14, n=5;
int **tab; // pointeur vers la matrice
tab = (int**)malloc(k * sizeof(int*));
for (i = 0; i < k; i++){
tab[i] = (int*)malloc(n * sizeof(int));
....
for (i = 0; i < k; i++)
free(tab[i]);
free(tab);
}
III- Le s pointeurs et les structures
III.6- les pointeurs de tableaux, les tableaux de pointeurs
La définition d’un tableau de pointeur est :
type *nom_tableau[taille] ;
Exemple :
int tab[8], *pt[8] =
{tab,tab+1,tab+2,tab+3,tab+4,tab+5,tab+6,tab+7};
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Déclaration de chaînes de caractères en C
char <NomVariable> [<Longueur>];
Exemples
char NOM [20];
char PRENOM [20];
char PHRASE [300];
Espace à réserver
Lors de la déclaration, nous devons indiquer l'espace à
réserver en mémoire pour le stockage de la chaîne.
La représentation interne d'une chaîne de caractères est
terminée par le symbole '\0' (NUL). Ainsi, pour un texte
de n caractères, nous devons prévoir n+1 octets.
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Remarques importantes
- La fonction scanf a besoin des adresses de ses
arguments:
* Les noms des variables numériques
(int, char, long, float, ...) doivent être marqués par le
symbole '&' .
* Comme le nom d'une chaîne de caractères est le
représentant de l'adresse du premier caractère de la
chaîne, il ne doit pas être précédé de l'opérateur adresse
'&' !
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Remarques importantes
- Scanf lit seulement un mot pas une chaine de caractère.
- Ceci est resolu par :

fgets(chaine1, sizeof(chaine1), stdin);


III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <string>
fournit la longueur de la
strlen(<s>) chaîne sans compter le '\0'
final

strcpy(<s>, <t>) copie <t> vers <s>

strcat(<s>, <t>) ajoute <t> à la fin de <s>

compare <s> et <t>


strcmp(<s>, <t>) lexicographiquement et
fournit un résultat:
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <string>

copie au plus <n>


strncpy(<s>, <t>,
caractères de <t>
<n>)
vers <s>

ajoute au plus <n>


strncat(<s>, <t>,
caractères de <t>
<n>)
à la fin de <s>
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <stdlib>

retourne la valeur numérique


atoi(<s>)
représentée par <s> comme int

retourne la valeur numérique


atol(<s>)
représentée par <s> comme long

atof(<s>) retourne la valeur numérique


représentée par <s> comme double (!)
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <stdlib>
Conversion de nombres en chaînes de caractères
itoa (<n_int>, <s>, <b>)
ltoa (<n_long>, <s>, <b>)
ultoa (<n_uns_long>, <s>, <b>)
Chacune de ces trois procédures convertit son premier
argument en une chaîne de caractères qui sera ensuite
attribuée à <s>. La conversion se fait dans la base <b>.
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <ctype>

La fonction: retourne une valeur différente de zéro,

isupper(<c>) si <c> est une majuscule ('A'...'Z')

islower(<c>) si <c> est une minuscule ('a'...'z')

isdigit(<c>) si <c> est un chiffre décimal ('0'...'9')


III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <ctype>

retourne une valeur différente de


La fonction:
zéro,

isalpha(<c>) si islower(<c>) ou isupper(<c>)

isalnum(<c>) si isalpha(<c>) ou isdigit(<c>)

isxdigit(<c>) si <c> est un chiffre hexadécimal

('0'...'9' ou 'A'...'F' ou 'a'...'f')


III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <ctype>

retourne une valeur différente de


La fonction:
zéro,

isspace(<c>) si <c> est un signe d'espacement

(' ', '\t', '\n', '\r', '\f')


III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
Les fonctions de <ctype>
Les fonctions de conversion suivantes fournissent une
valeur du type int qui peut être représentée comme
caractère; la valeur originale de <c> reste inchangée:

retourne <c> converti en minuscule si


tolower(<c>)
<c> est une majuscule

retourne <c> converti en majuscule si


toupper(<c>)
<c> est une minuscule
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
les pointeurs de chaînes de caractères
Un pointeur sur char peut en plus contenir l'adresse d'une
chaîne de caractères constante et il peut même être
initialisé avec une telle adresse.
char *c;
c="Ceci est une constante de";

char *A = "Petite chaîne";


char *B = "Deuxième chaîne un peu plus longue";
A = B;
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
les pointeurs de chaînes de caractères

NB : Les affectations discutées ci-dessus ne peuvent pas être


effectuées avec des tableaux de caractères:
char A[45] = "Petite chaîne";
char B[45] = "Deuxième chaîne un peu plus longue";
char C[30];
A = B; /* IMPOSSIBLE -> ERREUR !!! */
C = "Bonjour !"; /* IMPOSSIBLE -> ERREUR !!! */
III- Le s pointeurs et les structures
III.7- les pointeurs de chaînes de caractères
les pointeurs de chaînes de caractères
Les différentes façon de déclarer une chaine de caractères
char A[] = "Bonjour !"; /* un tableau */
char *B = "Bonjour !"; /* un pointeur */
Conclusions:
 Utilisons des tableaux de caractères pour déclarer les
chaînes de caractères que nous voulons modifier.
 Utilisons des pointeurs sur char pour manipuler des
chaînes de caractères constantes (dont le contenu ne
change pas).
 Utilisons de préférence des pointeurs pour effectuer les
manipulations à l'intérieur des tableaux de caractères.
III- Le s pointeurs et les structures
III.8- les fonctions et les pointeurs
Les passages de variables :
in add(int a, int b){
return a+b;
}
//appel
int a,b ;
int resutat=add(a,b); // passage par valeur.
void add(int a, int b, int *resultat){
*resultat=a+b;
}
//appel
int a, b, c;
add(a,b,&c); //a et b par valeur et c par adresse
III- Le s pointeurs et les structures
III.9 Pointeur de fonction
En langage C, le nom d’une fonction est considéré comme
une adresse de manière identique au nom d’un tableau. Le
nom d’une fonction correspond à l’adresse de la première
instruction à l’intérieur du code exécutable, une fois
l’édition de liens réalisée : appelé lien direct (early
binding). Cependant nous pouvons utiliser les liens
indirects dynamiques (pointeur de fonction) utilisés
seulement au moment de l’exécution du programme
(runtime) : en anglais late binding.
Considérons l’exemple ci-dessous illustrant les liens
indirects dynamiques :
III- Le s pointeurs et les structures
III.9 -Pointeur de fonction
int add(int nX, int nY)
{
return nX + nY;
}

int main()
{
// Create a function pointer and make it point to the Add
function
int (*pFcn)(int, int) = Add;
cout << pFcn(5, 3) << endl; // add 5 + 3

return 0;
}
III- Le s pointeurs et les structures
III.10 –les unions
Les unions permettent l’utilisation d’un même espace
mémoire par des données de types différents à des
moments différents..
Syntaxe :
union nom_de_union {
type1 nom_champ1 ;
type2 nom_champ2 ;
type3 nom_champ3 ;
type4 nom_champ4 ;
...
typeN nom_champ_N ;
} variables ;
III- Le s pointeurs et les structures
III.10 –les unions
exemple
union zone {
int entier;
long entlong;
float flottant;
double flotlong;
} z1,z2;
Les différents “champs” d’une union sont à la même
adresse physique. Ainsi, les égalités suivantes sont vraies :
&z1.entier == (int*)&z1.entlong
&z1.entier == (int*)&z1.flottant
&z1.entier == (int*)&z1.flotlong
III- Le s pointeurs et les structures
III.10 –les unions
Les unions ne sont pas destinées à faire des conversions.
Elles ont étés inventées pour utiliser un même espace
mémoire avec des types de données différents dans des
étapes différentes d’un même programme.
Elles sont, par exemple, utilisées dans les compilateurs.
Comme beaucoup de langages, le C offre la
possibilité de lire et d’écrire des données dans un
fichier. Pour des raisons d’efficacité, les accès à un
fichier se font par l’intermédiaire d’une mémoire-
tamp (on parle de buffer), ce qui permet de réduire
le nombre d’accès aux périphériques (disque...).
Pour pouvoir manipuler un fichier, un programme
a besoin d’un certain nombre d’informations :
l’adresse de l’endroit de la mémoire-tampon où se
trouve le fichier, la position de la tête de lecture, le
mode d’accès au fichier (lecture ou écriture).
#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])


{
char nomfich[21] ;
struct personne
{ int id;
char nom[20];
char prenoms[20];
int age;

}p1;
int n=0 ;
FILE * sortie ;
printf ("nom du fichier a creer : ") ;
scanf ("%20s", nomfich) ;
sortie = fopen (nomfich, "a+") ;
do { printf ("donnez id : ") ;
scanf ("%d", &p1.id) ;
printf ("donnez nom : ") ;
scanf ("%s", p1.nom);
printf ("donnez prenoms : ") ;
scanf ("%s", p1.prenoms) ;
printf ("donnez age : ") ;
scanf ("%d", &p1.age) ;
n++;
fwrite (&p1, sizeof(personne), 1, sortie) ;
}
while (n<=4) ;
fclose (sortie) ;
#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])


{
char nomfich[21] ;
struct personne
{ int id;
char nom[20];
char prenoms[20];
int age;

}p1;
FILE * entree ;
printf ("nom du fichier a lister : ") ;
scanf ("%20s", nomfich) ;
entree = fopen (nomfich, "r") ;
int tot=0;
int i=0;
while ( fread (&p1, sizeof(p1), 1, entree), ! feof(entree) )
{
printf("id : %d | ",p1.id);
printf ("nom : %20s | ", p1.nom) ;
printf ("prenoms : %20s | ", p1.prenoms) ;
printf ("age : %d \n", p1.age) ;
tot+=p1.age;
i++;
}) ;
printf("age total = %d \t",tot);
printf("age moyen = %d \n",tot/i);
fclose (entree) ;
I- Ouverture et fermeture de fichiers
Lorsqu’on désire accéder à un fichier, il est
nécessaire avant tout accès d’ouvrir
le fichier à l’aide de la fonction fopen.
Cette fonction, de type FILE * ouvre un fichier et lui
associe un flot de données.
Sa syntaxe est :
fopen("nom-de-fichier","mode")
La valeur retournée par fopen est
– soit un flot de données ;
– soit NULL si l’exécution de cette fonction ne se
déroule pas normalement.
I- Ouverture et fermeture de fichiers
Les différents modes d’accès
"r" ouverture d’un fichier texte en lecture
"w" ouverture d’un fichier texte en écriture
"a" ouverture d’un fichier texte en écriture à la
fin
"rb" ouverture d’un fichier binaire en lecture
"wb" ouverture d’un fichier binaire en écriture
"ab" ouverture d’un fichier binaire en écriture à
la fin
I- Ouverture et fermeture de fichiers
Les différents modes d’accès
"r+" ouverture d’un fichier texte en
lecture/écriture
"w+" ouverture d’un fichier texte en
lecture/écriture
"a+" ouverture d’un fichier texte en
lecture/écriture à la fin
"r+b" ouverture d’un fichier binaire en
lecture/écriture
"w+b" ouverture d’un fichier binaire en
lecture/écriture
"a+b" ouverture d’un fichier binaire en
lecture/écriture à la fin
I- Ouverture et fermeture de fichiers
Conditions particulières et cas d’erreur
 r : le fichier doit exister, sinon c’est une erreur
 w : le fichier peut ne pas exister. Dans ce cas, il
sera créée, et si le fichier existait déjà, son ancien
contenu est perdu.
 a : le fichier peut ne pas exister. Comme pour le
cas précédent, si le fichier n’existe pas, il est
créée ; si le fichier existe déjà, son ancien
contenu est conservé.
 Si un fichier est ouvert en mode ”écriture à la fin”,
toutes les écritures se font à l’endroit où était la
fin du fichier lors de l’exécution de l’ordre
d’écriture.
I- Ouverture et fermeture de fichiers
Les modes de communication standard
Il existe 3 modes de communication standard
lors de l’exécution d’un fichier par le système :
– stdin (standard input) : flot d’entrée (par
défaut, le clavier) ;
– stdout (standard output) : flot de sortie (par
défaut, l’´ecran) ;
– stderr (standard error) : flot d’affichage des
messages d’erreur (par défaut,l’´ecran).
Ces trois constantes se définies dans la
bibliothèque <stdio.h>.
I- Ouverture et fermeture de fichiers
Les modes de communication standard
NB : Il est fortement conseillé d’afficher
systématiquement les messages d’erreur sur stderr
afin que ces messages apparaissent à l’écran
même lorsque la sortie standard est redirigée.
Utilisation typique de fopen
#include <stdio.h>
FILE *fp;
...
if ((fp = fopen("donnees.txt","r")) == NULL) {
fprintf(stderr,"Impossible d’ouvrir le fichier
données en lecture\n");
exit(1);
}
II- Fermeture de fichiers : la fonction fclose
Elle permet de fermer le flot qui a été associé à
un fichier par la fonction fopen.
Sa syntaxe est :
fclose(flot)
où flot est le flot de type FILE* retourné par la
fonction fopen correspondante.
La fonction fclose retourne 0 si l’opération
s’est déroulée normalement et EOF si il y a eu
une erreur.
III- Les entrées-sorties formatées
III.1- La fonction d’écriture en fichier fprintf
La fonction fprintf, analogue à printf permet
d’écrire des données dans un flot. Sa syntaxe
est :
fprintf(flot,"chaîne de contrôle", expression1, .
. . , expressionn);
où flot est le flot de données retourné par la
fonction fopen. Les spécifications de format
utilisées pour la fonction fprintf sont les
mêmes que pour printf puisque :
printf(...) ⇐⇒ fprintf(stdout,...)
III- Les entrées-sorties formatées
III.2- La fonction de saisie en fichier fscanf
La fonction fscanf, analogue à scanf, permet de
lire des données dans un fichier. Sa syntaxe est
semblable `a celle de scanf :
fscanf(flot,"chaîne de contrôle", arg1, . . . ,
argn);
où flot est le flot de données retourné par
fopen. Les spécifications de format sont ici les
mêmes que celles de la fonction scanf.
IV- Impression et lecture de caractères dans un
fichier
IV.1- Lecture et écriture par caractère : fgetc et
fputc
Similaires aux fonctions getchar et putchar les
fonctions fgetc et fputc permettent
respectivement de lire et d’écrire un caractère
dans un fichier.
La fonction fgetc retourne le caractère lu dans
le fichier et la constante EOF.
IV- Impression et lecture de caractères dans un
fichier
IV.1- Lecture et écriture par caractère : fgetc et
fputc
lorsqu’elle détecte la fin du fichier. Son prototype
est :
int fgetc(FILE* flot);
où flot est le flot de type FILE* retourné par la
fonction fopen.
La fonction fputc écrit un caractère dans le flot de
données :
int fputc(int caractere, FILE *flot)
Elle retourne l’entier correspondant au caractère lu
(ou la constante EOF en cas d’erreur).
IV- Impression et lecture de caractères dans un
fichier
IV.2- Lecture et écriture optimisées par caractère :
getc et putc
Il existe également deux versions optimisées des
fonctions fgetc et fputc qui sont implémentées par
des macros. Il s’agit respectivement de getc et
putc.
Leur syntaxe est similaire à celle de fgetc et fputc :
int getc(FILE* flot);
int putc(int caractere, FILE *flot)
Ainsi, le programme suivant lit le contenu du
fichier texte entree.txt, et le
recopie caractère par caractère dans le fichier
sortie.txt:
Exercice
rappel
 a & 0x0F permet d'isoler les 4 bits de poids
faible de a (masque des 4 bits LSB : 0x0F).
 a & (1<<n) est nul si le nème bit de a vaut 0,
non nul s'il vaut 1.
mise à 0 ou à 1 de certains bits d'une valeur :
 a = a | 0x0F met à 1 les 4 bits de poids faible
de a ;
 a = a & ~(1<<n) met à 0 le nème bit de a.

 a = a | (1<<n) met à 1 le nème bit de a.


Exercice
Exercice 1
Ecrire un programme qui affiche sous forme binaire
le résultat d’un OU, d’un ET ou d’un OU EXCLUSIF
entre deux entiers entrés au claviers selon le choix
de l’utilisateur.
Exercice
Correction exercice 5
int main(int argc, char *argv[]) {
int nb1, nb2;
int choix;
int nombre;
int mem,i;
nb1= 14;
nb2= 10;
printf("votre choix(AND=1, OR=2, XOR=3):");
scanf("%d",&choix);
if(choix==1)
nombre=nb1&nb2;
else
if (choix==2)
nombre=nb1|nb2;
else
nombre=nb1^nb2;
Exercice
Correction exercice 5
i=0;
while(i < 8*sizeof(int))
{
mem = nombre << 1;
mem >>= 1;
putch((nombre == mem)? '0' : '1');
nombre <<= 1;
i++;
}

return 0;
}
Exercice
Exercice 3.4 : écrire un programme qui affiche
horizontalement un histogramme des
fréquences des caractères d'un fichier texte.
On pourra distinguer les lettres majuscules des
lettres minuscules, les chiffres et les autres
caractères.
 Le principe est le suivant :
 constitution d'un tableau entier des effectifs,
à partir du caractère saisi,
 calcul des fréquences (attention au type),
 affichage (attention au type).
Exercice
Exercice 3.4 : histogramme des caractères d'un fichier
#define TAILLE 37
#define NLETTRES 26
#define NCHIFFRES 10
#include <stdio.h>
int main(void)
{/* définitions et initialisations */
int c, i, j ,k , tab[TAILLE] , somme =0;
float total = 0., pour = 0.;
for(i = 0 ; i < TAILLE ; i++) tab[i] = 0;
/* saisie des variables */
while((c = getchar()) !=EOF)
{
/* remplissage du tableau (lettres) */
if( (( c>= 'A') && (c <= 'Z')) ||
(( c>= 'a') && (c <= 'z')) ) tab[(c-'A') %32 ] ++;
else /* chiffres */
if ( (c>= '0') && (c <= '9')) tab[(c -'0')+NLETTRES]++;
else tab[TAILLE-1]++; /* divers */
} /* fin de la saisie */
Exercice
/* calcul de l'effectif total */
for(i = 0; i < TAILLE;i++) somme += tab[i];
printf("somme = %d\n",somme);
/* affichage des résultats */
for(i = 0; i < NLETTRES;i++) /* boucle sur les lettres */
{
printf( " %c ", i+'A');
pour = (float)tab[i] /(float) somme; /* sommation des pourcentages */
total += pour;
k = (int) ( 100 * pour);
for (j = 0; j < k ; j++) printf("x");
printf("\n");
}
for(i = NLETTRES; i < NLETTRES+NCHIFFRES; i++) /* boucle sur les chiffres */
{printf( " %c ", i+'0' - NLETTRES);
pour = (float)tab[i] /(float) somme;
total += pour;
k = (int) ( 100 * pour);
or (j = 0; j < k ; j++) printf("x");
printf("\n");
}
*/
Exercice
 printf( " divers %s ");
 pour = (float) tab[TAILLE-1] /(float) somme ;
 total += pour;
 k = (int) (100 * pour) ;
 for (j = 0; j < k ; j++) printf("x");
 printf("\n");
 printf(" pourcentage traité : %6.2f\n", 100 *
total);
 return(1);
 }
Exercice
 Exercice 5.3 : écrire un programme de
suppression d'une occurrence c dans une chaîne
de caractère s. La fonction de suppression est la
fonction squezze.
 Exercice 5.4 : écrire un programme d'écriture des
caractères d'une chaîne dans l'ordre inverse.
 Exercice 5.5 : écrire une fonction atoi qui assure
la conversion d'une chaîne numérique en un
nombre entier. Cette fonction de la bibliothèque
C retourne zéro si la chaîne est non numérique.
 Exercice 5.6 : écrire un programme de recherche
de la ligne la plus longue d'un fichier. On devra
définir les fonctions :
 getline saisie d'une ligne de texte,
 copy recopie une chaîne de caractères dans
une autre.
Exercice
 Exercice 3.5 : écrire un programme qui
dessine un histogramme des fréquences des
longueurs des mots d'un fichier de texte.
L'histogramme est dessiné horizontalement.
Les pourcentages correspondants sont
ensuite calculés. On se limitera à des mots
d'au plus 25 caractères.
Exercice
Exercice 3.2 : écrire un programme de
comptage des chiffres, lettres et autres
caractères spéciaux (blanc, tabulation, fin de
ligne). Les nombres des occurrences des
chiffres, des lettres de l'alphabet, des
caractères spéciaux, seront respectivement
stockées dans les variables chiffre, lettre,
autre.
Exercice
#include <iostream>
#include <stdio.h>
int main(int argc, char** argv) {

int c, nb = 0 , ntab = 0, nl = 0;
while (( c = getchar()) != EOF )
{if (c == ' ' ) ++ nb;
else if (c == '\t') ++ntab;
else if (c == '\n') ++nl;
}
printf("nombre de blancs =");
printf("%d \n",nb);
printf("nombre de tabulations = %d",ntab);
printf("\nnombre de lignes = %d\n",nl);

return 0;
}
Exercice
Exercice 3.1 : écrire un programme de
comptage du nombre de lignes, de mots, de
caractères du fichier d'entrée standard. Utiliser
ce programme sur n'importe quel fichier texte
Exercice
#include <iostream>
#include <stdio.h>
#define YES 1
#define NO 0

int main(int argc, char** argv) {


int c,nl,nmot,ncar,dansmot;

dansmot = NO; nl = nmot = ncar = 0 ;


while ((c = getchar()) != EOF )
{++ ncar;
if ( c == '\n' ) ++ nl;
if ( c == ' ' || c == '\n' || c == '\t') dansmot= NO;
else if (dansmot == NO) {dansmot = YES; ++nmot; }
}
printf("nombre de lignes : %d \nnombre de mots : %d ncar %d\n",
nl, nmot, ncar);
}
return 0;
}
Exercice
Exercice 3.2
#include <stdio.h>
int main(void)
{/* initialisation */
int c,i,lettre, autre;
int chiffre[10];
lettre = autre = 0;
for(i = 0; i < 10; ++i) chiffre[i] = 0;
while ((c = getchar()) != EOF)
/* traitement des chiffres */
if( c >= '0' && c <= '9') ++chiffre[c-'0'];
/* traitement des caractères spéciaux */
else
if (c == ' ' || c == '\n' || c == '\t') ++lettre; else ++autre;
printf("nombre de chiffres :");
for(i = 0;i <10;++i) printf(" %d",chiffre[i]);
printf("\nespaces blancs = %d,autres = %d\n",lettre, autre);
}
Exercice
Exercice 3.3
int main(void)
/* programme d'affichage des années
bissextiles*/
{int annee;
printf("\n liste des années bissextiles\n");
for (annee = 1000; annee < 2001; annee++)
if ( annee % 4 == 0 && annee % 100 != 0 ||
annee % 400 == 0)
printf("%d ",annee);
}

Vous aimerez peut-être aussi