Langage C Module 1 21

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 144

Présenté par Ghislain AKINOCHO

Le Langage C
Initiation à la programmation procédurale
Module-1 – Concepts fondamentaux Module-2 – Concepts avancés
 Qu’est ce qu’un programme ? un bon  Les macros et la compilation conditionnelle
programme ?
 Les structures de données (struct et typedef)
 Présentation du Langage C (Historique)
 Les listes chaînées
 Programmer en C (Les 3 grandes étapes)
 Les piles et les files
 La syntaxe du langage
AGENDA  Les entrées-sorties standard <stdio.h>
 Les fichiers séquentiels
 Les bibliothèques statiques (.a)
 Les opérateurs , les expressions et le
transtypage  Les bibliothèques dynamiques (.dll)

 Les structures de contrôle


 Les tableaux, les pointeurs et les chaînes de
caractères – La bibliothèque <string.h>
 Les fonctions
 Les arguments de la fonction main
Les concepts fondamentaux

Module - 1
Le Langage C
Qu’est ce qu’un programme ?

Qu’est ce qu’un
programme ?

Le Langage C
Suite d’instructions

En langage machine Exécutable par l’ordinateur

Cohérence
Autonomie
Qu’est ce qu’un bon programme ?

Qu’est ce qu’un bon


programme ?

Le Langage C
Il doit résoudre le problème Période d’exploitation élevée (en années)

Efficacement et Rapidement
Claire et lisible Structuré
Le Langage C

Présentation
Présentation

 Un langage de programmation a pour but de permettre la communication entre


une machine et un être humain (le développeur).

Le Langage C  Le langage maternel de la machine n'utilise que deux symboles (0 et 1) : c'est le


langage machine.
 Par exemple : le nombre 5 est reconnu par une machine par la succession des
