• Aucun résultat trouvé

1Langage C/C++ , adresses et données La mémoire d’une machine (ordinateur, microcontrôleur) est organisée en octets. Chaque octet possède uneadresse.Les données occupent un ou plusieurs octets suivant leur type :

N/A
N/A
Protected

Academic year: 2022

Partager "1Langage C/C++ , adresses et données La mémoire d’une machine (ordinateur, microcontrôleur) est organisée en octets. Chaque octet possède uneadresse.Les données occupent un ou plusieurs octets suivant leur type :"

Copied!
8
0
0

Texte intégral

(1)

Ce cours/TD/TP est à réaliser à l’aide de code::block

Disponible gratuitement ici : https://codeblocks.org/downloads/26

Souc Windows , télecharger codeblocks-xx.yymingw-setup.exe (xx.yy est le numéro de la dernière version) code ::block est préinstallé sur les distributions Linux type Debian (Ubuntu, Mint ...)

Cette version de code::block dispose du compilateur c/c++ mingw sur windows et gcc sous Linux ainsi que du debugger GDB (Gnu Debugger) qui permet de poser des points d’arrêt, d’avancer un programme en pas à pas et de consulter les variables.

Prérequis : 

Connaissances élémentaires du langage C. main, fonctions, variables, types, printf.

Création d’un projet dans code::block en langage C.

Utilisation du debugger GDB

1 Langage C/C++ , adresses et données 

La mémoire d’une machine (ordinateur, microcontrôleur) est organisée en octets. Chaque octet possède une adresse.

Les données occupent un ou plusieurs octets suivant leur type :

Type de donnée Signification Taille (en octets) Plage de valeurs acceptée

char Caractère (ASCII) 1 -128 à 127

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

short int Entier court 2 -32 768 à 32 767

unsigned short int Entier court non signé 2 0 à 65 535

int Entier 2 (sur processeur 16 bits)

4 (sur processeur 32 bits)

-32 768 à 32 767

-2 147 483 648 à 2 147 483 647 unsigned int Entier non signé 2 (sur processeur 16 bits)

4 (sur processeur 32 bits) 0 à 65 535 0 à 4 294 967 295

long int Entier long 4 -2 147 483 648 à 2 147 483 647

unsigned long int Entier long non signé 4 0 à 4 294 967 295

float Flottant (réel) 4 3.4*10-38 à 3.4*1038

double Flottant double 8 1.7*10-308 à 1.7*10308

long double Flottant double long 10 3.4*10-4932 à 3.4*104932 Les variables peuvent être :

Globales : déclarées en début de programme, elles existent durant toute la durée d’exécution du programme et sont accessibles depuis n’importe quelle partie du programme.

Locales : déclarées dans une fonction, elles n’existent que lors de l’exécution de la fonction et donc accessibles que depuis la fonction. Les variables locales permettent d’améliorer l’occupation de la mémoire.

Les pointeurs sont des variables qui contiennent l’adresse d’une autre variable.

Un pointeur est déclaré avec une * :

int *p ; représente un pointeur sur des entiers double *d ; représente un pointeur sur des réels

L’opérateur * permet d’accéder au contenu de la donnée pointé par le pointeur.

L’opérateur & permet de récupérer l’adresse d’une variable.

Remarque : pour récupérer l’adresse d’un tableau le & n’est pas nécessaire, le nom du tableau représentant l’adresse de celui-ci.

int i,j ; // i et j sont des entiers

int *p ; // p est un pointeur sur des entiers

p=&i ; // p contient l’adresse de i, on dit que pointe sur i

j=*p ; // j est égal au contenu de l’adresse lointée par p, ce qui revient à j=i ;

(2)

Deux nouvelles variables de type pointeur (pi et pc) sont créés, les adresses des autres variables sont modifiées.

La fenêtre Watches du debugger donne les valeurs par défaut en décimal. Cliquer-droit sur une valeur puis

« properties » puis choisir la base d’affichage hexadecimal.

On voit ici les valeurs de iglo, jglo,, xloc, yloc et les valeurs des deux pointeurs qui contiennent les adresses de iglo et xloc,

#include <stdio.h>

#include <stdlib.h>

int *pi; // un pointeur sur des entiers char *pc; // un pointeurs sur des caractères char mess[]="Bonjour"; // une chaine

int iglo; // variables globales int jglo;

