Langage C Module 1 21
Langage C Module 1 21
Langage C Module 1 21
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)
Module - 1
Le Langage C
Qu’est ce qu’un programme ?
Qu’est ce qu’un
programme ?
Le Langage C
Suite d’instructions
Cohérence
Autonomie
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
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
Il apparaît évident que développer dans ces conditions s’avère fastidieux car il
faut :
Maîtriser le langage binaire mais également
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.
http://www.open-std.org/jtc1/sc22/wg14/
Les caractéristiques
Programmer
En Langage C 2. La compilation
Programmer
En Langage C
http://www.codeblocks.org/downloads/26
1. L’édition du code source
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 »)
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
Programmer #include
#define
}
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
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.
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 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 :
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.
LES CARACTÈRES
Les types de données
Les constantes ENTIÈRES
La norme ANSI prévoit trois représentations des constantes entières :
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
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' '$' '<'
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.
// Programme principal
int main()
{
sayHello();
doSomething();
sayGoodBye();
return 0;
}
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
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.
1011
0110
1011
Programme en
exécution
Les données en entrée Les résultats en sortie
Généralités
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
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 é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 :
#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
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
int main()
{
int n, errorCode;
system("pause");
return 0;
}
La fonction scanf
La librairie <stdio.h>
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
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.
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;
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 ;
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
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
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 ».
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;
}
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.
Opérateur Opération
& Et logique
| Ou Logique
^ Ou exclusif logique
~ Négation 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)
Opérateur Exemples
char a = 5;
char b = 6;
char c = a | b;
|
Ou logique 0101 (a = 5)
| 0110 (b = 6)
------
0111 (c = 7)
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)
Opérateur Exemples
char a = ~5;
~ ~ 0101 (~5)
Négation logique ------
1010 (a = 10)
❖ Mode de fonctionnement
DEBUT
FIN
La structure if … else
Les branchements
#include <stdio.h>
int main()
{
int 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.
return 0;
}
L’opérateur conditionnel « ? »
Les branchements
C’est une structure dite de choix multiple (ou de sélection multiple)
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;
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.
La structure do … while
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.
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.
instruction
La structure while
int main()
{
int i;
i = 0;
while (i < 30) // Condition testée avant la première entrée dans la boucle.
{
printf("%d\t", i);
i += PAS;
}
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
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;
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
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).
L’instruction break
Les itérations
#include <stdio.h>
int main()
{
int i, j = 0;
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.
L’instruction continue
Les itérations
#include <stdio.h>
int main()
{
int i, j = 0;
if (j == 4)
{
// Force le passage au tour suivant
continue;
}
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.
Les tableaux
La syntaxe de déclaration d’un tableau unidimensionnel est la suivante :
type_elements nom_tableau [nombre_elements] ;
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.
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 } ;
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] ;
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.
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
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.
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 ».
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.
Les pointeurs
Important !
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
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>.
char* strcpy(char* dest, const char* src); Copie la chaîne src dans dest.
La bibliothèque <string.h>
Chacune de ces unités de traitement est dédiée à la réalisation d’une tâche précise.
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 « ; »
// 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;
}
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;
/*
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;
}
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;
}
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 :
Les fonctions
#include <stdio.h>
// 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.
Les arguments de la fonction main sont rangés dans un tableau de chaînes caractères
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