Cours de la Programmation
C2
Filière : Informatique Appliquée
Semestre : S2
Professeur : Said LAKHAL
Année Universitaire : 2023/2024
1
Table des matières
................................................................................................................................................................. 1
Chapitre 1 : Pointeurs et allocation dynamique ................................................................................. 4
Introduction aux pointeurs ............................................................................................................... 4
Déclaration ......................................................................................................................................... 4
Opérations de base avec les pointeurs ............................................................................................. 5
Arithmétique des pointeurs .............................................................................................................. 6
Pointeurs et tableaux ......................................................................................................................... 6
Pointeurs et chaînes de caractères ................................................................................................... 7
Pointeurs et structures ...................................................................................................................... 8
Allocation dynamique de mémoire .................................................................................................. 8
Chapitre 2 : Les chaines de caractères ............................................................................................. 10
Déclaration de chaînes de caractères ............................................................................................. 10
Initialisation d’une CC.................................................................................................................... 10
Affichage de chaînes ........................................................................................................................ 10
Fonctions de manipulation de chaînes ........................................................................................... 11
Lecture d’une chaîne ....................................................................................................................... 11
Programme de manipulation des chaînes de caractères .............................................................. 12
Chapitre 3: Les fonctions ................................................................................................................... 14
Déclaration d’une fonction ............................................................................................................. 14
Appel d’une fonction ....................................................................................................................... 15
Durée de vie des variables............................................................................................................... 15
Transmission des paramètres d’une fonction ............................................................................... 16
Pointeur sur une fonction................................................................................................................ 16
Fonctions avec un nombre quelconque de paramètres ................................................................ 17
Chapitre 4 : Types composés (structures, unions, synonymes)....................................................... 18
Structures ......................................................................................................................................... 18
Unions ............................................................................................................................................... 19
Synonymes de types ......................................................................................................................... 19
Chapitre 5 : Les fichiers ..................................................................................................................... 21
Ouverture d'un fichier .................................................................................................................... 21
2
Lecture d'un fichier ......................................................................................................................... 21
Lecture caractère par caractère ..................................................................................................... 21
Lecture ligne par ligne .................................................................................................................... 22
Écriture dans un fichier .................................................................................................................. 22
Nouveau fichier ................................................................................................................................ 22
Caractère par caractère .................................................................................................................. 22
Ligne par ligne ................................................................................................................................. 23
Écriture ligne par ligne jusqu’à la rencontre d’une ligne vide .................................................... 23
Écriture dans un fichier existant .................................................................................................... 24
Caractère par caractère .................................................................................................................. 24
Fermeture d'un fichier .................................................................................................................... 24
Validation de l'ouverture de fichier ............................................................................................... 24
Exercice ............................................................................................................................................ 24
Manipulation de fichiers contenant des nombres ......................................................................... 24
Chapitre 6 : Complément : compilation séparée, directives du processeur ................................. 25
Introduction ..................................................................................................................................... 25
Compilation séparée ........................................................................................................................ 25
Création du directive....................................................................................................................... 25
Définition de toutes les fonctions incluses dans la directive......................................................... 25
Appel de ces fonctions dans la fonction main.c ............................................................................. 26
Compilation et exécution ................................................................................................................ 26
Directives du processeur ................................................................................................................. 26
3
Chapitre 1 : Pointeurs et allocation dynamique
Introduction aux pointeurs
Définition
Chaque variable stockée dans la mémoire centrale est caractérisée par deux attributs : la valeur et
l'adresse (Figure 1). La valeur correspond au contenu de la variable et est manipulée à l'aide des
techniques simples de programmation que nous avons déjà acquises. En revanche, l'adresse représente
l'emplacement de cette variable dans la mémoire et est gérée par de nouvelles variables appelées
pointeurs
Figure 1 : La valeur et l’adresse d’une variable
Déclaration
La syntaxe générale pour déclarer un pointeur est la suivante :
type *Identificateur_Pointeur;
Exemples
int *p1:// pointeur sur entier
double *p2:// pointeur sur double
char *p3:// pointeur sur caractère
Remarque
Dans la déclaration d’un pointeur, l’insertion ou la suppression d’un espace avant ou après le caractère
‘*’, ne pose aucun problème. Ainsi, les déclarations suivantes sont les mêmes :
float *r ; float* r ; float * r ;// r représente toujours un pointeur sur un float
4
Adresse mémoire
En informatique, l’adresse mémoire est un emplacement unique dans la mémoire où une valeur est
stockée. Elle est généralement représentée par un nombre hexadécimal.
L'adressage mémoire est le processus d'attribution d'adresses mémoire aux données. Il existe deux types
d'adressage mémoire :
1) Adressage direct : chaque emplacement mémoire a une adresse unique.
2) Adressage indirect : une adresse mémoire pointe vers une autre adresse mémoire, qui à son tour
pointe vers les données réelles.
Opérations de base avec les pointeurs
Initialisation
Le pointeur est une variable qui ne possède pas de valeur par défaut, il est donc important de l’initialiser
pour éviter des problèmes lors de la compilation.
Exemples
int a = 10;
int *p; // Déclaration
p = &a;// Initialisation
int *ptr= &a;// Déclaration et initialisation en même temps
Remarque
On peut avoir un pointeur qui ne pointe sur aucun résultat, comme illustre cet exemple :
float *F=NULL ;// La valeur NULL indique que le pointeur ne contient aucune adresse.
Accès à la valeur pointée
Pour accéder à la valeur pointée par un pointeur donné, il suffit de procéder l’identificateur du pointeur
par le symbole de déréférencement (*).
Exemples
int a = 10;
int *ptr= &a;
Pour afficher la valeur pointée par ptr, il suffit d’écrire :
printf ("Valeur de nombre via le pointeur : %d\n", *ptr);
Modification de la valeur pointée
Pour modifier la valeur pointée, il suffit de de procéder l’identificateur du pointeur par le symbole de
déréférencement (*), pour accéder à la valeur pointée, et de la suivre par la modification désirée.
5
Exemples
double d1 = 19.7;
double d2=-154.098 ;
double *p= &d1;
double *t=&d2 ;
*p=*p-15.765 ;// addition d’une valeur
*p=*p+d2 ;// addition de la valeur d’une variable
*p=*p+*t ;// addition d’une valeur pointée
Arithmétique des pointeurs
Incrémentation et décrémentation
Comme une variable, un pointeur peut être incrémenté ou décrémenté.
Exemples
char C1 = ‘r’;
char C2 = ‘x’;
char *ptrchar1, *ptrchar2;
ptrchar1 = &C1;
ptrchar2 = &C2;
ptrchar1++ ;// Incrémentation de ptrchar1
ptrchar2-- ;// Décrémentation de ptrchar2
printf("ptrchar1 pointe vers : %c\n", * ptrchar1);// Affichage du caractère ‘x’
printf("ptrchar2 pointe vers : %c\n", * ptrchar2);// Affichage du caractère ‘r’
Calcul d'adresse
Le pointeur permet de récupérer l’adresse d’une variable, comme il est illustré sur les deux exemples
suivants :
1) float f=-23.7 ;
float *ptrf=&f ;// ptrf contient l’adresse de la variable f
2) char Tab[4]={‘e’, ‘i’, ‘d’,’j’} ;
char *ptrchar=Tab+3 ;// ptrchar contient l’adresse du 4éme élément du tableau
Pointeurs et tableaux
Le nom d'un tableau tab représente l’adresse du début du tableau (il n'est pas utile de le faire précéder
de &) : la notation tab équivaut à &tab[0].
En réalité, le Langage C considère l'identificateur du tableau comme une constante de type pointeur sur
les éléments du tableau. Les notations suivantes sont alors équivalentes :
6
Elément Equivalent
Tab &tab[0]
tab+i &tab[i]
*tab tab[0]
*(tab+i) tab[i]
Table 1 : correspondance entre les différents éléments de la table
Considérons cet exemple :
int tab[6] ;
int *p=&tab[4]
Figure 2 : Correspondance entre le pointeur et les éléments d’un tableau
Parcours de tableaux avec des pointeurs
L’utilisation du pointeur pourra assurer le parcours de tous les éléments d’un tableau.
Dans l’exemple précédent, à l’aide de cette déclaration :
int *p1=tab ;
On pourra parcourir tous les éléments du tableau tab.
Pour accéder au 2ème élément il suffit d’incrémenter p1 par 1 : (p1++)
Pour accéder au 4ème élément, il suffit de décrémenter p par 1 : (p--)
Pour accéder au 3 élément : (p1=p1+2, ou, p=p-2)
Ainsi, à l’aide des opérations appliquées sur le pointeur, on peut parcourir tous les éléments d’un tableau.
Pointeurs et chaînes de caractères
Chaînes de caractères en C
Une chaîne de caractères en C est un tableau de caractères terminé par un le caractère nul ('\0').
Exemple
Char Nom[]= ‘’ Elkamali’’ ;
Ainsi : Nom[8]==’\0’
7
Manipulation des chaînes de caractères avec les pointeurs
Comme les pointeurs sont intimement liés aux tableaux, et que ces derniers sont étroitement liés aux
chaînes de caractères, par transitivité, les pointeurs peuvent manipuler aisément les chaînes de
caractères.
Pointeurs et structures
Considérons la structure suivante, définissant un vecteur dans l’espace vectoriel R3:
typedef struct Vecteur3D {
float x;
float y;
float z;
} Vecteur3D;
Vecteur3D vecteur1;
vecteur1.x=12.5 ;
vecteur1.y= 165.8;
vecteur1.z= -34.89;
// Ces valeurs peuvent être saisies par l’utilisateur aussi
Vecteur3D* pointeurVecteur;
pointeurVecteur=& vecteur1 ;
Pour accéder aux différents champs, en utilisant le pointeur :
pointeurVecteur-> x; *pointeurVecteur.x; // accéder au champs x
pointeurVecteur-> y; *pointeurVecteur.y;// accéder au champs y
pointeurVecteur-> z; *pointeurVecteur. z;// accéder au champs z
Allocation dynamique de mémoire
La gestion de la mémoire consiste à l'allouer dynamiquement, en réservant une zone mémoire au
besoin et en la libérant une fois que son utilisation est terminée. Quatre fonctions très connues assurent
la gestion dynamique de la mémoire :
Malloc
Elle permet d’allouer un bloc de mémoire de taille spécifiée.
8
Syntaxe
void* malloc(size_t size);
Exemple
char *ptr = (char*)malloc(5 * sizeof(char));
Calloc
Elle permet d’allouer un bloc de mémoire de taille spécifiée d’éléments, en initialisant chaque élément
à zéro.
Syntaxe
void* calloc(size_t num_elements, size_t element_size);
Exemple
float *ptr = (float *)calloc(5, sizeof(float));
Realloc
Elle est utilisée pour redimensionner un bloc de mémoire déjà alloué.
Syntaxe
void* realloc(void* ptr, size_t new_size);
Exemple
int *ptr = (int*)malloc(5 * sizeof(int));
// ... Utiliser le bloc alloué ...
ptr = (int*)realloc(ptr, 10 * sizeof(int));
Free
Cette fonction libère l’espace mémoire alloué par un pointeur.
Syntaxe
free( Identificateur_Pointeur)
Exemple
char *ptr = (char*)malloc(5 * sizeof(char));
9
// ... Utiliser le bloc alloué ...
free(ptr);
Chapitre 2 : Les chaines de caractères
Déclaration de chaînes de caractères
Une chaîne de caractères est déclarée souvent sous forme d’un tableau de caractères, ou d’un
pointeur :
Char ChaineCara[10] ;
Char *ptr= ChaineCara ;
Remarque
La manipulation des CCs nécessite la directive : #include <string.h>, car elle contient des fonctions de
traitement des CCs.
Questions :
A base de l’exemple précédent, accéder au 2ème élément de la CC, en utilisant le pointeur ptr ?
A l’aide du même pointeur, comment on peut s’assurer que la fin de CC est atteinte ?
Initialisation d’une CC
Dans la plut part des cas, la longueur d’une CC est inconnue au départ, pour cette raison, au lieu de
préciser la taille, on utilise cette déclaration :
Char chainecara[]=’’Bonjour mes amis ‘’ ;
Question
Est-t-il possible d’initialiser le pointeur par la même façon ? Si oui, comment ? sinon, pourquoi ?
Accès aux caractères
Comme la CC est traitée par le tableau, chacun de ses caractères est accessible par son indice. Le
premier caractère a la valeur 0 comme indice. Dans le cas de manipulation par pointeurs, il suffit de
l’incrémenter pour atteindre tous les éléments.
ChaineCara[3] ;// pour accéder au 4ème élément
Ptr=+6 ; //pour accéder au 7ème élémnt
Question
Comment peut on s’assurer que deux CCs sont égales ?
Affichage de chaînes
Deux fonctions sont utilisées pour afficher les chaînes de caractères : printf ou puts.
printf("%s\n", maChaine); // Utilisation du format de chaîne %s
10
puts(maChaine);
Questions :
Donner une instruction pour lire une CC ?
Donner une 2ème instruction pour l’afficher ?
Fonctions de manipulation de chaînes
Le langage C offre plusieurs fonctions pour manipuler les CC, à savoir : strlen, strcpy, strcat, etc.
Strlen est utilisée pour renvoyer la longueur d’une CC
Strlen
Cette fonction est utilisée pour afficher la longueur d’une CC
Syntaxe
Strlen(CC)
Question
Ecrire une instruction pour afficher parmi deux CCs, l’une qui a une longueur maximale
Sctrcpy
Sctrcpy permet de copier le contenu d’une chaîne source dans une chaîne de destination
Syntaxe
strcpy(destination, source);
Question
Donner quelques exemples d’application de cette fonction
strcat
Cette fonction assure la concaténation de 2 CCs, et stock le résultat dans la CC de destination.
Syntaxe
strcat(destination, source);
Question
Donner un exemple, illustrant l’utilisation de cette fonction ?
Remarque
Ces fonctions ne sont pas les seules à utiliser pour manipuler les CCs, mais elles sont les fonctions
essentielles et les plus fréquemment utilisées..
Lecture d’une chaîne
Comme les autres types de variables, pour lire une CC, on utilise la fonction scanf
Syntaxe
scanf("%s", maChaine);
Question
11
Donner l’équivalent de la fonction puts(CC), pour lire une CC
Comparaison de chaînes :
strcmp
La fonction strcmp permet de comparer deus CCs.
Syntaxe
Strcmp(str1,str2)
Résultat
0, si str1=str2
<0, si str1<str2
>0, si str1>str2
Programme de manipulation des chaînes de caractères
#include <stdio.h>
#include <stdlib.h>
#include<ctype.h>
#include<string.h>
int main()
{
//1: Lecture
//***********
//char io[13];
//gets(io);
//puts("\n");
//puts(io);
//2: Ecriture
//***********
//char *o="jjkkuuuud";
//char kl[]="llllllooo";
//puts(o);
/*puts("\n");
puts(kl);*/
//3: Longueur
//***********
/*char jul[]="nnhhfjjfkkk";
12
int gf=strlen(jul);
gf=strlen(jul);
printf("%d",gf);*/
//4: Comparaison:
//**********
/*char str1[] = "apple";
char str2[] = "application";
int result;
result = strcmp(str2, str1);
printf("%d",result);*/
//5: Copier
//**********
/* char source[] = "Bonjour";
char destination[20];
strcpy(destination, source);
puts(destination);*/
//6: strcat
//**********
/*char source[] = "Bonjour";
char destination[20]="jjjkkki";
strcat(source, destination);
puts(source);*/
return 0;
}
13
Chapitre 3: Les fonctions
Déclaration d’une fonction
Définition
Les fonctions en C permettent de structurer le programme, en associant un bloc d’instructions dans une
fonction, pour faire appel à ce bloc plusieurs fois dans le même programme ou par d’autres programme.
Syntaxe
En générale, une fonction est déclarée comme suit :
type nom_fonction ( type_1 arg_1,..., type_n arg_n)
{
[Déclarations de variables locales]
Liste d’instructions
}
Type : représente le type de la fonction. Si la fonction ne renvoie aucune valeur le type considéré est
void.
Nom_fonction : est l’identificateur de la fonction qui permet de la distinguer par rapport aux autres
fonctions et identificateurs
Arg_1,…, arg_n sont les arguments ou les paramètres de la fonction, dont chacun est identifier par un
nom et un type.
[ déclarations de variables locales ] : C’est un bloc qui contient la déclaration des variables à utiliser
localement dans le corps de la fonction. Ces variables ne sont pas accessibles par d’autres fonctions ou
autres instructions situées à l’extérieure.
Liste d’instructions : Contenant les instructions format le corps de la fonction.
Exemples
int Soustraction(int a, int b)
{
return(a-b);
}
void salutation ()
{
printf(“bonjour”);
}
La 1ère fonction renvoie un résultat de type entier. Alors que, la 2ème fonction ne renvoie aucun résultat.
Question
Donner deux exemples de fonctions : une renvoie un résultat et l’autre ne renvoie aucun résultat.
14
Appel d’une fonction
L’appel d’une fonction se fait par l’expression :
nom-fonction(para-1,para-2,...,para-n)
Le nombre des paramètres et leurs ordres est très important, quand on fait appel à une fonction. Car si
on change le nombre ou l’ordre des paramètres les résultats seront changés.
Remarque1
Dans la fonction soustraction précédente, le résultat de soustraction(5,10) et soustraction(10,5) ne sont
pas les mêmes. Aussi, l’expression soustraction(12,4,7) est invalide, car le nombre de paramètres n’était
pas respecté.
Remarque 2
Quand on appel une fonction avant son implémentation, on doit la définir avant par exemple, si on veut
utiliser la fonction soustraction, mais la définition arrivera après. Dans ce cas, une déclaration reste
indispensable.
int Soustraction(int a, int b)
Question
Est-ce qu’on peut déclarer deux fonctions différentes et par le même identificateur ? Tester votre
réponse ?
Durée de vie des variables
Les variables manipulées en C ne sont pas traitées de la même façon, en termes de durée de vie.
Ainsi, on pourra distinguer entre deux types : Variables permanentes ou statiques et variables
dynamiques.
Variable permanente : Une variable permanente occupe une place mémoire durant tout le temps
d’exécution du programme.
Variable dynamique : La variable change sa place mémoire durant l’exécution du programme.
Variables globales
Définition
Une variable globale est une variable définie hors toutes les fonctions. Ainsi, toute fonction peut en
accéder.
Exemple
Int a ;
Type_func1 nom_fun1 function(arguements1) ;
Type_func2 nom_fun2 function(arguements2);
Type_func3 nom_fun3 function(arguements3);
Int main(arguments) ;
15
La variable a est définie à l’extérieure de toutes les fonctions, par conséquent, toutes les fonctions
peuvent utiliser a.
Question
Est-t-il possible de définir une variable comme globale et locale à une fonction particulière ?
Transmission des paramètres d’une fonction
Les paramètres d’une fonction sont traités de la même manière que les variables locales de classe
automatique : lors de l’appel de la fonction, les paramètres effectifs sont copiés dans le segment de pile.
La fonction travaille alors uniquement sur cette copie. Cette copie disparaît lors du retour au programme
appelant. Cela implique en particulier que, si la fonction modifie la valeur d’un de ses paramètres, seule
la copie sera modifiée ; la variable du programme.
La fonction main()
La fonction main est une fonction particulière en langage C. C'est le point de départ de l'exécution d'un
programme C. Le principe de la fonction main est le suivant :
int main(void) {
// Instructions du programme
return 0; // Indique une fin normale du programme
}
int main(int argc, char *argv[]) {
// Instructions du programme
return 0; // Indique une fin normale du programme
}
Questions
Est-ce qu’on peut imaginer un programme en C sans la fonction main() ?
Est-ce qu’on peut définir une fonction dans le corps de la fonction main() ?
Est-t-il possible d’appeler une fonction par une autre fonction différente de la fonction main()?
Pointeur sur une fonction
Le pointeur sur une fonction est une variable qui stocke l'adresse mémoire d'une fonction. Cela permet
d’appeler une fonction indirectement à travers le pointeur.
Syntaxe
type_retour (*nom_pointeur)(type_parametre1, type_parametre2, ...);
Exemples :
int addition(int a, int b) {
return a + b;
}
int (*ptr)(int, int) = addition;
int resultat = (*ptr)(3, 5);
16
Question
Donner les étapes essentielles assurant la définition et l’utilisation d’un pointeur sur une fonction ?
Fonctions avec un nombre quelconque de paramètres
En langage C, vous pouvez utiliser la notation à points de suspension ... pour créer des fonctions avec
un nombre variable de paramètres. Ces fonctions sont appelées fonctions à nombre variable d'arguments
ou fonctions variadiques. La bibliothèque standard C fournit des macros et des fonctions pour travailler
avec ces fonctions variadiques, telles que stdarg.h.
Voici un exemple d'une fonction variadique simple qui calcule la somme de ses arguments :
#include <stdio.h>
#include <stdarg.h>
// Fonction variadique pour calculer la somme d'un nombre variable d'arguments
int somme(int nombre, ...) {
int resultat = 0;
// Déclaration d'un objet de type va_list pour stocker la liste d'arguments
va_list liste_arguments;
// Initialisation de la liste d'arguments avec le dernier argument fixe
va_start(liste_arguments, nombre);
// Parcours des arguments et accumulation de la somme
for (int i = 0; i < nombre; i++) {
resultat += va_arg(liste_arguments, int);
}
// Libération des ressources associées à va_list
va_end(liste_arguments);
return resultat;
}
int main() {
// Appel de la fonction variadique avec différents nombres d'arguments
int resultat1 = somme(3, 1, 2, 3);
int resultat2 = somme(5, 10, 20, 30, 40, 50);
// Affichage des résultats
printf("Somme 1 : %d\n", resultat1);
printf("Somme 2 : %d\n", resultat2);
return 0;
}
17
Question
Donner les éléments essentiels garantissant la définition d’une fonction avec un nombre quelconque de
paramètres.
Chapitre 4 : Types composés (structures, unions, synonymes)
Définition
En langage C, les types composés sont des structures de données qui permettent de regrouper plusieurs
éléments de types différents sous un même nom. Ils sont essentiels pour organiser et manipuler des
données complexes de manière efficace. Les types composés les plus couramment utilisés sont les
structures et les unions.
Structures
Une structure est une collection de variables de types différents, appelées membres, regroupées sous un
même nom.
Chaque membre d'une structure peut être de n'importe quel type de données, y compris des types de
données définis par l'utilisateur, comme d'autres structures.
La syntaxe pour définir une structure est la suivante :
struct Nom_Structure {
type membre1;
type membre2;
// Autres membres...
};
Exemple de déclaration et d'utilisation d'une structure :
struct Vect3D {
double x;
double y;
double z ;
};
struct Vect3D p1;
p1.x = -10;
p1.y = 2.7;
p1.z=6.9 ;
Exercice :
18
Définir les structures suivantes :
Coordonnées polaires : CP
Coordonnées cylindriques :CC
Coordonnées sphériques :CS
Coordonnées GPS :CG
Etablir des fonctions de passage d’un système de coordonnées à un autre
Unions
Définition
Une union est similaire à une structure, mais à la différence qu'elle alloue suffisamment d'espace
mémoire pour contenir seulement un des membres à la fois. Cela signifie que tous les membres partagent
la même zone mémoire.
La syntaxe pour définir une union est similaire à celle d'une structure :
union Nom_Union {
type membre1;
type membre2;
// Autres membres...
};
Exemple de déclaration et d'utilisation d'une union :
union Donne {
int i;
float f;
char c;
};
union Donne don;
don.i = 10;
// Ou bien :
don.f = 3.14;
// Ou bien :
don.c = 'A';
Synonymes de types
Définition
En C, il est possible de définir des synonymes pour des types de données existants en utilisant le mot-
clé typedef.
Cela peut rendre le code plus lisible et portable, car cela permet de donner des noms plus significatifs à
des types existants.
19
La syntaxe pour définir un synonyme de type est la suivante :
typedef type Nom_Synonyme;
Exemple de déclaration de synonyme de type :
typedef float reel;
reel nombre = -5.6;
Les synonymes de type peuvent également être utilisés avec des structures et des unions pour rendre le
code plus concis et plus lisible.
20
Chapitre 5 : Les fichiers
Inclusion de bibliothèques : Pour manipuler des fichiers en langage C, vous devez inclure la
bibliothèque standard <stdio.h>.
Ouverture d'un fichier
Pour ouvrir un fichier en C, utilisez la fonction fopen(). Cette fonction prend deux arguments : le nom
du fichier et le mode d'ouverture (lecture, écriture, etc.).
FILE *file_pointer;
file_pointer = fopen("nom_du_fichier", "mode");
Les modes courants sont :
"r" : lecture (le fichier doit exister).
"w" : écriture (crée un nouveau fichier ou écrase le contenu s'il existe).
"a" : ajout (écrit à la fin du fichier).
"r+"=r+lecture : lecture/écriture (le fichier doit exister).
"w+"w=w+lecture : lecture/écriture (crée un nouveau fichier ou écrase le contenu s'il existe).
"a+"=a+lecture : lecture/ajout (écrit à la fin du fichier).
Lecture d'un fichier
Lecture caractère par caractère
FILE *file_pointer;
char caractere;
// Ouvrir le fichier en mode lecture
file_pointer = fopen("C:\\Users\\pc\\Desktop\\Ok\\test.txt", "r");
// Vérifier si l'ouverture a réussi
if (file_pointer == NULL)
{
printf("Impossible d'ouvrir le fichier.\n");
return 1; // Gestion d'erreur
}
// Lire chaque caractère jusqu'à la fin du fichier
while ((caractere = fgetc(file_pointer)) != EOF)
21
{
printf("%c", caractere); // Afficher le caractère lu
// Vous pouvez faire n'importe quelle opération sur le caractère lu ici
}
// Fermer le fichier lorsque vous avez terminé
fclose(file_pointer);
Lecture ligne par ligne
FILE *file_pointer;
char ligne[100]; // Taille maximale d'une ligne
// Ouvrir le fichier en mode lecture
file_pointer = fopen("C:\\Users\\pc\\Desktop\\Ok\\test.txt", "r");
// Vérifier si l'ouverture a réussi
if (file_pointer == NULL) {
printf("Impossible d'ouvrir le fichier.\n");
return 1; // Gestion d'erreur
}
// Lire chaque ligne du fichier jusqu'à la fin du fichier
while (fgets(ligne, sizeof(ligne), file_pointer) != NULL) {
printf("%s", ligne); // Afficher la ligne lue
// Vous pouvez faire n'importe quelle opération sur la ligne lue ici
}
// Fermer le fichier lorsque vous avez terminé
fclose(file_pointer);
Pour lire à partir d'un fichier, utilisez fscanf() ou fgets() pour lire ligne par ligne.
Écriture dans un fichier
Nouveau fichier
Caractère par caractère
FILE *file_pointer;
char caractere;
Ouvrir un nouveau fichier en mode écriture
file_pointer = fopen("C:\\Users\\pc\\Desktop\\Ok\\e1.txt", "w");
// Vérifier si l'ouverture a réussi
if (file_pointer == NULL) {
22
printf("Impossible de créer le fichier.\n");
return 1; // Gestion d'erreur
}
printf("Saisissez des caractères (terminer par '$') :\n");
// Lire les caractères saisis par l'utilisateur jusqu'à la rencontre de '$'
while ((caractere = getchar()) != '$') {
// Écrire chaque caractère dans le fichier
fputc(caractere, file_pointer);
}
// Fermer le fichier lorsque vous avez terminé
fclose(file_pointer);
printf("Caractères écrits dans le fichier.\n")
Ligne par ligne
Écriture ligne par ligne jusqu’à la rencontre d’une ligne vide
FILE *file_pointer;
char ligne[100]; // Taille maximale d'une ligne
// Ouvrir un nouveau fichier en mode écriture
file_pointer = fopen("C:\\Users\\pc\\Desktop\\Ok\\e2.txt", "w");
// Vérifier si l'ouverture a réussi
if (file_pointer == NULL) {
printf("Impossible de créer le fichier.\n");
return 1; // Gestion d'erreur
}
printf("Saisissez des lignes (terminer par une ligne vide) :\n");
// Lire chaque ligne saisie par l'utilisateur jusqu'à la rencontre d'une ligne vide
while (fgets(ligne, sizeof(ligne), stdin) != NULL && strcmp(ligne, "\n") != 0) {
// Écrire chaque ligne dans le fichier
fputs(ligne, file_pointer);
}
// Fermer le fichier lorsque vous avez terminé
fclose(file_pointer);
printf("Lignes écrites dans le fichier.\n");
23
Écriture dans un fichier existant
Caractère par caractère
FILE *file_pointer;
char caractere;
// Ouvrir le fichier en mode ajout
file_pointer = fopen("C:\\Users\\pc\\Desktop\\Ok\\test.txt", "a");
// Vérifier si l'ouverture a réussi
if (file_pointer == NULL) {
printf("Impossible d'ouvrir le fichier.\n");
return 1; // Gestion d'erreur
}
printf("Saisissez des caractères à ajouter (terminer par '$') :\n");
// Lire les caractères saisis par l'utilisateur jusqu'à la rencontre de '$'
while ((caractere = getchar()) != '$') {
// Écrire chaque caractère à la fin du fichier
fputc(caractere, file_pointer);
}
// Fermer le fichier lorsque vous avez terminé
fclose(file_pointer);
printf("Caractères ajoutés à la fin du fichier.\n");
Fermeture d'un fichier
Une fois que vous avez fini de travailler avec un fichier, il est important de le fermer en utilisant la
fonction fclose().
Validation de l'ouverture de fichier
Il est essentiel de vérifier si l'ouverture du fichier a réussi ou non. Si fopen() retourne NULL, cela
signifie que l'ouverture a échoué.
Exercice
Manipulation de fichiers contenant des nombres
Soit Fichier.txt un fichier texte existant, contenant des entiers séparés par des espaces.
Donner une fonction C permettant de convertir une chaîne de caractères contenant uniquement
des chiffres à un entier ?
Ecrire un programme C permettant d’extraire chaque entier et de le stocker dans un tableau. ?
24
Chapitre 6 : Complément : compilation séparée, directives du
processeur
Introduction
La "compilation séparée" et les "directives du processeur" sont deux concepts distincts mais souvent
interconnectés dans le domaine de la programmation et du développement logiciel. Voici un descriptif
détaillé de chacun de ces concepts :
Compilation séparée
La compilation séparée est une technique de compilation qui permet de diviser un programme
informatique en plusieurs fichiers source distincts, puis de les compiler indépendamment les uns des
autres pour créer des fichiers objets individuels. Ces fichiers objets peuvent ensuite être liés ensemble
pour former un programme exécutable final. Cette approche facilite la gestion de projets de grande
taille en permettant une organisation modulaire du code source.
Voici les étapes générales du processus de compilation séparée :
Chaque fichier source est compilé séparément pour produire un fichier objet correspondant.
Création du directive
Il s’agit d’un fichier qui contient toutes les fonctions à définir :
Exemple : Directive functions contenant deux fonctions : Bon() et Mul(int, int)
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
// Déclaration des fonctions
void Bon();
int Mul(int a, int b);
#endif
La directive en C est un fichier d’extension .h
Définition de toutes les fonctions incluses dans la directive
#include "functions.h"
#include <stdio.h>
// Définition de la fonction sayHello
void Bon() {
printf("Bonj, world!\n");
}
// Définition de la fonction add
int Mul(int a, int b) {
25
return a * b;
}
Enregistrement de ce fichier sous le nom : functions.c
Appel de ces fonctions dans la fonction main.c
#include "functions.h"
#include <stdio.h>
int main() {
// Appel de la fonction sayHello définie dans functions.c
Bon();
// Appel de la fonction add définie dans functions.c
int P = Mul(7, 8);
printf("7 * 8 = %d\n", P);
return 0;
}
Compilation et exécution
1) Compilation du fichier qui contient les fonctions implémentées
2) Compilation de la fonction main.c
3) Exécution de la fonction main.c
Les fichiers objets sont ensuite liés ensemble pour former un exécutable final.
La compilation séparée présente plusieurs avantages, notamment :
Réutilisabilité du code : Les fonctions et les modules peuvent être réutilisés dans différents
projets.
Gestion modulaire : Les projets peuvent être organisés en modules distincts, ce qui simplifie la
maintenance et la collaboration.
Temps de compilation réduit : Seuls les fichiers source modifiés doivent être recompilés, ce
qui réduit le temps de compilation lors de la modification d'une partie du code.
Directives du processeur
Les directives du processeur sont des instructions spéciales insérées dans le code source d'un
programme pour contrôler le comportement du compilateur ou pour incorporer du code spécifique à
une plateforme ou à un processeur particulier. Ces directives sont généralement spécifiques à un
compilateur ou à une architecture matérielle donnée.
Voici quelques exemples courants de directives du processeur :
#include: Cette directive est utilisée pour inclure le contenu d'un fichier source ou d'un fichier en-tête
dans un autre fichier source.
#define: Cette directive est utilisée pour définir des macros, qui sont des substitutions de texte utilisées
pour simplifier le code et améliorer sa lisibilité.
26
Exemples
#define yu 9;
#define CARRE(x) ((x) * (x))
#ifdef, #ifndef, #else, #endif: Ces directives sont utilisées pour conditionner l'inclusion de certaines
parties du code source en fonction de la définition de macros ou de symboles.
Les directives du processeur sont souvent utilisées pour écrire du code portable qui peut être compilé
et exécuté sur différentes plateformes ou architectures matérielles sans modification significative.
En combinant la compilation séparée avec l'utilisation judicieuse des directives du processeur, les
développeurs peuvent créer des programmes modulaires, portables et facilement maintenables.
27