int main() {

char xloc,yloc; // variables locales

iglo=0x12345678; // les entiers sont codés sur 32bits jglo=0xABCDEF09;

xloc=0x11; // les char sont codés sur 8 bits yloc=0x22;

pi=&iglo; // pi contient l'adresse de iglo pc=&xloc; // pc contient l'adresse de xloc printf("Adresse de iglo pi= %p\n",pi);

printf("Adresse de xloc pc= %p\n",pc);

return 0;

}

(3)

2 Un grand classique, la fonction « echange »

On désire réaliser une fonction qui échange les valeurs de deux variables.

Une première approche consiste à réaliser ce programme qui teste la fonction échange :

L’exécution de ce programme donne ce résultat, visiblement il ne fonctionne pas :

Placer un point d’arrêt sur le premier printf, lancer le debugger, visualiser x,x,i,j,k.

Dérouler le programme en pas à pas avec step into qui permet d’entrer dans les fonctions.

Constater lors de l’appel de la fonction echange, le transfert des valeurs de x et y dans i et j, puis l’échange de i avec j. Mais au retour x et y n’ont pas changés.

Cela est dû au principe du transfert de paramètres par valeur du C/C++.

Le seul moyen de réaliser la fonction échange est de transférer non pas les valeurs de x et y mais leurs adresses et donc d’utiliser des pointeurs.

#include <stdio.h>

#include <stdlib.h>

void echange(int i, int j) {

int k;

k=i;

i=j;

j=k;

}

int main() {

int x=1;

int y=2;

printf("x= %d y=%d\n",x,y);

echange(x,y);

printf("x= %d y=%d\n",x,y);

return 0;

}

(4)

La fonction échange qui fonctionne

Ajouter dans Watches, *i et *j qui représentent les valeurs de x et y.

On voit ici le résultat.

#include <stdio.h>

#include <stdlib.h>

void echange(int *i, int *j) // les paramètres sont des pointeurs {

int k;

k=*i; // k = le contenu de l’adresse pointée par i donc x *i=*j; // le contenu de i = le contenu de j donc x=y *j=k; // le contenu de j dinc y = k qui vaut x }

int main() {

int x=1;

int y=2;

printf("x= %d y=%d\n",x,y);

echange(&x,&y); // on transmet maintenant les adresses de x et y printf("x= %d y=%d\n",x,y);

return 0;

}

(5)

3 Pointeurs sur les tableaux

Le programme ci-dessous montre l’utilisation d’un pointeur sur une chaîne de caractère.

Exécuter le programme en pas à pas, visualiser et interpréter les valeurs des adresses des chaînes de caractères, de p et j.

#include <stdio.h>

#include <stdlib.h>

char jour1[]={"lundi"};

char jour2[]={"mardi"};

char jour3[]={"mercredi"};

char jour4[]={"jeudi"};

char jour5[]={"vendredi"};

char jour6[]={"samedi"};

char jour7[]={"dimanche"};

void affJour(char *j) {

printf("Nous sommes %s\n",j);

}

int main() {

char *p; // p est un pointeur sur des char p=jour4; //pas de & pour un tableau

affJour(p);

p=jour2;

affJour(p);

p=jour6;

affJour(p);

return 0;

}

(6)

4 Pointeurs de pointeurs

Le programme précédent ne permet pas d’afficher en boucle les jours de la semaine. Il est possible de déclarer des tableaux de chaines de caractère. Chaque chaine étant repérée par une adresse (accessible par un pointeur), on peut indexer les chaines par un pointeur de pointeur.

#include <stdio.h>

#include <stdlib.h>

// deux tableaux de pointeurs de chaines de caratères

char *jour[]={"lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"};

char

*mois[]={"janvier","fevrier","mars","avril","mai","juin","juillet","aout","septembre","octobre","novemb re","decembre"};

// un pointeur sur des pointeurs de char char **pp;

// affiChaine reçoit un pointeur de pointeurs de char (donc d'une chaine) et le nombre de pointeurs de char (de chaines) à traiter

void affChaine(char **ptc, int n) {

int i;

for(i=0;i<n;i++) {

printf("%s ",*(pp+i));

}

printf("\n");

}

int main() {

pp=jour+2; // pp pointe sur le pointeur de la chaine jour + 2 soit mercredi printf("%s\n",*pp);

pp=mois+2; // pp pointe sur le pointeur de la chaine mois + 2 soit mars printf("%s\n",*pp);

pp=jour; // pp pointe sur le premier pointeur *jour affChaine(pp,7);

pp=mois; // pp pointe sur le premier pointeur *mois affChaine(pp,12);

return 0;

}