symboles 0101 (c'est la représentation du nombre en base 2 (en binaire)).

 De même, les opérations qu'une machine est capable d'exécuter sont codées par des
nombres, c'est-à-dire une succession de 0 et 1.
 Par exemple : l'instruction machine 1010101101010110 demande à la machine
d’effectuer la somme : 5+6 (0101 (5) + 0110 (6))
Présentation

 Détaillons l’instruction

Le Langage C 10101011 0101 0110


code de l’opération Opérande 1 Opérande 2
Additionner

 Cette instruction signifie : « Additionner (10101011) 5 (0101) et 6 (0110) »


Présentation

 Il apparaît évident que développer dans ces conditions s’avère fastidieux car il
faut :
 Maîtriser le langage binaire mais également

Le Langage C  Les caractéristiques physiques des machines sous-jacentes.

 Face à cela, il était donc nécessaire voire vital de définir des langages moins
contraignants, plus intuitifs et surtout plus proches du langage humain.

 C’est donc l’avènement de très nombreux langages dits évolués.


 Parmi eux le Langage C
Historique
▪ 1945 – Langage Binaire
▪ 1950 – Langage Assembleur
▪ 1955 – FORTRAN
▪ 1960 – ALGOL – COBOL
▪ 1965 – BASIC

1972 – C - créé par Denis Ritchie


Le Langage C ❖ 1978 – Définition rigoureuse « The C Programming Language » par Kernighan et Ritchie (K&R 78)
– plus tard avec Ken Thomson, ils écrivent en C le système UNIX
✓ Le succès d’Unix induisit celui du Langage C
✓ Plusieurs compilateurs sur le marché (Mais non conformes à la version K&R 78)
✓ Fin des années 80 : Nécessité de mettre de l’ordre dans ce chaos à travers une normalisation du langage C
❖ 1989 – ANSI C (ou C89), American National Standard Institute
❖ 1990 – ISO (International Standards Organization) l’adopte tel quel …
❖ Versions plus récentes (C11, C99 …)

http://www.open-std.org/jtc1/sc22/wg14/
Les caractéristiques

▪ Langage de bas niveau :


▪ Accès à des données telles que des bits, des adresses mémoire, …

Le Langage C ▪ Permet donc l’écriture de systèmes d’exploitation et de logiciels.

▪ Dispose également de structures de base nécessaires à la conception d’applications


structurées, ce qui en fait aussi un langage de haut niveau

▪ Un des premiers langages offrant des possibilités de programmation modulaire (regroupement


de fonctions par thématiques)
Les trois étapes de
Le Langage C la programmation
en Langage C
 En langage C, l’écriture d’un programme se déroule en 3 étapes principales :

1. L’édition du code source

Programmer
En Langage C 2. La compilation

3. L’édition des liens


1. L’édition du code source

 Il s’agit de l’écriture du code source depuis un éditeur de texte


(Bloc Note, ou un Environnement de Développement Intégré
(EDI)) – code::blocks

 Nous opterons pour un IDE offrant toutes les commodités (outils)


nécessaires pour une bonne expérience de développeur.

Programmer
En Langage C

 http://www.codeblocks.org/downloads/26
1. L’édition du code source

 Cette étape consiste à traduire les instructions algorithmiques en


instructions C.
 Un ou plusieurs fichiers peuvent être utilisés. Dans la section
« Structuration et Organisation du code source C », nous verrons en détail
comment cela est possible.

Programmer #include <stdio.h>


int main ()

En Langage C Réflexion
Edition du code source
{
printf ("Hello World !");
return 0;
algorithmique
}

Algorithme

main.c

 Les fichiers obtenus après l’édition du code source portent l’extension .c.
2. La compilation

 Comme nous l’avons dit précédemment, en langage C, le code source peut être
découpé en un ou plusieurs fichiers source.
 Chaque fichier source est traduit en langage machine, indépendamment des autres,
par une opération dite de compilation, réalisée par un programme appelé compilateur.
 Le résultat de cette opération porte le nom de module objet (extension « .o » ou
« .obj »)

Programmer  La compilation est une opération qui se déroule en deux sous-étapes


 Une opération de prétraitement réalisé par le préprocesseur et
En Langage C  la compilation à proprement dite.
2. La compilation

A. Le prétraitement
 Cette étape consiste à modifier le texte des fichiers sources en se basant
essentiellement sur l’interprétation d’instructions très particulières dites directives à
destination du préprocesseur ;

 Ces dernières sont reconnaissables par le fait qu’elles commencent par le symbole #
(#include, #define, …)
Programmer
En Langage C
2. La compilation

A. Le prétraitement #include <stdio.h>


#define NMAX 20
avant prétraitement int main ()
{
int N [NMAX];
Renommage des printf ("Hello World !");
symboles / macros return 0;

Programmer #include
#define
}

En Langage C inclusion des fichiers h


Contenu du
.h main.c
fichier stdio.h

int main ()
Les fichiers .h (fichiers entêtes) {
contiennent les entêtes de int N [20];
fonctions des bibliothèques après prétraitement printf ("Hello World !");
return 0;
standards ou personnalisées.
}
2. La compilation

A. La compilation à proprement dite

main.c
main.o
traduction en binaire
Programmer
En Langage C modules objets
indépendants
fic1.c
fic1.o non exécutables
traduction en binaire

fic2.c
fic2.o
traduction en binaire
3. L’édition des liens

 Il s’agit d’une sorte de merge des différents modules objets et des fonctions de la
bibliothèque standard afin de constituer un programme exécutable.

Programmer main.o fic1.o fic2.o


stdio
En Langage C .h .lib
A l’issu de ces 3 étapes, en cas de succès, le
programme peut être exécuté, en le chargeant
en mémoire :

✓ autant de fois qu’on le souhaite et


✓ sans avoir à recourir à nouveau au
Programme : fichier
compilateur ni à l’environnement de
binaire exécutable et
développement.
autonome.
 Installation, préparation et découverte de l’environnement de
TP-1 développement
 Premier programme C – La compilation et les modes d’exécution de
TP-2 programmes C
La syntaxe du langage
Les types de données élémentaires du langage.
La structure d’un programme C.
Les éléments du langage : les commentaires, les identificateurs et les
mots-clés.
 Type d’une information / d’une variable
 Détermine l’espace requise pour le stockage
 Détermine la façon de coder, d’interpréter et d’exploiter l’information dans la zone
réservée

 Type d’une fonction


 Détermine la façon d’interpréter et d’exploiter sa valeur de retour

 Type simples
 L’information est, à un instant donné, caractérisée par une seule valeur

 Types agrégés
 L’information est caractérisée par un ensemble de valeurs.

Les types de données


 En théorie, la norme ANSI prévoit qu’il puisse exister six types ENTIER différents
caractérisés par deux paramètres :
 La taille de l’emplacement mémoire utilisé pour les représenter (short ou long),
 Un attribut précisant si l’on représente des nombres signés (signed), c’est-à-dire
des entiers relatifs, ou des nombres non signés (unsigned), c’est-à-dire des entiers
naturels.

 Le type _Bool a été introduit par la version C99 de la norme


 Elle représente des valeurs booléennes
 true est représenté par 1 et false par 0

 Sa définition se trouve dans le fichier entête stdbool.h


 Les constantes true et false sont définies pour respectivement valoir 1 et 0

LES ENTIERS
Les types de données
 Le tableau ci-dessous présente un récapitulatif des types ENTIER proposés par le langage
Dénomination Spécificateurs de Taille Domaine minimal
usuelle type possibles (en octets)
Booléen true 1
_Bool 1
Introduit par C99 false 0
Entier court signé short 2 -32 767 à +32 767
Entier court non signé unsigned short 2 0 à 65 535
-32 767 à +32 767 ou
Entier signé int - signed int - signed 2 ou 4
-2 147 483 647 à +2 147 483 647
Entier non signé unsigned int - unsigned 2 0 à 65 535
Entier long signé long - long int 4 -2 147 483 647 à +2 147 483 647
Entier long non signé unsigned long 4 0 à 4 294 967 295
Entier très long signé -9223372036854775808 à
long long int – long long 8
Introduit par C99 9223372036854775807
Entier très long non
unsigned long long int
signé 8 0 à 18446744073709551615
unsigned long long
Introduit par C99

LES ENTIERS
Les types de données
 Les types flottants (appelés également réels) servent à représenter de manière
approchée une partie des nombres réels.
 Les types flottants sont au nombre de trois :

Type Taille en mémoire Intervalle de valeur Précision (chiffre après la virgule)


(en octets)
float 4 1.2 E-38 à 3.4E+38 6
double 8 2.3 E-308 à 1.7 E+308 15
long double 10 3.4 E-4932 à 1.1 E+4932 19

LES FLOTTANTS
Les types de données
 Les types CARACTÈRE correspondent au mot clé char.
 La norme ANSI prévoit en fait deux types caractère différents obtenus en introduisant
dans le spécificateur de type, de façon facultative, un qualificatif de signe, à savoir signed
ou unsigned.
 Cet attribut intervient essentiellement lorsqu’on utilise un type caractère pour
représenter de petits entiers.
 Raison pour laquelle la norme définit, comme pour les types entiers, le domaine
(numérique) minimal des types caractères.

Dénomination usuelle Noms de type possibles Taille mémoire Domaine minimal


(en octets)

Caractère non signé unsigned char 1 0 à 255


char (suivant l’implémentation)

Caractère signé signed char 1 -127 à 127


char (suivant l’implémentation)

LES CARACTÈRES
Les types de données
 Les constantes ENTIÈRES
 La norme ANSI prévoit trois représentations des constantes entières :

 Décimale (base 10)


 Commence par un nombre qui n’est pas 0
 Exemple: 1981
 Octale (base 8)
 Commence par un 0
 Exemple: 015 (correspondant à 13 en base 10)
 Hexadécimale (base 16)
 Commence par 0x ou 0X
 Exemple: 0x1F, 0X2a (les symboles A, B, C, D, E, F ne sont pas sensibles à la
casse)

LES CONSTANTES
Les types de données
 Les constantes ENTIÈRES
 Par défaut, le type d’une constante entière est le premier type dans la hiérarchie
des types pouvant représenter sa valeur

 La hiérarchie se définit ainsi : int < long < unsigned long < long long

 Les constantes entières sont donc normalement de type int

 Il est néanmoins possible de préciser explicitement le type que l’on veut. Pour cela,
des suffixes spécifiques doivent être associés à la déclaration.
 Suffixe l ou L (long), ll ou LL (long long)
 Précédé ou non de u ou U (pour le cas unsigned)
 Exemple : 12UL, 80ll, 017UL, 0x81F0u

LES CONSTANTES
Les types de données
 Les constantes REELLES
 Elles sont représentées par une suite de chiffres décimaux avec un point décimal.
 Pour distinguer une constante réelle d’une constante entière, le point décimal est
nécessaire.
 Par défaut, une constante réelle est de type double
 Le suffixe L (ou l) confère le type long double, F (ou f) le type float
 Exemple :
 7.5 (constante de type double)
 .8L (constante de type long double)
 -8.09F (constante de type float)

LES CONSTANTES
Les types de données
 Les constantes CARACTÈRES
 Les caractères imprimables
 Les constantes caractère correspondant à des caractères imprimables peuvent
se noter de façon classique, en écrivant entre apostrophes (ou quotes) le
caractère voulu, comme dans ces exemples : 'a' 'y' '$' '<'

 Les caractères disposant d’une « séquence d’échappement »


 Certains caractères non imprimables possèdent une représentation
conventionnelle dite séquence d’échappement, utilisant le caractère « \ »,
nommé « antislash ».

 Dans cette catégorie, on trouve également quelques caractères qui, bien que
disposant d’un graphisme, jouent un rôle particulier de délimiteurs qui suivent
: (\n \t \f …), ce qui les empêche d’être notés de manière classique entre
deux apostrophes.

LES CONSTANTES
Les types de données
Tableau récapitulatif des caractères autorisés en C et
leur code ASCII respectif.

Les constantes caractères


 Le format du texte est libre et la mise en page est transparente pour le compilateur.
 Cela n’empêche qu’une bonne présentation du code permet une bonne lisibilité du programme et favorise une rapide
prise en main par les développeurs.

Structure d’un programme C


 Comme nous l’avions dit dans la section qui présente les trois étapes de la création d’un programme en C, le code
source peut-être contenu dans un seul fichier mais peut également réparti dans plusieurs fichiers distincts selon le
choix architectural du développeur.
 Les fichiers sources du programme peuvent donc être modifiés et compilés séparément.
 L’édition des liens est nécessaire pour la prise en compte des modifications dans le fichier exécutable final.

 Comment faire le choix de partir sur un fichier ou sur plusieurs ?


1. Pour de petits programmes (moins de 3 fonctions par exemple), il est préférable d’utiliser un modèle de code source
« tout en un » donc à un seul fichier.
2. Lorsque les programmes deviennent volumineux (prise en compte des structures de données, nombre importants
de modules élémentaires, etc. …), il apparaît plus judicieux d’opter pour un modèle de programmation modulaire à
plusieurs fichiers organisés par thématiques.
1. Modèle à un seul fichier
 Dans ce modèle toutes les fonctions du programmes sont écrites dans un et un seul fichier C comme le montre le code
ci-dessous :

Structure d’un programme C


#include <stdio.h>
#include <stdlib.h>
Fichier source unique : main.c Exécution …

// Zone de déclaration des fonctions


void sayHello();
void doSomething();
void sayGoodBye();

// Programme principal
int main()
{
sayHello();
doSomething();
sayGoodBye();
return 0;
}

// Zone de définition des fonctions déclarées plus haut


void sayHello() {
printf("Hello world !\n");
}
void doSomething() {
printf("Nothing to be done.\n");
}
void sayGoodBye() {
printf("Goodbye !\n");
system("pause");
}
2. Modèle à plusieurs fichiers
 Reprenons l’exemple de tout à l’heure et modifions-le en séparant les fonctions du programme principal. Pour cela,
nous allons créer deux autres fichiers : fonctions.h et fonctions.c
 Le fichier fonctions.h permettra de déclarer les fonctions.

Structure d’un programme C


 Le fichier fonctions.c permettra de les définir (il s’agit de l’implémentation).

 Nous conserverons le fichier main.c uniquement pour le programme principal.


fonctions.c
// Les entêtes des fonctions : #ifndef FONCTIONS_H_INCLUDED #include <stdio.h>
// sayHello(), doSomething() et sayGoodbye() #define FONCTIONS_H_INCLUDED #include <stdlib.h>
#include "fonctions.h"
// Déclaration des fonctions // Définition des fonctions
// Programme principal void sayHello(); // déclarées dans fonctions.h
int main() void doSomething(); void sayHello() {
{ void sayGoodbye(); printf("Hello world !\n");
sayHello(); }
doSomething(); #endif // FONCTIONS_H_INCLUDED
sayGoodbye(); void doSomething() {
return 0; fonctions.h printf("Nothing to be done.\n");
} }

void sayGoodbye() {
main.c printf("Goodbye.\n");
system("pause");
}
 Les blocs d’instructions
 Dans un programme C, l’ensemble des instructions est délimité par des accolades
formant ainsi des blocs.
 Chaque bloc peut contenir un sous-bloc. Ce sous-bloc est considéré comme une
instruction.

Bloc d’instructions
Sous-bloc
d’instructions

Les éléments du langage


 Les commentaires
 Les commentaires sont des éléments textuels au milieu des instructions d’un programme
et qui permettent de décrire un bout de code.
 Ils ne sont pas analysés par le compilateur et donc pas compilés. Ils aident à la
compréhension du code.
 Le langage C proposent deux types de commentaires :
/*
1- Les longs commentaires qui nécessitent
plusieurs lignes.
*/

// 2- et les commentaires qui tiennent sur une seule ligne

 Certes, il est fortement recommandé de commenter son code source au moment de


l’édition pour une meilleure documentation, néanmoins, il ne faut surtout pas en abuser
(en commentant chaque ligne d’instruction par exemple) au risque de rendre le code
source illisible.

Les éléments du langage


 Les identificateurs
 Dans un programme, de nombreux éléments (variables, fonctions, types …) sont désignés
par un nom qu’on appelle identificateur.
 Ils sont formés d’une suite de caractères choisis parmi les lettres, les chiffres ou le
caractère « souligné » ( _ ) communément appelé « underscore » ;
 Le premier caractère d’un identifiant est nécessairement différent d’un chiffre. D’ailleurs,
le compilateur vous le signalera si vous vous entêtez ☺.
 Les identificateurs sont sensibles à la casse. Cela signifie qu’une variable « toto » sera
différente d’une variable « Toto » du point de vue du compilateur.

 Voici quelques identificateurs corrects :


 _variable, Variable, variable, variable_1, _12, une__variable

Les éléments du langage


 Les mots-clés
 Les mots-clés sont des mots réservés par le langage à un usage bien défini. Ils ne
peuvent surtout pas être employés comme des identificateurs.
 La norme ANSI C99 introduit les mots-clés inline | restrict | _Bool | _Complex | et
_Imaginary

auto default float long sizeof unsigned _Imaginary


break do for restrict static void
case double goto register struct volatile
char else if return switch while
const enum inline short typedef _Bool
continue extern int signed union _Complex

 Lorsque vous utilisez un IDE pour le développement, ces mots-clés sont


automatiquement mis en évidence. C’est un des avantages des IDE ☺.

Les éléments du langage


 Les variables
 Les variables sont des zones mémoires destinées à stocker temporairement les
informations manipulées par le programme durant son exécution.
 Elles doivent toujours être déclarées avant leur première utilisation. Elles sont, la plupart
du temps, initialisées pour éviter des résultats inattendus et inexpliqués.
 La déclaration confère à la variable un type spécifique. Ce type permet :
1. De définir la nature des informations qu’elles contiendront durant l’exécution du programme.
2. De définir la taille (en octets) de la zone mémoire à allouer.

 En tant qu’identificateur, la variable se doit de respecter les règles vues précédemment sur
les identificateurs.
 Voici la syntaxe de déclaration d’une variable en langage C :
type nom_de_la_variable;
 Notez la présence obligatoire du caractère « ; » qui marque la fin de toute instruction en C.

Les éléments du langage


 Les constantes
 Les constantes sont utilisées pour définir des valeurs qui n’évolueront pas durant
l’exécution du programme.
 Les constantes peuvent être définies en C de deux manières différentes :
1. En utilisant le mot clé const
 Comme c’est le cas pour une variable, la constante occupera une zone mémoire qui lui sera
allouée.
 Par contre, une fois initialisée, cette zone mémoire ne pourra plus être modifiée durant
l’exécution du programme.
 Exemple : const type une_constante_entiere = 10;

2. En utilisant la directive #define


 Aucune zone mémoire n’est allouée. Il s’agit tout simplement de la définition d’un symbole qui
sera substitué par sa valeur lors de la phase de prétraitement (opération réalisée durant la
compilation par le préprocesseur).
 Exemple : #define TAILLE_MAX 20

Les éléments du langage


Les instructions
d’entrées/sorties
La bibliothèque <stdio.h>
La fonction printf
La fonction scanf
 Les programmes ont la plupart du temps besoin d’informations en entrée pour
influencer leur comportement.
 Ils fournissent en retour des informations de sortie pour rendre compte de leur activité à
l’issu du traitement.

1011
0110
1011

Programme en
exécution
Les données en entrée Les résultats en sortie

 La bibliothèque <stdio.h> propose une énorme quantité de fonctions permettant de


réaliser les opérations d’entrées/sorties dans un programme C.
 Ces opérations permettent l’échange d’informations entre le programme et le monde
extérieur.

Généralités

Les instructions d’entrées/sorties


 Comme la plupart des fonctions du même type, la fonction printf est déclarée dans le
fichier <stdio.h>.
 Son utilisation dans un code C requiert la directive #include <stdio.h>
 Cette fonction prend comme paramètre :
 une chaîne de caractère représentant le format de l’information à afficher et
 Une liste d’arguments facultatifs, en nombre variable.

 La ligne déclarative de la fonction (encore appelée signature, entête ou prototype) est la


suivante :
 int printf ( const char * format [ , argument, … ] ) ;
 format : représente la chaîne de caractères à écrire sur la sortie standard (l’écran de
l’ordinateur)
 argument : l’argument représente les éléments (expressions, variables, …) utilisés pour
construire la chaîne de caractères

 Elle retourne une valeur de type int égale au nombre de caractères écrits sur la sortie
standard ou -1 en cas de problème. Cette information est très rarement exploitée.
La fonction printf

Les instructions d’entrées/sorties


 L’utilisation de la fonction printf peut se faire sans paramètres ou avec des paramètres
additionnels (les arguments variables).

 Voici un premier exemple de l’utilisation de la fonction où l’on affiche une simple chaîne
de caractère : Hello World!, sans paramètres additionnels :

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

int main()
{
printf("Hello World!");

system("pause");
return 0;
}

La fonction printf

Les instructions d’entrées/sorties


 Lorsque des paramètres additionnels sont à afficher, le formatage de la chaîne de
caractères à afficher devient nécessaire.
 En effet, pour afficher les informations additionnelles, il faut spécifier leur format, c’est-
à-dire qu’il faut préciser comment elles seront présentées à l’écran.
 Plusieurs formats d’affichage sont possibles pour une même donnée.
 Par exemple, un entier peut-être affiché sous le format décimal, octal ou même hexadécimal.
Un caractère peut être affiché sous sa forme naturelle ou sous sa forme numérique (définie
par son code ASCII), etc.

 Les éléments du langage permettant de définir ces différents formats sont appelés
spécificateurs de format. Les plus utilisés sont présentés dans le tableau ci-dessous :

Spécificateur Utilité Spécificateur Utilité


%d %i Format des int %f Format des float
%ld %li Format des long %lf Format des double
%o Format octal %c Format char
%x %X Format Hexadécimal %s Format chaîne de caractère
La fonction printf

Les instructions d’entrées/sorties


 Le programme ci-dessous affiche un caractère sous sa forme naturelle et sous sa forme
numérique.

#include <stdio.h>
#include <stdlib.h> spécificateur de
format
int main() caractère
{
char a = 'a';
printf("Le code ascii de '%c' est '%d'\n", a, a);

system("pause");
return 0;
spécificateur
}
de format
entier

Exécution …

La fonction printf

Les instructions d’entrées/sorties


 Comme la fonction printf vue précédemment, la fonction scanf est également
déclarée dans le fichier <stdio.h>.
 Son utilisation dans un code C requiert la directive #include <stdio.h>
 Elle prend comme paramètre :
 une chaîne de caractère représentant le format de l’information à lire et
 Une liste d’arguments obligatoires (contrairement à la fonction printf), en nombre
variable.

 La signature de la fonction est la suivante :


 int scanf ( const char * format [ , argument, … ] ) ;
 format : représente la chaîne de caractères à lire à partir de l’entrée standard (le
clavier de l’ordinateur)
 argument : l’argument représente les éléments (adresses de variables) où stocker les
données lues.

 Elle retourne une valeur de type int égale au nombre d’informations correctement
interprétées lors de la saisie (après avoir validé la saisie avec la touche « entrée ») ou -1
en cas de problème.
La fonction scanf

Les instructions d’entrées/sorties


 Le programme ci-dessous lit au clavier un entier fourni par l’utilisateur puis affiche le
code d’erreur retourné par la fonction scanf.

#include <stdio.h> Exécution … donnée saisie correcte.


#include <stdlib.h>

int main()
{
int n, errorCode;

printf("Enter an Integer : ");


errorCode = scanf("%d", &n);

spécificateur de Adresse de n où Exécution … donnée saisie incorrecte.


format entier stocker l’entier lu.

printf("ErrorCode = %d.\n", errorCode);

system("pause");
return 0;
}

La fonction scanf

Les instructions d’entrées/sorties


 Le tableau ci-dessous présente quelques fonctions utilises de la bibliothèque
<stdio.h>

Fonction Prototypes et Exemples Description


int putchar (int car) ;
putchar
int c = 'A';
Ecrit sur stdout le caractère c
putchar (c);
int getchar (void) ;
getchar
int c ;
Lit à partir de stdin un caractère
c = getchar ();
int puts(const char *str) ;
Ecriture d’une chaîne de caractères terminée par \n
puts
puts ("Bonjour") ; sur stdout
char * gets(char * str) ;
gets
char mot [21] ;
Lecture d’une chaîne de caractère depuis stdin
gets (mot) ;

La librairie <stdio.h>

Les instructions d’entrées/sorties


 Découverte de la syntaxe du langage, sa structure de base et utilisation
TP-3 des fonctions d’entrée/sortie de la bibliothèque <stdio.h>
Les expressions
Les opérateurs
Le transtypage
 Une expression est une combinaison d’un opérateur et d’une ou deux données.
 Le résultat de l’évaluation d’une expression peut devenir une opérande pour une
expression englobante.
 Exemple :
 Considérons l’expression suivante : b + 10 (expression_1)
 expression_1 devient ici une opérande dans expression_2 : a = b + 10

 Toute expression peut devenir une instruction en la faisant suivre d’un point virgule « ; »

 Nous verrons plus loin que l’invocation d’une fonction peut dans certains cas devenir
une opérande pour une expression plus englobante.
 Voyons un petit exemple en attendant : y = 1 + f(x);
 Le retour de la fonction f devient une opérande pour l’expression 1 + f(x).

Les expressions

Les expressions
 Le langage C propose plusieurs types d’opérateurs dédiés à la réalisation de calculs
élémentaires. Il existe deux grandes familles :
 Les opérateurs arithmétiques
 Dans cette catégorie, on trouve les opérateurs arithmétiques classiques tels que :
 L’addition : « + », la soustraction : « - », la multiplication : « * », la division entière « / » et le
modulo « % »
 Les opérateurs arithmétiques combinés tels que :
 « += », « -= », « *= », « /= », « %= », …

 Les opérateurs arithmétiques d’incrémentation et de décrémentation : « ++ », « -- »


 Les opérateurs binaires de décalage de bits : « << », « >> »

 Les opérateurs logiques


 Dans cette catégorie, on trouve les opérateurs logiques usuels tels que : « && », «||», «!»
 Les opérateurs logiques relationnelles tels que :
 « > », « >= », « < », « <= », « == », « != »,
 Les opérateurs logiques binaires tels que : « ~ », «|», « & », « ^ »
Les opérateurs

Les opérateurs
 Ces opérateurs permettent de réaliser des opérations arithmétiques portent sur deux
opérandes de mêmes types.
 Si les opérandes ne sont pas de même type une conversion implicite est réalisée
automatiquement. Le développeur a la possibilité également de faire une conversion
explicite (appelée transtypage) pour garantir la compatibilité des types entre les
opérandes.
1. « + » réalise l’addition de deux numériques
2. « - » réalise la soustraction de deux numériques
3. « * » réalise la multiplication de deux numériques
4. « / » réalise , la division entière de deux numériques. Si les deux opérandes sont des entiers, le
résultat est un entier. Ainsi, l’opération « 1 / 3 » produira comme résultat « 0 » au lieu de
« 0.333 ».
5. « % » réalise le modulo de deux entiers.

Les opérateurs
arithmétiques classiques
Les opérateurs arithmétiques
 Le code ci-dessous présente le mécanisme de conversion implicite tel que présenté
précédemment :
int main()
{
int a = 10;
long b = 20;

double c = a * b;
/*
double c = a (int) * b (long)
1- le contenu de la variable 'a' est converti en long
double c = a (long) * b (long)
2- l'opération peut être réalisée car
portant sur deux long. Elle fournit comme résultat 200 (long)
double c = 200
3- le résultat est converti en double pour être compatible avec
la variable 'c' de type double
*/
return 0;
}

Les opérateurs
arithmétiques classiques
Les opérateurs arithmétiques
 La différence entre la conversion implicite et explicite (transtypage) est présenté par le
tableau ci-dessous :
 L’opérateur qui réalise ce transtypage est appelé opérateur de cast.

Conversion implicite Conversion explicite (cast)


int a = 8 ; (typeSouhaité) donnée
long b = a ;
int a = 8 ;
Conversion automatique de a long b = (long) a ;
(int vers long)

Les opérateurs
arithmétiques classiques
Les opérateurs arithmétiques
 Le code ci-dessous présente le mécanisme de conversion explicite (transtypage) tel que
présenté précédemment :
int main()
{
int a = 10;
long b = 20;

double c = (double)a * (double)b;


/*
double c = a (double) * b (double)
1- le contenu de la variable 'a' est converti en double directement
2- l'opération peut être réalisée car
portant sur deux double. Elle fournit comme résultat 200.000000 (double)
double c = 200.000000

Aucune conversion n’est nécessaire à l’issu du calcul.


Le résultat est du type de la variable 'c'.
*/
return 0;
}

Les opérateurs
arithmétiques classiques
Les opérateurs arithmétiques
 Les opérateurs combinés permettent le compactage de certaines instructions
arithmétiques :
 Ci-dessous la formule :
 operande_1 operateur= operande_2 ;

 Cette formule est la forme compactée de l’instruction :


 operande_1 = operande_1 operateur operande_2 ;

 Le code ci-dessous montre un exemple d’utilisation :


#include <stdio.h>
int main()
{
int var = 10;

var += 1; // est équivalent à : var = var + 1 ;


var %= 2; // est équivalent à : var = var % 2 ;
var -= 8; // est équivalent à : var = var – 8 ;

return 0;
}
Les opérateurs
arithmétiques combinés
Les opérateurs arithmétiques
 Ces opérateurs permettent de modifier la valeur d’une opérande en augmentant sa
valeur de 1 (incrémentation) ou en la réduisant de 1 (décrémentation)

Opérateur Opération
++ ➔ Incrémentation

-- ➔ Décrémentation

 Ils peuvent être utilisés selon deux manières différentes :

1. La première approche consiste à positionner l’opérateur à gauche ou à droite de


l’opérande tout simplement, ce qui a pour effet d’agir sur cette opérande uniquement.
 Exemple : « a ++ ; » est équivalent à « ++ a; » mais aussi à « a = a + 1; » ou
encore « a += 1; »

Les opérateurs d’ incrémentation


et de décrémentation
Les opérateurs arithmétiques
2. La seconde approche consiste à utiliser l’opérateur dans une opération d’affectation :
 Le code suivant présente quelques exemples d’implémentation de cette seconde
approche et ces conséquences sur les variables mises en jeu :

L’opérateur j++ est placé après l’opérande. L’opérateur ++j est placé avant l’opérande.
int main() int main()
{ {
int i = 1; int i = 1;
int j = 2; int j = 2;
i = j++; // i=2 et j=3 i = ++j; // i=3 et j=3
/* /*
Deux opérations sont réalisées, Deux opérations sont réalisées,
dans cet ordre : dans cet ordre :

D’abord D’abord
i = j; => i vaut 2 j = j + 1; => j vaut 3

Ensuite ... Ensuite ...


j = j + 1; => j vaut 3 i = j; => i vaut 3
*/ */
return 0; return 0;
Les opérateurs d’ incrémentation } }

et de décrémentation
Les opérateurs arithmétiques
 Les opérateurs binaires de décalage de bits modifient la valeur d’un élément en décalant
les bits qui le constituent vers la gauche ou vers la droite.

Opérateur Exemples
char a = 10;
char b = a << 2;

a 0 0 0 0 1 0 1 0
a << 1 0 0 0 1 0 1 0 0
<<
Décalage de bits à a << 2 0 0 1 0 1 0 0 0
gauche
hexadécimal 2 8
décimal 0x28 = 2 x 161 + 8 x 160 = 40
b = 40
Les opérateurs binaires de
décalage de bits
Les opérateurs arithmétiques
 Les opérateurs binaires de décalage de bits modifient la valeur d’un élément en décalant
les bits qui le constituent vers la gauche ou vers la droite.

Opérateur Exemples
char a = 10;
char b = a >> 2;

a 0 0 0 0 1 0 1 0
a >> 1 0 0 0 0 0 1 0 1
>>
Décalage de bits à a >> 2 0 0 0 0 0 0 1 0
droite
hexadécimal 0 2
Remarquez les
décimal 0x02 = 0 x 161 + 2 x 160 = 2
pertes de données !!
b=2
Les opérateurs binaires de
décalage de bits
Les opérateurs arithmétiques
 Les opérateurs logiques servent à combiner des expressions logiques (dont la valeur peut
être soit true, soit false) par des opérateurs logiques usuels de type et, ou et de
négation.

 Les opérateurs de comparaison (<, <=, >, >=, ==, !=, …) fournissent une valeur
entière, ce qui impose aux opérandes des opérateurs logiques d’être de type entier.

 Plutôt que de restreindre leur valeur à 0 (false) et 1 (true), les concepteurs du langage ont
préféré donner une signification aux opérateurs logiques dans tous les cas,

 Seul 0 correspond à « false », tandis que toute autre valeur correspond à « true ».

Les opérateurs logiques

Les opérateurs logiques


 Le code ci-dessous présente une illustration :

#include <stdio.h> Exécution …


#include <stdlib.h>

int main()
{
int a = 5;
int b = 10;
int p = a >= b;
/*
Le résultat de l'évaluation de a >= b donne : false ce qui correspond à 0
p reçoit donc la valeur 0
*/
printf("Contenu de p = '%d'.\n", p);
system("pause");

return 0;
}

Les opérateurs logiques

Les opérateurs logiques


 Ci-dessous une présentation des opérateurs logiques usuels

Contraintes
Opérateur Signification et résultat Remarques
opérandes
Négation logique de op :
! op
1 si op nul, 0 sinon
Et logique de op1 et op2 : && n’évalue son
Scalaire
op1 && op2 1 si op1 et op2 tous deux non deuxième opérande
(numérique ou
nuls, 0 sinon que si nécessaire.
pointeur)
Ou logique de op1 et op2 : || n’évalue son
op1 || op2 0 si op1 ou op2 tous deux nuls, deuxième opérande
1 sinon que si nécessaire.

Les opérateurs logiques


usuels
Les opérateurs logiques
 Les opérateurs logiques binaires permettent de faire des comparaison bit à bit.
 Ils sont au nombre de quatre et sont présentés dans le tableau ci-dessous :

Opérateur Opération
&  Et logique
|  Ou Logique
^  Ou exclusif logique
~  Négation logique

Les opérateurs logiques


binaires
Les opérateurs logiques
 L’opérateur binaire « Et logique » (&)

Opérateur Exemples
char a = 5;
char b = 6;
char c = a & b;
&
Et logique 0101 (a = 5)
& 0110 (b = 6)
------
0100 (c = 4)

Les opérateurs logiques


binaires
Les opérateurs logiques
 L’opérateur binaire « Ou logique » (|)

Opérateur Exemples
char a = 5;
char b = 6;
char c = a | b;
|
Ou logique 0101 (a = 5)
| 0110 (b = 6)
------
0111 (c = 7)

Les opérateurs logiques


binaires
Les opérateurs logiques
 L’opérateur binaire « Ou exclusif logique » (^)

Opérateur Exemples
char a = 5;
char b = 6;
char c = a ^ b;
^
Ou exclusif logique 0101 (a = 5)
^ 0110 (b = 6)
------
0011 (c = 3)

Les opérateurs logiques


binaires
Les opérateurs logiques
 L’opérateur binaire « Négation logique » (~)

Opérateur Exemples
char a = ~5;
~ ~ 0101 (~5)
Négation logique ------
1010 (a = 10)

Les opérateurs logiques


binaires
Les opérateurs logiques
 A la découverte des opérateurs arithmétiques usuels, relationnelles,
TP-4 combinés, d’incrémentation et de décrémentation, logiques et binaires ...
Les structures
de contrôle
Les branchements : if … else, switch
Les itérations : while, do … while, for
Les branchements
if …else
switch
 C’est une structure dite de choix (ou de sélection ou alternative)

Les deux formes de l’instruction if


if (expression) if (expression)
instruction_1 instruction_1
else
instruction_2
expression expression quelconque de type scalaire (numérique ou pointeur)

instruction_1 ou instruction_2 instruction exécutable quelconque, c’est-à-dire simple, structurée ou bloc

❖ Mode de fonctionnement
DEBUT

FIN

La structure if … else

Les branchements
#include <stdio.h>

int main()
{
int var;

printf("Enter an Integer : ");


scanf("%d", &var);

if (var < 8)
{ // Dans cette section le premier test est vérifié
printf("%d < 8.\n", var);
}
else if (var > 8)
{ // Dans cette section,
// le premier test n'est pas vérifié et le second l'est.
printf("%d > 8.\n", var);
}
else
{ // Dans cette section,
Exemple d’utilisation // Les deux précédents tests ne sont pas vérifiés.
printf("%d == 8.\n", var);
}

return 0;
}
La structure if … else

Les branchements
 Comme son nom l’indique, il s’agit d’un opérateur et non d’une structure conditionnelle.
 Il est utilisé pour des instructions simples et peut remplacer la structure if … else.

(expression) ? valeur si vraie : valeur si fausse ;


#include <stdio.h>
#include <stdio.h>
int main()
int main()
{
{
int a, b;
int a, b, max;
printf("Enter two Integer : ");
printf("Enter two Integer : ");
scanf("%d %d", &a, &b);
scanf("%d %d", &a, &b);
printf("Max = %d.\n", (a > b) ? a : b);
max = (a > b) ? a : b;
// Si a > b, l’opérateur renvoie a, sinon b
return 0;
// Cette valeur est affectée à max.
}
printf("Max = %d.\n", max);

return 0;
}

L’opérateur conditionnel « ? »

Les branchements
 C’est une structure dite de choix multiple (ou de sélection multiple)

Les deux formes de l’instruction if


switch (expression) N.B : Les crochets [ … ] signifient que leur contenu
{ est facultatif.
case constante_1 : [ instruction_1 ]
case constante_2 : [ instruction_2 ]

[ default : instruction_3 ]
}
expression Une expression qui lorsqu’elle évaluée fournit un
résultat de type entier (char, short, int ou long)
signé ou non.
constante_i une constante entière qui détermine sur quelle
instruction se brancher
instruction_i séquence d’instructions quelconques

La structure switch

Les branchements
❖ Mode de fonctionnement
switch (expression)
{
case constante_1: instruction_1; break;
case constante_2: instruction_2;
default: instruction_3;
}

DEBUT FIN

La structure switch

Les branchements
#include <stdio.h>

int main()
{
int n;

printf("Enter a rate : ");


scanf("%d", &n);

switch (n)
{
case 1: printf("Not meeting objective.\n"); break;
case 2:
case 3: printf("Almost meets objective.\n"); break;
case 4: printf("Fully meets objective.\n"); break;
case 5:
case 6: printf("Exceeds objective.\n"); break;
case 7: printf("Significantly exceeds objective.\n"); break;
default: printf("unrated.\n");
}
Exemple d’utilisation
return 0;
}

La structure switch

Les branchements
Les itérations
do … while
while
for
 Cette structure réalise la boucle FAIRE TANTQUE algorithmique.
 Néanmoins, la richesse de la notion d’expression en C peu amener à la dénaturer
quelque peu.

L’instruction do … while ❖ Mode de fonctionnement


do DEBUT
instruction
while (expression) ;
instruction quelconque : simple,
instruction
structurée ou bloc
expression quelconque de type
scalaire (numérique ou pointeur)
expression nommée parfois « expression de
contrôle de la boucle » ou condition
de poursuite.

La structure do … while

Les itérations FIN


#include <stdio.h>

int main()
{
int n;

do
{
// Ce bloc d'instruction est exécuté au moins une fois.
printf("Enter an Integer (> 0) : ");
scanf("%d", &n);
} while (n <= 0); // Condition testée à chaque fin de tour.

// Sortie de boucle, la condition n'est pas vérifiée.


printf("R%cponse correcte.\n", 130);

return 0;
}

Exemple d’utilisation

La structure do … while

Les itérations
 Cette structure réalise la boucle TANTQUE FAIRE algorithmique.
 Néanmoins, la richesse de la notion d’expression en C peu amener à la dénaturer
quelque peu. Contrairement à ce qui se passe pour do … while, la syntaxe n’impose ici
aucun point-virgule.

L’instruction while ❖ Mode de fonctionnement

while (expression) DEBUT

instruction

instruction quelconque : simple,


instruction
structurée ou bloc
expression quelconque de type
scalaire (numérique ou pointeur)
expression nommée parfois « expression de
contrôle de la boucle » ou condition
de poursuite.

La structure while

Les itérations FIN


#include <stdio.h>
#define PAS 3

int main()
{
int i;

printf("Les multiples de 3 inf%crieurs %c 30 sont : ", 130, 133);

i = 0;
while (i < 30) // Condition testée avant la première entrée dans la boucle.
{
printf("%d\t", i);

i += PAS;
}

// Sortie de boucle, la condition n'est plus vérifiée.


return 0;
}
Exemple d’utilisation

La structure while

Les itérations
 Cette structure est assimilée à tord à la structure POUR algorithmique.
 En effet, POUR et for ne sont pas équivalents. La structure for va bien au-delà des
possibilité de la structure POUR algorithmique.

L’instruction for
for ( [expression_1] ; [expression_2] ; [expression_3] )
instruction

N.B : Les crochets [ … ] signifient que leur contenu est facultatif.


instruction Une instruction quelconque : simple, structurée ou bloc

expression_1 et Des expressions de type quelconque pas nécessairement scalaire ici.


expression_3
expression_2 Une expression de type scalaire si cette expression est omise, tout se
(numérique ou pointeur) passe comme si elle avait pour valeur 1
(vraie)

La structure for

Les itérations
DEBUT

FIN

Mode de fonctionnement

La structure for

Les itérations
#include <stdio.h>
#define PAS 3

int main()
{
int i;

printf("Les multiples de 3 inf%crieurs %c 30 sont : ", 130, 133);

for(i = 0; i < 30 ; i += PAS)


{
printf("%d\t", i);
}

// Sortie de boucle, la condition n'est plus vérifiée.


return 0;
}

Exemple d’utilisation

La structure for

Les itérations
 L’instruction for est une instruction while qui s’ignore.
 D’ailleurs, comme le précise formellement la norme ANSI,

 L’instruction :
for ( expression_1 ; expression_2 ; expression_3 )
instruction

 est équivalente, en l’absence de branchements (goto, break, continue) dans l’instruction, à :

expression_1 ;
while ( expression_2 )
{
instruction
expression_3 ;
}
Lien entre for et while

Les itérations
 L’instruction break est couramment utilisée avec l’instruction switch. Elle permet
également de provoquer la fin prématurée d’une boucle (for, while ou do … while).

 En cas d’imbrication d’instructions de boucles ou d’instructions switch, break ne met fin


qu’à l’instruction la plus interne le contenant.

 On notera que l’instruction structurée if n’est pas concernée par break.

L’instruction break

Les itérations
#include <stdio.h>

int main()
{
int i, j = 0;

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


{
printf("i = %d et j = %d\n", i, j);

if (j == 4)
{
// On quitte la boucle
break;
}

j++;
}

return 0;
Exemple d’utilisation }

L’instruction break

Les itérations
DEBUT

Mode de fonctionnement

FIN
L’instruction break

Les itérations
 Alors que break permet de mettre fin prématurément à une boucle, continue permet de
forcer le passage au tour suivant.

 Cette instruction ne s’utilise que dans une boucle et son exécution force simplement le
passage au tour suivant, en ignorant les instructions situées entre continue et la fin de la
boucle.

 Elle ne concerne que la boucle de niveau le plus interne la contenant.

L’instruction continue

Les itérations
#include <stdio.h>

int main()
{
int i, j = 0;

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


{
printf("i = %d et j = %d\n", i, j);

if (j == 4)
{
// Force le passage au tour suivant
continue;
}

// Cette instruction ne sera pas


// exécutée
j++;
}
Exemple d’utilisation
return 0;
}

L’instruction continue

Les itérations
DEBUT

Mode de fonctionnement
FIN

L’instruction continue

Les itérations
 A la découverte des structures de contrôle if else, switch, do while, while
TP-5 et for ...
Les tableaux, les pointeurs et les chaînes de caractères
La bibliothèque <string.h>
 Un tableau est un ensemble d’éléments de même type désignés par un identificateur
unique.
 Chaque élément est repéré par un indice précisant sa position au sein de l’ensemble.
 Un tableau occupe une zone de mémoire continue (non fragmentée), les éléments y sont
juxtaposées.
 L’espace mémoire occupé par un tableau est égale à sa taille (nombre d’éléments)
multipliée par l’espace allouable pour le type des éléments.
 La taille du tableau est connue obligatoirement lors de sa déclaration.
 Un tableau peut être initialisé dès sa déclaration.

 On distingue deux types de tableaux :


1. Les tableaux unidimensionnels
2. Les tableaux multidimensionnels

Les tableaux
 La syntaxe de déclaration d’un tableau unidimensionnel est la suivante :
 type_elements nom_tableau [nombre_elements] ;

 Exemple : int tab [10];

 Définition d’un tableau de type int de taille 10 (correspondant au nombre


d’éléments)

 On peut accéder à la première composante du tableau par tab[0], à la deuxième par


tab[1],..., à la dernière par tab[9].

La déclaration

Tableaux unidimensionnels

Les tableaux
 Lors de la déclaration d'un tableau, on peut initialiser ses composantes en indiquant la
liste des valeurs respectives entre accolades.
 Le nombre de valeurs dans la liste doit corresponde à la taille du tableau (précisée entre
crochets).
 Si la liste ne contient pas assez de valeurs pour toutes les composantes, les composantes
restantes sont initialisées à 0.

Exemples Représentation en mémoire


int A[4] = { 10, 7, 9, -1 } ; 10 7 9 -1

float B[4] = { 3.50, 7.00 } ; 3.50 7.00 0 0

L’initialisation

Tableaux unidimensionnels

Les tableaux
 Si la dimension du tableau n'est pas indiquée explicitement lors de l'initialisation, alors
l'ordinateur réserve automatiquement le nombre d'octets nécessaires.
 Ci-dessous un exemple de réservation de 5 x sizeof ( int ) octets (dans notre cas : 20
octets), déterminée automatiquement par le compilateur …

Exemples
int A [ ] = { 10, 20, 30, 40, 50 } ;

Rien entre les crochets

La réservation automatique

Tableaux unidimensionnels

Les tableaux
 Représentation d’un tableau unidimensionnel vue du développeur

Tableaux unidimensionnels

Les tableaux
 Représentation d’un tableau bidimensionnel vue du développeur

Tableaux
multidimensionnels
Les tableaux
 Représentation d’un tableau tridimensionnel vue du développeur

Tableaux
multidimensionnels
Les tableaux
 Un tableau est en réalité un vecteur de données de même type qui vont être placés les
unes à côté des autres en mémoire.
 Un tableau à 2 dimensions est donc un vecteur de vecteurs de données de même type qui
vont être placés les uns à côtés des autres en mémoire.

Organisation
physique
Organisation
logique

 Pour les tableaux multidimensionnels, nous nous limiterons aux tableaux bidimensionnels
dans le cadre de ce cours.
Tableaux
multidimensionnels
Les tableaux
 La syntaxe de déclaration d’un tableau bidimensionnel est la suivante :
 type_elements nom_tableau [nombre_lignes] [nombre_colonnes] ;

 Exemple : int tab[4][6];

 Définition d’un tableau de type int de taille 4 x 6 (correspondant au nombre


d’éléments (6 éléments par ligne sur 4 lignes)

 On peut accéder à la première composante de la première ligne par tab [0][0], à la


deuxième par tab[0][1], et ainsi de suite …

La déclaration

Tableaux bidimensionnels

Les tableaux
 Tout comme les tableaux unidimensionnels, il est possible, lors de la déclaration,
d’initialiser les composantes d’un tableau bidimensionnel en précisant les éléments de
chaque ligne entre accolades.

Exemples Représentation logique

int tab [4][6] = { 1 0 0 0 0 0


{1},
{1, 1}, 1 1 0 0 0 0
{1, 1, 1},
{1, 1, 1, 1} 1 1 1 0 0 0
};
1 1 1 1 0 0

organisation
physique
1 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0
L’initialisation

Tableaux bidimensionnels

Les tableaux
 Lorsque le nombre de lignes n’est pas indiquée explicitement lors de l'initialisation, alors
l'ordinateur réserve automatiquement le nombre d'octets nécessaires.
 L’exemple ci-dessous prévoit une réservation de 4 x 6 x sizeof ( int ) octets (soit 96 octets ),
déterminée automatiquement par le compilateur …

Exemples
int tab [4][6] = {
{1},
{1, 1},
{1, 1, 1},
{1, 1, 1, 1}
};

La réservation automatique

Tableaux bidimensionnels

Les tableaux
 Important !
 Il n’existe aucun contrôle sur l’indice

 Si vous déclarez un tableau de taille 5 et que vous tenter d’initialiser 10


éléments, votre programme écrit en dehors du tableau => overflow !
 Ecrasement possible des valeurs d’autres variables

Valeur supérieure à la taille


configurée
Dépassement de mémoire

Les tableaux
 Lorsque l’on déclare une variable, par exemple un entier i, l’ordinateur réserve un espace
mémoire pour y stocker les valeurs de i.

 L’emplacement de cet espace dans la mémoire est nommé adresse.

 Un pointeur est tout simplement une variable spéciale qui permet de stocker l’adresse
d’une autre variable.

 Par exemple :

Les pointeurs
 Si un pointeur P contient l'adresse d'une variable A alors « P pointe sur A ».

 Les pointeurs et les noms de variables ont le même rôle :


 Ils donnent accès à un emplacement dans la mémoire interne de l'ordinateur
1. Un pointeur est une variable qui peut 'pointer' sur différentes adresses.
2. Le nom d'une variable reste toujours lié à la même adresse.

 La manipulation des pointeurs en C requiert :


 L’opérateur & dit « adresse de » dont le rôle est de fournir l’adresse d’une variable
 &nom_de_variable va donc fournir l’adresse de la variable nom_de_variable

 L’opérateur * dit « contenu de » dont le rôle est de fournir le contenu d’une zone mémoire
 *nom_de_pointeur va donc fournir le contenu de la zone référencée par (ou pointée par)
le pointeur nom_de_pointeur

Les pointeurs
 La syntaxe de déclaration d’un pointeur est la suivante :
 type * nom_de_pointeur ;

 Elle permet de déclarer un pointeur nom_de_pointeur qui peut recevoir des adresses
de variables du type type.

 Exemple : int* ptr;

 ptr est du type int*


 ptr est un pointeur sur des variables du type int
 ptr peut contenir des adresses de variables du type int
La déclaration

Les pointeurs
 Important !

 Lors de la déclaration d'un pointeur en C, ce dernier est lié explicitement


à un type de données.
 Ainsi, la variable ptr déclarée comme pointeur sur int ne doit pas
recevoir l'adresse d'une variable d'un autre type que int !!

Les pointeurs
 Le lien entre les tableaux et les pointeurs peut se résumer en une phrase :
 « Le nom d'un tableau est un pointeur constant sur le premier élément de ce tableau. »
 En d’autres termes, si nous considérons les déclarations suivante :
int tableau[10];
int* ptr;

 &tableau [0] et tableau sont une seule et même adresse (l’adresse du premier élément du
tableau)
 L’instruction « ptr = tableau ; » est équivalente à « ptr = &tableau [0] ; »
 Si un pointeur p pointe sur un élément quelconque du tableau, alors p + 1 pointe sur
l’élément suivant et p - 1 sur le précédent. De façon plus générale :
 p + i pointe sur le i-ième élément devant p
 p - i pointe sur le i-ième élément derrière p

Lien entre tableaux et pointeurs


 Il n'existe pas de type spécial chaîne ou string en C.

 Une chaîne de caractères est traitée comme un tableau à une dimension de caractères.

 Il existe quand même des notations particulières et une bonne quantité de fonctions
spécialisées dans le traitement des chaînes de caractères. Elles sont définies dans la
bibliothèque <string.h>.

 Déclaration d’une chaîne de caractères en C.


 char nom_chaine [longueur] ;

 Exemple : char nom[20];

Les chaînes de caractères


 Comme pour tout tableau, lors de la déclaration d’un tableau de caractères, il nous faut
indiquer l’espace à réserver pour le stockage des caractères constituant la chaîne.
 La représentation interne d'une chaîne de caractères est terminée par le symbole '\0' .
Ainsi, pour une chaîne de N caractères, nous devons prévoir N+1 octets.
 Exemple : char texte[10] = "BONJOUR !";
char texte[10] = { 'B','O','N','J','O','U','R',' ','!','\0' };

 Pour la mémorisation de la chaîne de caractères "BONJOUR !", le système a besoin de


dix octets.
 'a' est un caractère constant codé sur 1 octet, qui a la valeur numérique 97 correspondant
Espace à réserver
à son code ASCII.
 "a" est un tableau de caractères qui contient deux caractères : 0 1

 La lettre 'a' et le caractère de fin de chaîne : '\0' 'a' '\0'

Les chaînes de caractères


 La bibliothèque <string.h> est dédiée à la manipulation des chaînes de caractères …
 Ci-dessous quelques fonctions fréquemment utilisées :

Prototype fonction Description


Concatène deux chaînes de caractères
char* strcat(char* dest, const char* src); (dest et src).
Le résultat est mis dans dest.

char* strchr(const char* str, int c); Recherche la première occurrence du


caractère c dans la chaine str.
int strcmp(const char* str1, const char* str2); Compare les chaînes str1 et str2

char* strcpy(char* dest, const char* src); Copie la chaîne src dans dest.

size_t strlen(const char* str); Retourne la taille de la chaîne str

La bibliothèque <string.h>

Les chaînes de caractères


TP-6  A la découverte des chaînes de caractères et de la bibliothèque <string.h>
Les fonctions
Le passage par valeur – Le passage par adresse
 Un code source écrit en un seul bloc (en seule partie) est difficile à comprendre dès qu’il devient
assez volumineux.

 Le langage C permet le découpage du code source d’un programme en plusieurs unités de


traitement appelés « fonctions ».

 Chacune de ces unités de traitement est dédiée à la réalisation d’une tâche précise.

 Le découpage en modules plus élémentaires :

 Evite les séquences d’instructions répétitives


 Partage d’outils communs qu’il suffit d’avoir écrits et mis au point une seule fois
 Favorise le travail collaboratif

 Le point d’entrée dans un programme C est lui-même une fonction : main(…)


Généralités

Les fonctions
typeDeRetour nomDeLafonction (typeArg_1 arg_1, …, typeArg_i arg_i, …)
{
// Déclarations des variables locales

// instructions à exécuter
}

 Les procédures telles qu’on les connaît en algorithmique n’existe pas en langage C. Néanmoins
une procédure algorithmique sera traduite en C par une fonction qui « retourne rien .»
 En C, rien est une information de type « void » et une instruction qui ne fait rien peut être
représentée tout simplement par un « ; »

void nomDeLaProcedure (typeArg_1 arg_1, …, typeArg_i arg_i, …)


{
// Déclarations des variables locales

// instructions à exécuter
}
Anatomie d’une fonction en C

Les fonctions
// Le minimum entre deux réels peut // ou encore ainsi …
être déterminé basiquement ainsi … float minimum(float arg1, float arg2)
float minimum(float arg1, float arg2) {
{ if (arg1 < arg2) return arg1;
float min; else return arg2;
}
if (arg1 < arg2) min = arg1;
else min = arg2;

return min;
}

// ou encore plus simplement à l’aide de l’opérateur ternaire


float minimum(float arg1, float arg2)
{
return (arg1 < arg2) ? arg1 : arg2;
}

Exemples de fonctions

Les fonctions
void sayHello(char gender, char * nom, char * prenom)
{
switch (gender)
{
case 'f':
case 'F': printf("Bonjour Madame %s %s.\n", nom, prenom); break;

case 'h':
case 'H': printf("Bonjour Monsieur %s %s !\n"); break;

default: printf("Bonjour %s %s !\n", nom, prenom);


}

return; // cette instruction peut être omise.


}

Exemples de fonctions de type


void (procédures)
Les fonctions
 Lorsqu’une fonction de type void doit retourner plusieurs résultats à l’image de la
procédure algorithmique ci-dessous, il faut passer en paramètres les adresses respectives
des zones mémoires où stocker ces résultats.
{précondition : aucune}
{rôle : renvoie les voisins gauche et droite d’un entier}
PROCEDURE voisins (DONNEE: ENTIER n, RESULTAT: ENTIER gauche, ENTIER droite)
DEBUT
gauche = n – 1
droite = n + 1
FIN

/*
précondition : aucune
rôle : renvoie les voisins gauche et droite d’un entier
*/
void voisins(int n, int* ptr_gauche, int* ptr_droite)
{
*ptr_gauche = n - 1;
*ptr_droite = n + 1;
}
Retourner plusieurs résultats ?

Les fonctions
#include <stdio.h>  Lors de l’appel de la fonction, le
système crée automatiquement
float racineCarree(float argument); une variable locale pour stocker
une copie de la valeur passée en
int main() paramètre.
{
float racineCalculee, nombre;  La fonction travaille alors sur la
Copie de nombre dans l’argument au moment de copie et l’original reste inchangée.
printf("Entrer un réel svp : "); l’appel de la fonction racineCarree (…)
scanf("%f", &nombre);

racineCalculee = racineCarree(nombre);
printf("la racine de carrée de %.2f est %.2f.\n", nombre, racineCalculee);

return 0;
}

float racineCarree(float argument)


{
float racine = 0;
while (racine * racine < argument)
Utilisation de la copie en utilisant l’argument à
racine += 0.01;
l’intérieur de la fonction racineCarree (…)
return racine;
}

Les fonctions
Le passage par valeur
#include <stdio.h>  Lors du retour de la fonction,
return prend en paramètre la
float racineCarree(float argument); donnée que doit retourner la
fonction (ici racine).
int main()
{  Cette donnée est copiée (dans
float racineCalculee, nombre; racineCalculee) par une opération
d’affectation.
printf("Entrer un réel svp : ");
scanf("%f", &nombre);

racineCalculee = racineCarree(nombre);
printf("la racine de carrée de %.2f est %.2f.\n", nombre, racineCalculee);

return 0;
}

float racineCarree(float argument)


{
float racine = 0;
while (racine * racine < argument)
racine += 0.01;

return racine;
}

Les fonctions
Le passage par valeur
 Le passage par adresse est un passage par copie de l’adresse de la variable et non de la
valeur de celle-ci.
 Il est généralement utilisé lorsqu’on souhaite :

 Passer en paramètre une chaîne de caractères.


 Exemple de la fonction sayHello () vue précédemment dans le cours

 Renvoyer au module appelant, plusieurs informations (l’instruction return ne


retournant qu’une seule information à la fois)
 Exemple de la fonction voisins () vue précédemment dans le cours.

 Modifier dans la fonction, la valeur à passer en paramètre.


 Exemple de la fonction reinitialiser ()

Le passage par adresse

Les fonctions
#include <stdio.h>

int reinitialiser(int* adresse);


Modifier dans la fonction, la valeur à
int main() passer en paramètre.
{
int var = 9, code_retour;  Nous souhaitons réinitialiser la variable var
en lui affectant la valeur 0 si et seulement
code_retour = reinitialiser(&var); si celle-ci est négative.

if (code_retour) printf("La variable a été initialis%ce.\n", 130);


 La fonction reinitialiser (…) prend donc
comme argument l’adresse mémoire de
else printf("La variable n'a pas été modifi%c.\n", 130);
var pour y accéder directement et
effectuer la modification.
return 0;
}  Avant, elle s’assure que la zone contient
bien un nombre négatif.
int reinitialiser(int* adresse)
{  Dans ce cas, elle effectue la modification et
int code_erreur = 0; retourne 1.

// On réinitialise la zone si elle contient un nombre négatif  Si la zone mémoire ne pas contient un
if (*adresse < 0) nombre négatif, elle ne fait rien et la valeur
{ 0 est retournée par défaut.
*adresse = 0; // Modification de la zone

// Valeur à retourner
code_erreur = 1;
}

return code_erreur;
Les fonctions
} Le passage par adresse
Les arguments de la fonction main
La ligne de commandes
 Au lancement du programme, il est tout à fait possible de fournir des informations à la
fonction main (le point d’entrée du programme) tout comme on le ferait avec les autres
fonctions.

 Ces arguments sont facultatifs.

 Il est possible de fournir autant d’arguments que l’on veut …

 Les arguments de la fonction main sont rangés dans un tableau de chaînes caractères

 Le passage des arguments peut se faire en ligne de commandes ou en utilisant un


raccourci.

Les arguments de la fonction main


argc : Nombre d’arguments
de la fonction main au
moment de l’appel y compris le
nom du programme …

argv : Tableau de chaînes de caractères

Définition des arguments

Les arguments de la fonction main


Exemple d’utilisation

Les arguments de la fonction main


 A la découverte des fonctions en C, des modes de passage par valeur et
TP-7 par adresse, et des arguments de la fonctions main.
Les concepts avancés

Module - 2
Le Langage C
Les macros et la compilation conditionnelle
#ifndef – #ifdef - #endif - #define - #undef …
Les structures de données
struct - typedef
Les listes chaînées
Simple chaînage
Les Piles
Last In First Out (LIFO algorithm)
Les Files
First In First Out (FIFO algorithm)
Les Fichiers
Les fichiers séquentiels
Les bibliothèques statiques
Les librairies statiques (.a / .so)
Les bibliothèques dynamiques
Les librairies dynamiques (.dll)
FIN

Vous aimerez peut-être aussi