les pointeurs l'opérateur &. l'opérateur adresse & retourne l'adresse...
TRANSCRIPT
Les pointeursL'opérateur &.L'opérateur adresse & retourne l'adresse d'une variable en mémoire.
Exemple :int i = 5;
printf'(" Voici i: %d\n",i);
printf'(" Voici son adresse : %p\n",&i);
Pour afficher l'adresse d'une variable ont utilise généralement %p qui affiche l'adresse en hexadécimal (4 octets).L'adresses d'une variable correspond à l'adresse de début de la variable dans la mémoire.
Voici i: 5 Voici son adresse : 0028FF40
Les pointeursL'opérateur &.L'opérateur adresse & retourne l'adresse d'une variable en mémoire.
Exemple :int i = 5;
printf'(" Voici i: %d\n",i);
printf'(" Voici son adresse : %p\n",&i);
Pour afficher l'adresse d'une variable ont utilise généralement %p qui affiche l'adresse en hexadécimal (4 octets).L'adresses d'une variable correspond à l'adresse de début de la variable dans la mémoire.
Voici i: 5 Voici son adresse : 0028FF40
Adresse Contenu Identifiant
. . .
0028FF3F ?
0028FF40 5 Variable i
0028FF41 0 i
0028FF42 0 i
0028FF43 0 i
0028FF44 15 Variable B
0028FF45 0 B
0028FF46 0 B
0028FF47 0 B
0028FF48 ?
0028FF49 ?
0028FF4A ?
. . .
Les pointeursQu'est-ce qu'un pointeur?C'est une variable qui contient l'adresse d'une autre variable. On dit que le pointeur pointe sur la variable.
Exemple : int *P; P = &X;Adresse
de XAdresse
de XValeur de
XValeur de
Xpointeur Variable
Adresse Contenu Identifiant
. . .
0028FF3F ?
0028FF40 44 *X
0028FF41 FF *X
0028FF42 28 *X
0028FF43 0 *X
0028FF44 15 X
0028FF45 0 X
0028FF46 0 X
0028FF47 0 X
0028FF48 ?
0028FF49 ?
0028FF4A ?
. . .
Les pointeursDéclaration d'un pointeur.Une variable de type pointeur se déclare à l'aide de l'objet pointé précédé du symbole * (opérateur d'indirection).
Exemple :int *pi; // pi est un pointeur pointant sur un entier char *pc; // pc est un pointeur pointant sur un charfloat *pf; // pf est un pointeur pointant sur un float
L'opérateur * désigne le contenu de l'adresse,Exemple : int *pi,X; // pi est un pointeur pointant sur un entier
pi = &X; // on initialise le pointeur pi *pi = 5; // On charge l'entier pointé par pi avec la
// valeur 5, c'est en fait X
Les pointeursL'arithmétique des pointeurs.On déplace un pointeur dans la mémoire à l'aide des opérateurs d'addition, de soustraction, d'incrémentation, de décrémentation.
On ne peut le déplacer que d'un nombre de cases mémoire multiple de la taille de la variable en mémoire.
Exemple :int *pi; char *pc;*pi = 5;*pc = 'A';
Pointeur Contenu
. . .
pi 05
00
00
00
pi +1 ?
?
?
?
pc 65
pc + 1 ?
?
?
. . .
Les pointeursL'arithmétique des pointeurs.Exemple :int *pi; // pi pointe sur un objet de type entier (4 octets)char *pc; // pc pointe sur un objet de type char (1 octet)float *pf; // pf pointe sur un objet de type float (4 octets)*pi = 145; // 145 est le contenu de la case mémoire pi*pi+1 = 200; // 200 est de contenu des cases mémoires 4 cases
// après pi*pi+2 = 500; // 500 est le contenu des cases mémoires 8 cases
// après pi*pc = 'A'; // la case mémoire pc contient le code ASCII de A = 65pc--; // on décrémente la valeur du pointeur pc de 1*pf = 1.5; // 1,5 est stocké dans la case mémoire pf et les 4
// suivantespf++; // on incrémente la valeur du pointeur pf de 4 cases
//mémoires qui correspond à la taille d'un float
Les pointeursL'arithmétique des pointeurs.Exemple :int *pi,*qi,i;
pi = qi; // autorisé
i = pi + qi; // interdit : on ne peut pas additionner deux pointeurs
// ça n'a pas de sens
i = pi-qi; // autorisé : donne le nombre d'objets entre les deux // pointeurs
I = pi*qi; // interdit : on ne peut pas multiplier deux pointeurs
// ça n'a pas de sens
Les pointeursLes pointeurs avec une fonction.Exemple : Fonction qui prend un pointeur en paramètre d'entréeint carre(int *A){
int Res;Res = (*A) * (*A); // équivalent à : *A**A ou * A * * A return (Res);
}
Void main(void){
int *X,Y;X = (int*)malloc(1*sizeof(int)); // initialisation du pointeur sur le tas
// (heap) zone mémoire réservée aux // données
*X = 2;Y = carre(X);
}
Les pointeursLes pointeurs avec une fonction.Exemple : Fonction qui prend un pointeur en paramètre d'entrée et retourne un pointeur.int *carre(int *A){
int *Res; Res = (int*)malloc(1*sizeof(int)); *Res = (*A) * (*A); // équivalent à : *A**A ou * A * * A return (Res);
}
Void main(void){
int *X,*Y;X = (int*)malloc(1*sizeof(int)); Y = (int*)malloc(1*sizeof(int)); *X = 2;Y = carre(X);free(X);free(Y); // on libère la mémoire allouées aux pointeurs
}
!La mémoire allouée au pointeur Res n'est pas libérée …
Les pointeursLes pointeurs avec une fonction.Solution plus efficace : on passe en paramètre deux pointeurs.void carre(int *A, int *Res)
{
*Res = (*A) * (*A); // équivalent à : *A**A ou * A * * A
}
void main(void)
{
int *X,*Y;
X = (int*)malloc(1*sizeof(int));
Y = (int*)malloc(1*sizeof(int));
*X = 2;
carre(X,Y);
free(X);free(Y); // on libère la mémoire allouées aux pointeurs
}
Les pointeursLes pointeurs et les tableaux.Le langage C gère un tableau comme un pointeur à la différence près qu'il réserve un emplacement dimensionné par la déclaration.
Exemple : int T[50];
int i, *pi, T[10];
pi = &i; // *pi représente i car pi pointe sur i
*pi = 0; // c'est équivalent à i = 0
pi = &T[0]; // pi pointe maintenant sur le premier élément du tableau T
// *pi représente T[0]
*pi = 0; // équivalent à T[0] = 0;
Les pointeursLes pointeurs et les tableaux.La déclaration de T[50] réserve en mémoire 50 entiers, mais nous avons en même temps un nouveau pointeur initialisé sur le début du tableau.
Exemple :int *pi, T[10],X;
pi = T; // pi pointe sur le début du tableau soit le premier élément
*T = 0; // c'est équivalent à T[0] = 0
*(T+2) = 5; // c'est équivalent à T[2] = 5
*(pi+5) = 0; // équivalent à T[5] = 0;
Attention !
X = *(T +2) ; // c'est équivalent à X = T[2] : X 5
≠
X = *T + 2; // c'est équivalent à X = T[0] + 2 : X 0 + 2 X 2
Les pointeursLes tableaux en mémoire : Tableaux de pointeursExemple : tableau 1 dimension
char Tab1D[5];
Exemple : tableau 2 dimensions avec des chaines de caractères
char Tab2D [5][7] ={"UN","DEUX","TROIS","QUATRE","CINQ"};
On alloue le maximum pour ne pas avoir de problèmes de débordement.
Zone Mémoire inutilisables
T O T O '\0'
U N '\0'D E U X '\
0'T R O I S '\
0'Q U A T R E '\
0'C I N Q '\
0'
Les pointeursLes tableaux en mémoire : Tableaux de pointeursOn déclare un tableau de pointeurs dans lequel chaque pointeur désigne l'adresse d'un autre tableau
Exemple : tableau 2 dimensions avec des chaines de caractères
char *Tab2D [5] ;U N '\
0'D E U X '\0'
T R O I S '\0'
Q U A T R E '\0'
C I N Q '\0'
Les pointeursLes tableaux en mémoire : Tableaux de pointeurs
Exemple :
char *Tab[] = { "UN" , "DEUX", "TROIS", "QUATRE", "CINQ"} ;
Tab[0] pointe sur "UN"
Tab[1] pointe sur "DEUX"
*Tab[0] retourne sur 'U' de "UN"
*( Tab[0] + 1) retourne sur 'N' de "UN"
*( Tab[1] + 2) retourne sur 'U' de "DEUX"
Attention:*Tab[4] + 1 retourne 'D' car *Tab[4] 'C' et 'C' + 1 'D'
Les pointeursPointeur de pointeur:Un pointeur de pointeur est un pointeur pointant sur un pointeur, pointant sur un pointeur, . . . , pointant sur une variable. Cela permet de gérer des tableaux sans aucune dimension prédéfinie.
Exemple : tableau de chaine de caractère
char *Tab[] = { "UN" , "DEUX", "TROIS", "QUATRE", "CINQ"} ;
char **p // déclaration d'un pointeur de pointeur
p = &Tab[0] // p pointe sur le début du tableau de chaines de caractères
// * chaine ** caractère
*p pointe sur "UN"*(p+1) pointe sur "DEUX"
**p retourne sur 'U' de "UN"
*(*p + 1) retourne sur 'N' de "UN"
*( *(p+1) + 2) retourne sur 'U' de "DEUX"
Les pointeursAllocation dynamique des pointeurs:La déclaration d'un pointeur n'engendre pas de réservation en mémoire.Si on ne réserve pas d'emplacement mémoire, le pointeur risque de pointer sur d'autres variables : débordement de pointeur.La réservation ou allocation mémoire pour les pointeurs est réalisée généralement dans une zone réservé appelé le tas (heap). On parle alors d'allocation dynamique (modifiable à tout moment par programme).
On gère l'allocation dynamique de la mémoire avec les fonctions suivantes:
malloc()calloc()realloc()free()
Les pointeursAllocation dynamique des pointeurs:La fonction malloc : void *malloc(taille);Elle alloue un bloc de mémoire de taille octets sur le tasElle renvoie un pointeur sur la zone de type void (valable pour tous les types) qu'il faut donc convertir en un type adapté aux données.Si l'allocation réussit, malloc renvoi un pointeur sur le bloc, elle échoue si taille = 0 ou s'il n'y a pas assez de place en mémoire. Dans ce cas elle retourne un pointeur nul : NULLEx:
int *p;
p = (int *) malloc(10 * sizeof(int) ); // réservation pour 10 entiers
if ( p== NULL) // test création du pointeur
{
printf("erreur d'allocation mémoire !!!");
// ici traitement de l'erreur …
}
Les pointeursAllocation dynamique des pointeurs:La fonction calloc : void *calloc(nombre,taille);Elle alloue un bloc de mémoire de (nombre x taille) octets sur le tasElle renvoie un pointeur sur la zone de type void (valable pour tous les types) qu'il faut convertir en un type adapté aux données.Si l'allocation réussit, calloc renvoi un pointeur sur le bloc, elle échoue si taille = 0 ou s'il n'y a pas assez de place en mémoire. Dans ce cas elle retourne un pointeur nul : NULLEx:
int *p;
p = (int *) calloc(10 , sizeof(int) ); // réservation pour 10 entiers
if ( p== NULL) // test création du pointeur
{
printf("erreur d'allocation mémoire !!!");
// ici traitement de l'erreur …
}
Les pointeursAllocation dynamique des pointeurs:La fonction realloc : void *realloc( pointeur , newtaille );Elle permet de changer la taille d'un bloc déjà alloué. Elle gère l'aspect dynamique des pointeurs. Utilisable à tous moment dans le programmeElle renvoie un pointeur sur la zone de type void (valable pour tous les types) qu'il faut convertir en un type adapté aux données.Si l'allocation réussit, calloc renvoi un pointeur sur le bloc, elle échoue si taille = 0 ou s'il n'y a pas assez de place en mémoire. Dans ce cas elle retourne un pointeur nul : NULLEx:int *p;
…
p = (int *) realloc( p , 20 * sizeof(int) ); // réservation pour 10 entiers supplémentaires
if ( p== NULL) // test création du pointeur
{
printf("erreur d'allocation mémoire !!!");
// ici traitement de l'erreur …
} !!! ATTENTION, les données peuvent être déplacées si l'espace n'est pas suffisant !!!
Les pointeursAllocation dynamique des pointeurs:La fonction free : free ( pointeur );Elle permet de libérer l'espace mémoire alloué par les fonctions malloc(), calloc() realloc()Il est très important de libérer l'espace mémoire après utilisation, sinon celui-ci devient inutilisable pour la suite du programme
Ex:
int *p;
p = (int *) malloc( 10 * sizeof(int) ); // réservation pour 10 entiers
if ( p== NULL) // test création du pointeur
{
printf("erreur d'allocation mémoire !!!");
// ici traitement de l'erreur …
}
……
Free(p); // on libère la mémoire
Les structuresQu'est-ce qu'une structure ?Une structure est un objet composé de plusieurs champs de types différents, qui sert à représenter un objet. Par exemple un client peut être représenté par son nom, son prénom, son année de naissance, son adresse.
Ex:
struct client // client est le nom de la structure
{
char nom[25];
char prenom[20];
int annee_naissance;
char adresse[100];
} Un_Client ; // Un_Client et le nom d'une variable de type client
// optionnel si on déclare seulement le type
// ; obligatoire dans tous les cas
Les structuresDéfinition du type et déclaration de variables?
Définition de la structure
struct client // client est le nom de la structure
{
char nom[25];
char prenom[20];
int annee_naissance;
char adresse[100];
} ;
Déclaration de variables :
struct client Un_Client; // déclaration de la variable Un_Client
struct client NouveauClient; // déclaration de la variable NouveauClient
Les structuresDéfinition du type et déclaration de variables?
Définition de la structure
typedef struct client CLIENT; // création d'un alias CLIENT sur struct client
struct client // client est le nom de la structure
{
char nom[25];
char prenom[20];
int annee_naissance;
char adresse[100];
} ;
Déclaration de variables simplifié :
CLIENT Un_Client; // déclaration de la variable Un_Client
CLIENT NouveauClient; // déclaration de la variable NouveauClient
Les structuresManipulation des champs :Les structures peuvent être manipulées champs par champs ou dans leur ensemble,
Exemple : typedef struct client CLIENT; // création d'un alias CLIENT sur struct client
struct client // client est le nom de la structure
{
char nom[25];
char prenom[20];
int annee_naissance;
char adresse[100];
} ;
Int main(void){
CLIENT Un_Client; // déclaration de la variable Un_Client
CLIENT NouveauClient; // déclaration de la variable NouveauClient
gets(NouveauClient.nom); // initialisation du champs nom
gets(NouveauClient.prenom);gets(NouveauClient.adresse);
scanf("%d",&NouveauClient.annee_naissance);
Un_Client = NouveauClient; // Affectation sur l'ensemble des champs (copie)
}
Les structuresLes pointeurs de structures:
Définition de la structure
typedef struct client CLIENT // création d'un alias CLIENT sur struct client
struct client // client est le nom de la structure
{
char nom[25];
char prenom[20];
int annee_naissance;
char adresse[100];
} ;
Déclaration de variables simplifié :
CLIENT Un_Client; // déclaration de la variable Un_Client
CLIENT NouveauClient; // déclaration de la variable NouveauClient
Les structuresLes pointeurs de structures:Définition de la structure
struct date
{ int jour;
int mois;int annee;} *p ;
int main (void){
p = (struct date *)malloc(sizeof(struct date)); if (p == NULL){ printf("erreur d'allocation mémoire!!!"); exit(-1); }
printf("Donnez le jour : "); scanf("%d",&pdate->jour);
printf("Donnez le mois : ");scanf("%d",&pdate->mois);printf("Donnez l'annee : ");scanf("%d",&pdate->annee);printf("La date %d/%d/%d \n", pdate->jour, pdate->mois, pdate->annee );
}
Les fichiersQu'est-ce qu'un fichier ?Un fichier est un ensemble d'informations stockées sur une mémoire de masse (disque dur, CD-ROM, mémoire flash…)En C, un fichier est une suite d'octets. Les informations contenues dans un fichier ne sont pas forcément de même type (char, int, float structure…)
L'adresse d'une information dans le fichier est donnée par un pointeur.
Deux types de fichier:Les binaires : Dans un fichier dit "binaire", les informations sont codées telles que comme en mémoire. Se sont généralement des nombres. Les fichiers texte : Dans un fichier dit "texte", les informations sont codées en ASCII. Ces fichiers sont visualisable facilement avec un simple éditeur de texte. Le dernier octet de ces fichiers est EOF.
Les fichiersManipulation des fichiersLa lecture ou l'écriture dans un fichier n'est pas directe, mais utilise une zone mémoire tampon. Une structure spécifique gère ce tampon et d'autre variables nécessaires à la gestion du processus.
typdef struct{char *buffer; // pointeur vers le tamponchar *ptr; // pointeur vers le caractère suivant dans le
tamponint cnt; // nombre de caractères dans le tamponint flag; // bits donnant l'état du fichierint fd; // descripteur (identifiant de fichier)} FILE;
Les fichiersOuverture des fichiersAvant qu'un programme puisse manipuler un fichier, il doit commencer par l'ouvrir.
FILE * fopen( char *nom_fichier, char *mode_acces);
Exemple:
#include <stdio.h>
void main(void){FILE *fp;fp = fopen("nomdufichier.dat","r"); // Ouverture du fichier en mode lectureif (fp==NULL)
{printf("Erreur d'ouverture de fichier\n");}
……}
Les fichiersOuverture des fichiersLes différents modes d'accès aux fichiers texte.
Pour les fichiers binaires, les modes d'accès sont: "rb","wb", "ab", "rb+", "wb+", "ab+".
Mode d'accè
s
cible résultat
"r" Ouvrir le fichier en lecture (read) fopen retourne NULL si le fichier n'existe pas
"w" Ouvrir le fichier en écriture (write)
Le fichier est créé s'il n'existe pas. S'il existe le contenu est
écrasé et perdu
"a" Ajouter des données (append). Ouverture en écriture à la fin du
fichier
Le fichier est créé s'il n'existe pas
"r+" Ouvrir le fichier en lecture et en écriture
Fopen retourne NULL si le fichier n'existe pas
"w+" Ouvrir le fichier en lecture et en écriture
Le fichier est créé s'il n'existe pas. S'il existe le contenu est
écrasé et perdu
"a+" Ouvrir le fichier en lecture et en ajout
Le fichier est créé s'il n'existe pas
Les fichiersFermeture des fichiersQuand un fichier n'est plus utilisé, on le ferme. Cela annule sa liaison avec le pointeur FILE correspondant.Attention il ne faut pas oublier de fermer un fichier après utilisation, car le nombre de fichiers susceptibles d'être ouverts simultanément est limité (nombre de pointeurs FILE limité).
int fclose( FILE *pointeur_fichier);
Exemple:
#include <stdio.h>
void main(void){FILE *fp;
……fclose(fp); // Fermeture du fichier, retourne 0 si pas d'erreur sinon EOF}
Les fichiersLecture et écriture en mode caractère:Lecture :
int fgetc( FILE *pointeur_fichier);La fonction fgetc retourne le caractère lu sous la forme d'un int. Si la valeur retourné est EOF ( EOF = -1), c'est que la fin de fichier a été atteinte ou qu'il y a eu une erreur.Exemple:
int c;
c = fgetc(fp);
Ecriture :int fputc( int caractere, FILE *pointeur_fichier);
La fonction fputc transfère un caractère dans le fichier pointé par pointeur_fichier. La fonction retourne le caractère écrit si pas d'erreur, et EOF s'il y a une erreur.Exemple:
fputc( 'A', fp);
Les fichiersLecture et écriture en mode chaine:Lecture :char *fgets(char *pointeur_tampon,int nombre, FILE *pointeur_fichier);
La fonction fgets lit dans le fichier à partir de la position courante, nombre caractères et les range à l'emplacement pointé par pointeur_tampon. La fonction s'arrête si un saut de ligne '\n' a été lu ou si nombre-1 caractères ont été lu ou si c'est la fin de fichier.Exemple:
char stringbuf[81];
fgets(stringbuf, 81 , fp);
Ecriture :char * fputs( char *pointeur_tampon, FILE *pointeur_fichier);
La fonction fputs écrit une chaine de caractère dans un fichier à partir de la position courante.la fonction retourne une valeur positive si pas d'erreur, et EOF s'il y a une erreur.Exemple:
fputs( 'Message', fp);
Les fichiersLecture et écriture formatées:Lecture :char *fscanf(FILE *pointeur_fichier,char *chaine_formatee, variables,..,..);La fonction fscanf lit des données dans un fichier en les formatant. Elle retourne le nombre de données correctement lues si pas d'erreur. La valeur EOF signifie fin de fichier ou erreur.Exemple: long num;
char nom[30];char prenom[30];
…fscanf(fp, "%ld %s %s",&num, nom, prenom);
Ecriture :int * fprintf(FILE * pointeur_fichier,char *chaine_formatee, variables,..,..);La fonction fprintf écrit des données dans un fichier en les formatant, elle retourne le nombre de données correctement écrites si pas d'erreur, et EOF s'il y a une erreur.Exemple:
fprintf( fp, "%ld %s %s",num,nom,prenom);
Les fichiersLecture et écriture en bloc:Lecture :int *fread(void *pointeur_Tampon,size-t taille,size_t nombre,FILE *point_fic);La fonction fread lit un bloc de données de taille x nombre octets et le range à l'emplacement référencé par pointeur_tampon. Elle retourne le nombre d'octets lus. Si la valeur est inférieur à nombre alors erreur.Exemple: struct client k[5];
…fread(k, sizeof(struct client),5,fp);
Ecriture :int * fwrite(void *pointeur_Tampon,size-t taille,size_t nombre,FILE *point_fic);La fonction fwrite écrit un bloc de données de taille x nombre octets rangé à l'emplacement référencé par pointeur_tampon dans le fichier pointé par point_fic. Elle retourne le nombre d'objets complétement écrits. Si la valeur est inférieur à nombre alors erreur.
Exemple:
fwrite(k, sizeof(struct client), 5, fp);
Les fichiersPositionnement dans un fichier:Jusqu'à présent on a supposé un accès séquentiel aux données.
Si on veut accéder à la valeur C5 : il faut un accès direct aux données donc positionner le pointeur de fichier au bon endroit
C1 C2 C3 C4 C5 C6 C7 C8 C9
Avant 1éré lecture
0 1 2 3 4 5 6 7 8
Après 1éré lecture
Après 2éme lecture
Après 6éme lecture
Les fichiersPositionnement dans un fichier: int fseek(FILE *pointeur_fichier, long offset, int base);La fonction fseek permet de placer le pointeur de position sur un octet quelconque d'un fichier. Le paramètre offset impose le nombre d'octets dont il faut décaler le pointeur relativement à la base. Si l'offset est négatif le déplacement s'effectue vers le début du fichier. base précise l'origine du déplacement dans le fichier.
La fonction retourne 0 si pas d'erreur sinon un nombre non nul.Exemple: fseek(fp,0,0); // on se place au début du fichier
fseek(fp,0,SEEK_END); // on se place à la fin du fichier
fseek(fp,-3,SEEK_END); // on se place 3 octets avant la fin du fichier
Si on veut accéder à la valeur C5 : il faut un accès direct aux données donc positionné le pointeur de fichier au bon endroit
base
Constante symbolique.
signification
0 SEEK_SET Début du fichier
1 SEEK_CUR Position actuelle dans le fichier
2 SEEK_END Fin de fichier
Les fichiersLecture de la position du pointeur dans un fichier: long ftell(FILE *pointeur_fichier);La fonction ftell permet de connaitre l'octet du fichier sur lequel pointe le pointeur de fichier. La fonction retourne dans un entier long la position courante dans le fichier à partir du début du fichier. Retourne -1 en cas d'erreur.
Exemple:
long position ;
position = ftell(fp);
Exemple recherche de la taille d'un fichier (on considère le fichier ouvert)
long Taille;fseek(fp,0,SEEK_END); // on se place en fin de fichier
Taille = ftell(fp); // lecture de la position dans le fichier
Si on veut accéder à la valeur C5 : il faut un accès direct aux données donc positionné le pointeur de fichier au bon endroit