(7)

5 Énumérations

Une énumération (enum) est une sorte de « define » qui numérote des équivalences. Une énumération définit un nouveau type.

Dans le programme suivant lundi=0 mardi=1 etc.… L’utilisation de pointeurs s’accompagne souvent d’énumérations.

Un type  énuméré dans une boucle :

#include <stdio.h>

#include <stdlib.h>

// jourSemaine est nouveau type de données // lundi=0, mardi=1 etc...

enum jourSemaine {

lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche };

// les chaines de caractères des jours de la semaine

char *jour[]={"lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"};

char **pp;

int main() {

enum jourSemaine aujourdhui; // aujourdhui est de type jouSemaine aujourdhui=mercredi; // donc aujourdhui = 2

pp=jour+aujourdhui; // donc pp pointe sur la chaine *jour[2] c'est à dire "mercredi"

printf("%s\n",*pp);

return 0;

}

#include <stdio.h>

#include <stdlib.h>

// jourSemaine est nouveau type de données // lundi=0, mardi=1 etc...

enum jourSemaine {

lundi, mardi, mercredi, jeudi, vendredi, samedi, dimanche };

// les chaines de caractères des jours de la semaine

char *jour[]={"lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"};

char **pp;

int main() {

enum jourSemaine aujourdhui; // aujourdhui est de type jouSemaine for(aujourdhui=lundi;aujourdhui<=dimanche;aujourdhui++) {

pp=jour+aujourdhui; // donc pp pointe sur la chaine *jour[2] c'est à dire "mercredi"

printf("%s\n",*pp);

} return 0;

}

(8)

6 Pointeurs sur des fonctions

Il est possible de créer un pointeur sur une fonction. Cela permet de passer l’adresse d’une fonction en paramètre d’une fonction.

Dans l’exemple ci-dessous la fonction affiche reçoit en paramètre un nombre a et un pointeur sur une fonction. Elle appelle la fonction pointée avec le paramètre a, reçoit en retour le résultat de l’opération.

La déclaration d’un pointeur sur une fonction est similaire à la déclaration d’une fonction retournant un pointeur. On ajoute juste des parenthèses pour spécifier que le pointeur est sur la fonction. Le non de la variable d’entrée n’est pas spécifié, seulement son type.

Une fonction qui reçoit un entier et retourne un pointeur sur un entier → int *pf(int a) ; Un pointeur sur une fonction qui reçoit un entier et retourne un entier → int (*pf)(int) ;

Exécuter le programme en pas à pas et visualiser les passages par les fonctions triple et quadruple

#include <stdio.h>

int triple(int a) {

printf("Calcul de %d x 3 ",a);

return a * 3;

}

int quadruple(int a) {

printf("Calcul de %d x 4 ",a);

return a * 4;

}

void affiche(int a,int (*pf)(int)) // pointeur sur une fonction qui reçoit un int et renvoie un int {

printf(" -> %d\n",(*pf)(a));

}

int main(void) {

affiche(3, &triple); // passage en paramètre de l'adresse de la fonction triple

affiche(3, &quadruple); // passage en paramètre de l'adresse de la fonction quadruple return 0;

}

Références

Documents relatifs

L’exemple suivant montre la déclaration d’une variable de type pointeur de fonction qui doit retourné un entier nommé pFonction1 et d’une fonction retournant

L'informatique construit des mots binaires de 32 ou 64 éléments binaires suivant la génération du processeur pour communiquer avec les périphériques.. - En moyenne 3 MO pour

Une étude plus approfondie permet de conclure que ces deux surfaces sont tan- gentes tout le long de cette conique, qui contient d'ailleurs le point de rencontre des

Epreuve Classe Examinateur Sujet n° Coef.. 1pt 9) En utilisant la fonction ci-dessus, écrire un algorithme qui demande 10 nombres à l’utilisateur en les stockant dans un

L’octet est l’unité de mesure qui convient pour calculer la taille d’un (petit) document texte. Pour des textes plus importants, on utilisera le kilo-octet et

a) Quelle est, en octets puis en mégaoctets, la place mémoire nécessaire pour enregistrer une séquence audio/vidéo de 10 secondes ?. b) Même chose pour l’ensemble des

Un point matériel M de masse étudié dans le référentiel du laboratoire supposé galiléen est solidaire d'une rigole circulaire (de centre O et de rayon a)

- On peut ainsi assigner une valeur au pointeur de fonction, le passer à une fonction, le retourner d’une fonction et, finalement le ranger dans un