E N C G - Casablanca
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.

E N C G - Casablanca

Bienvenue sur le Forum Officiel des Etudiants de l'Ecole Nationale de Commerce et de Gestion - Casablanca
 
AccueilRechercherDernières imagesS'enregistrerConnexion
CHATBox ... discutez en ligne sur le Forum !
BIENVENUE AUX NOUVEAUX ENCG'istes
Le Deal du moment : -55%
Coffret d’outils – STANLEY – ...
Voir le deal
21.99 €

 

 Introduction au langage C/C++ (3)

Aller en bas 
AuteurMessage
Quantum Theory

Quantum Theory


Messages : 106
Réputation : 5
Date d'inscription : 10/08/2010
Localisation : A chercher entre le "A" et le "Z" // :)
Profession : Etudiant

Introduction au langage C/C++ (3) Empty
MessageSujet: Introduction au langage C/C++ (3)   Introduction au langage C/C++ (3) EmptyVen 3 Sep - 1:18

.
Chapitre 6

Structures de données

Une structure de données est une construction qui essaie de rassembler de façon commode

et fiable des données ayant un rapport entre elles et que l'on est souvent amené à manipuler «

en bloc ». Il s'agit souvent d'une image informatique d'un objet ou d'un concept du monde réel.

Un vecteur, comme une accélération ou un champ électrique, constitue un bon exemple ; avec les

connaissances acquises dans les chapitres précédents, je peux représenter les trois composantes

d'un champ électrique comme trois nombres

Ex, Ey, Ez . Cette représentation est peu commode
du point de vue du programmeur. Une carte d'identité est un autre objet que je peux souhaiter

informatiser ; elle contient des données relative à une même personne : nom, prénom, date de

naissance, taille, couleur des yeux. . .Pour l'instant, je ne sais pas manipuler une carte d'identité

autrement qu'en lui associant une série d'identificateurs.

Les tableaux sont des « structures de données». Ils constituent en fait la catégorie la plus

importante de structure de données en programmation scientifique et technique car ils sont parfaitement

adaptés à la représentation des vecteurs et des matrices. Ces structures sont « rigides»,

c'est-à-dire qu'elles ne changent pas de taille au cours de l'exécution d'un programme ; on connaît

en informatique des structures de données (listes, arbres) dont la taille peut croître ou décroître

pendant l'exécution.

6.1 tableau : définition

Un tableau est un ensemble d'éléments qui portent tous le même nom et qui appartiennent tous

au même type de variable (

int, float, char,... ). Ces données occupent en général des cases
successives dans la mémoire, si bien que l'on a tendance à confondre élément du tableau et case

mémoire correspondante. Pour désigner un emplacement particulier, on utilise le nom collectif et le

rang ou l'indice de l'élément. La figure ci-dessous représente schématiquement un tableau de nom

c .
c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9] c[10] c[11]

6 -68 123 6874 0 -852 951 -1 528 6 1 7896

Sur la première ligne, j'ai écrit le nom en C++ de chacune des douze variables

qui sont
numérotées de 0 à 11

. La deuxième ligne montre le contenu des douze emplacements mémoire
correspondants : ces variables sont manifestement de type

int . Le nom d'un élément, le sixième par
exemple, est

c[5] . C'est une variable comme une autre, que je peux manipuler comme d'habitude ;
les expressions suivantes ont leur sens habituel :

x = c[2] + c[3]; cout << c[8] << c[11]/c[0] << endl; x = c[1]/3;

L'indice est un entier, soumis aux règles de calcul ordinaire, comme dans

a = 3; b = 4; c[a + b];

41

Intro_C

42
Il y a cependant une règle

fondamentale à respecter : l'indice qui désigne l'un des éléments d'un
tableaux

doit rester à l'intérieur de l'intervalle défini lors de la déclaration du tableau (voir plus
loin). Contrairement à ce que l'on peut voir en Pascal, il n'y a aucun mécanisme pour «surveiller» les

indices et aucun message d'erreur si un indice déborde de l'intervalle permis. La seule conséquence,

mais elle est en général spectaculaire, est que l'on lit comme valeur d'une variable une syllabe de

code ou les données d'un autre utilisateur ; de même, on peut écrire sur un fragment de programme

ou sur des données à conserver. Ainsi, le compilateur ne protestera pas si j'écris

c[12] = 22 en
croyant initialiser le dernier élément du tableau précédent.

6.2 Déclaration et initialisation de tableaux

Comme toute variable, un tableau doit être déclaré avant utilisation, mais il faut préciser sa

taille, pour que le compilateur réserve l'espace mémoire correspondant. Ainsi, pour le tableau

précédent

int c[12]; ou encore
float x[1024]; int a[10], b[10]; char texte[128];

Je peux fixer la valeur des éléments du tableau en même temps que je le déclare :

int c[8] = {1,6,-4,123,-21,0,478,360};

Si la liste entre accolades contient moins de valeurs qu'il n'y a d'éléments, les derniers éléments

sont initialisés à zéro. Le cas contraire (plus de valeurs que d'éléments) provoque une erreur de

compilation. Il est bien préférable d'écrire

int c[] = {1,6,-4,123,-21,0,478,360};

pour laisser le compilateur compter lui-même.

6.3 Exemples élémentaires

Voici un programme simpliste qui rempli un tableau avec des entiers consécutifs et en calcule

la somme.

1

// t a b l e a u 1 . cpp : r emp l i s s a g e d 'un t a b l e a u
2

#include <ios t ream>
3

#include <c s t d l i b >
4

using namespace s td ;
5

int main ( void ){
6

int t [ 1 0 ] , s [ 1 0 ] , i ;
7

for ( i = 0 ; i < 1 0 ; i++)
8 t [ i ] = i ;

9 s [ 0 ] = 0 ;

10

for ( i = 1 ; i < 1 0 ; i++)
11 s [ i ] = s [ i

¡ 1] + t [ i ] ;
12 cout << " element somme cumulee \n" ;

13

for ( i = 0 ; i < 1 0 ; i++)
14 cout << "\ t " << t [ i ] << "\ t \ t " << s [ i ] << "\n" ;

15 system( " pause " ) ;

16 }

Je définis deux tableaux (ligne 6) de 10 éléments chacun. J'utilise ensuite une boucle « for » pour

initialiser le tableau

t (lignes 7,Cool. La boucle suivante garnit le tableau s : l'élément s i est la somme
des éléments de

t , depuis 0 jusqu'à i .
Intro_C

43
Dans l'exemple suivant, j'imagine que les réponses à un questionnaire ont été codées de 1 à 10.

À partir des résultats de l'enquête, je doit déterminer la fréquence d'apparition de chaque réponse.

J'ai supposé que les données étaient assez peu nombreuses pour permettre une initialisation du

tableau dans le corps du programme.

1

// t a b l e a u 2 . cpp : t a b l e a u de f r é quenc e s ou histogramme
2

#include <ios t r eam . h>
3

#include <c s t d l i b >
4

using namespace s td ;
5

int main ( void ){
6

int nb_reps , nb_code = 1 0 ;
7

int code , i , f r e q s [ 1 0 ] ;
8

int r eps [ 4 0 ] = { 1 , 3 , 8 , 8 , 4 , 2 , 3 , 1 , 2 , 6 ,
9 4 , 8 , 3 , 7 , 2 , 1 , 3 , 3 , 6 , 7 ,

10 5 , 8 , 2 , 3 , 1 , 9 , 7 , 8 , 6 , 1 ,

11 7 , 4 , 1 , 2 , 3 , 6 , 5 , 4 , 7 , 8 } ;

12

for ( code = 1 ; code <= nb_code ; code++)
13 f r e q s [ code ] = 0 ;

14

for ( i = 0 ; i < 4 0 ; i++)
15 ++f r e q s [ r eps [ i ] ] ;

16 cout << " code f r equenc e " << endl ;

17

for ( code = 1 ; code <= 1 0 ; code++)
18 cout << code << "\ t " << f r e q s [ code ] << endl ;

19 system( " pause " ) ;

20

return 0 ;
21 }

Une première boucle (lignes 12,13) me sert à initialiser à zéro le tableau des fréquences. Chaque

élément de ce tableau va en fait jouer le rôle d'un compteur, qui sera incrémenté de un à chaque

apparition du code correspondant. Remarquez que je numérote ces éléments/compteurs de 1 à 10,

comme les codes correspondants ; cela revient à ignorer

freqs[0] , qui peut contenir n'importe quoi.
Il serait en effet maladroit et malcommode de numéroter différemment le code et son compteur.

La deuxième boucle (lignes 14,15) parcourt les éléments du tableau des réponses ; si par exemple

reps[12]

vaut 4, l'élément freqs[4] = freqs[reps[12]] est incrémenté.
Les lignes suivantes impriment les résultats du décompte. J'insiste encore sur la nécessité de

contrôler la validité des données. Si le tableau des réponses contient la valeur 13, le programme

essaiera d'incrémenter freqs[13], qui n'existe pas, avec un résultat imprévisible ou catastrophique.

Voici ce qu'imprime le programme :

code frequence

1 6

2 5

3 7

4 4

5 2

6 4

7 5

8 6

9 1

10 0

Le programme précédent fonctionne, mais il est mal écrit ! En effet, il est difficile à modifier.

Pour changer un détail comme le nombre de réponses ou le nombre de codes, il faut parcourir tout

le programme, sans oublier aucune des apparitions de ces paramètres. C'est assez facile ici, ça le

serait moins pour un programme de 10000 lignes. En général, il faut «paramétrer» son programme,

Intro_C

44
pour permettre des modifications faciles, qui affectent une ou deux lignes ; cela est particulièrement

vrai des programmes qui utilisent des tableaux. C'est ce que j'ai déjà fait de façon très partielle,

en définissant l'entier

nb_code .
Le langage C offre la possibilité de définir et d'initialiser facilement des paramètres constants

grâce au préprocesseur. Il suffit d'introduire au début les définitions

#define NB_REPS 40

#define NB_CODE 10

Remarquez l'absence de ponctuation ! Lorsque le préprocesseur rencontre le nom

NB_CODE dans
le programme, il le remplace

mécaniquement par 10. Si l'utilisateur veut changer le nombre de
réponses, il lui suffit de le faire dans la seule ligne de définition. De même pour

NB_REPS et 40.
L'écriture en majuscules est une convention universellement respectée : elle signe une définition

destinée au préprocesseur.

Si ce mécanisme est tout à fait admis en C++, il est cependant peu utilisé, car on dispose d'un

autre procédé aussi simple et plus puissant. Il suffit de déclarer et d'initialiser (au niveau global

ou à tout autre niveau commode) des constantes entières :

const int nb_reps = 40, nb_code = 10;

Ces «variables» ne sont pas modifiables dans la suite du programme : toute tentative d'affectation

d'une nouvelle valeur à

nb_reps ou à nb_code provoquera une erreur de compilation.
Les deux méthodes précédentes offrent un autre avantage intéressant : les symboles ainsi définis

peuvent servir lors de la déclaration de la taille d'un tableau. On ne peut pas écrire

int reps[nb_reps];

........ // impossible

cin << nb_reps;

Les tableaux de « dimension variable», définie au moment de l'exécution, sont, en effet, interdits

en C comme en C++ sauf appel au mécanisme d'allocation dynamique, qui ne sera pas abordé

dans ce cours. Par contre,

const int nb_reps = 40;

int reps[nb_reps];

est licite, et permet d'adapter la taille du tableau aux circonstances, en changeant la valeur d'une

constante sur une seule ligne (ou d'un

#define ).
Voici une nouvelle version du même programme, tenant compte de ces perfectionnements. J'en

profite pour y ajouter le tracé (grossier) d'un histogramme des fréquences. Je vais imprimer, pour

chaque valeur de

code , une barre horizontale de longueur proportionnelle à freqs[code] . Auparavant,
il me faudra normaliser les valeurs des éléments de

freqs pour que les barres tiennent dans
la page.

1

// h i s t o g . cpp : c ons t r u c t i on amé l ior é e d ' histogramme
2

#include <ios t ream>
3

#include <c s t d l i b >
4

using namespace s td ;
5

const int nb_reps = 40 , //nombre de r épons e s
6 nb_code = 10 ,

//nombre de codes ¡ v a l e u r s
7 l_lg = 6 0 ;

// longueur d ' une l i g n e
8

int main ( void ){
9

int code , i , j , f r e q s [ nb_code+1] , fmax ;
10

int r eps [ nb_reps ] = { 1 , 3 , 8 , 8 , 4 , 2 , 3 , 1 , 2 , 6 ,
11 4 , 8 , 3 , 7 , 2 , 1 , 3 , 3 , 6 , 7 ,

Intro_C

45
12 5 , 8 , 2 , 3 , 1 , 9 , 7 , 8 , 6 , 1 ,

13 7 , 4 , 1 , 2 , 3 , 6 , 5 , 4 , 7 , 8 } ;

14

for ( code = 1 ; code <= nb_code ; code++)
15 f r e q s [ code ] = 0 ;

16

// c onf e c t i on de l ' histogramme
17

for ( i = 0 ; i < nb_reps ; i++)
18 ++f r e q s [ r eps [ i ] ] ;

19 cout << " code f r equenc e " << endl ;

20

for ( code = 1 ; code <= nb_code ; code++)
21 cout << code << "\ t " << f r e q s [ code ] << endl ;

22 cout << endl ;

23

// r e che r che de l a f r é quenc e max
24 fmax = f r e q s [ 1 ] ;

25

for ( code = 2 ; code <= nb_code ; code++)
26

i f ( f r e q s [ code ] > fmax ) fmax = f r e q s [ code ] ;
27

// normal i s at i on
28

for ( code = 1 ; code <= nb_code ; code++)
29 f r e q s [ code ]

? = l_lg /fmax ;
30

// impr e s s ion
31

for ( code = 1 ; code <= nb_code ; code++){
32 cout << code << "\ t " << f r e q s [ code ] << "\ t " ;

33

for ( j = 1 ; j <= f r e q s [ code ] ; j++)
34 cout << '

? ' ;
35 cout << "\n" ;

36 }

37 system( " pause " ) ;

38

return 0 ;
39 }

Voici le résultat :

1 48 ************************************************

2 40 ****************************************

3 56 ********************************************************

4 32 ********************************

5 16 ****************

6 32 ********************************

7 40 ****************************************

8 48 ************************************************

9 8 ********

10 0

Vous constatez que les valeurs affichées tiennent compte de la nouvelle normalisation, mais de

façon pas tout à fait exacte. Cela est due à la ligne 29, où se produit une erreur d'arrondi. Comment

faut-il modifier le programme ?

6.4 Tableau comme argument d'une fonction

Étant donné la déclaration

int temperature[24]; , qui fait référence à un tableau de 24 entiers,
je peux appeler une fonction qui utilise les éléments de ce tableau par l'instruction

calc( temperature, 24).

Il est souvent nécessaire d'informer la fonction de la taille du tableau (24 ici) pour qu'elle traite

effectivement tous les éléments.

Attention :

à la différence des arguments « simples », un tableau argument d'une fonction est
toujours transmis par référence (on dit aussi par adresse). Cela signifie que toute modification

Intro_C

46
des éléments de

temperature dans le sous-programme calc se fera sentir dans le programme
principal ! La raison profonde est que le nom du tableau contient en fait l'adresse du premier

élément ; à l'aide de cette information, la fonction peut faire ce qu'elle veut de chaque élément

du tableau. Au contraire, un élément isolé est traité comme une variable ordinaire (passage par

valeur). On peut justifier ce comportement par le fait que copier un gros tableau pour le passer

par valeur coûterait beaucoup de temps et de place (cf le qualificatif

VAR en Pascal).
Voyons un petit exemple de ces notions.

1

/ ? tab_arg . cpp : pas sag e de t a b l e a u e t d ' élément de t a b l e a u en argument ? /
2

#include <ios t ream>
3

#include <c s t d l i b >
4

using namespace s td ;
5

#define TAILLE 5
6

void modifTab ( int [ ] , int ) ;
7

void modifElem( int ) ;
8

int main ( void ){
9

int a [TAILLE] = { 0 , 1 , 2 , 3 , 4 , } , i ;
10 cout << " e l ement s du tabl eau de depar t : " << endl ;

11

for ( i = 0 ; i < TAILLE; i++)
12 cout << a [ i ] << "\ t " ;

13 cout << endl ;

14 modifTab ( a ,TAILLE) ;

15 cout << " e l ement s du tabl eau apr e s modifTab : " << endl ;

16

for ( i = 0 ; i < TAILLE; i++)
17 cout << a [ i ] << "\ t " ;

18 cout << endl ;

19 cout << " va l eur de a [ 3 ] : " << a [ 3 ] << endl ;

20 modifElem( a [ 3 ] ) ;

21 cout << " va l eur de a [ 3 ] apr e s modifElem : " << a [ 3 ] << endl ;

22 system( " pause " ) ;

23

return 0 ;
24 }

25

void modifTab ( int b [ ] , int t a i l l e ){
26

int i ;
27

for ( i = 0 ; i < t a i l l e ; i++)
28 b [ i ]

? = 2 ;
29 }

30

void modifElem( int x ){
31 x

? = 5 ;
32 cout << " va l eur l o c a l e de x modi f i e e : " << x << endl ;

33 }

dont le résultat est

elements du tableau de depart:

0 1 2 3 4

elements du tableau apres modifTab:

0 2 4 6 8

valeur de a[3]: 6

valeur locale de x modifiee: 30

valeur de a[3] apres modifElem: 6

6.4.1 Une sage précaution : la déclaration « const »

On a vu que tout tableau fourni comme argument à une fonction était modifiable par celle-ci.

Pour éviter toute modification involontaire, on peut qualifier cet argument de « constant», comme

Intro_C

47
dans l'exemple suivant.

http://tab_ct.cpp: argument tableau constant

1 #include <iostream>

2 void modif ( const int []);

3 int main(){

4 int a[] = {1,2,3,4};

5 modif(a);

6 for (int i = 0; i < 4; i++)

7 cout << a[i] << "\t" ;

8 cout << endl;

9 return 0;

10 }

11 void modif (const int b[]){

12 for (int i = 0; i < 4; i++)

13 b[i] += 5; // impossible!

14 }

Ce programme, d'apparence correcte, ne sera pas compilé : la fonction

modif tente de modifier
les éléments du tableau

a qui est déclaré comme constant, aussi bien dans l'entête (ligne 2) que
dans la déclaration de la fonction (ligne 12).

6.5 Tableaux à plusieurs dimensions

Dans le jargon de l'informatique, le « nombre de dimensions » d'un tableau est le nombre de

ses indices. Dans la pratique, on rencontre très souvent des tableaux à deux indices (lignes et colonnes),

qu'il s'agisse de représenter des dépenses par rubriques et par mois, des notes par étudiant

et par matière ou les cases d'un jeu d'échec. La figure ci-dessous montre un tableau à 3 lignes et

quatre colonnes.

col. 0 col. 1 col. 2 col. 3

ligne 0 a[0][0] a[0][1] a[0][2] a[0][3]

ligne 1 a[1][0] a[1][1] a[1][2] a[1][3]

ligne 2 a[2][0] a[2][1] a[2][2] a[2][3]

Dans cet exemple, j'ai suivi la convention du langage C++ : les indices commencent en zéro et

donc le premier élément, en haut à gauche, est

a[0][0] . J'ai aussi suivi la convention de l'algèbre
linéaire : le premier indice d'un tableau désigne la ligne, le deuxième la colonne. Ceci n'est qu'une

convention (presque universelle) mais il importe de retenir que cela ne préjuge en rien de la façon

dont les éléments sont effectivement rangés en mémoire (ils sont en fait rangés à la queue-leu-leu,

ligne par ligne ; le compilateur s'y retrouve, grâce à la déclaration du tableau, qui précise le nombre

de lignes et de colonnes).

Un élément quelconque,

a[2][3] par exemple, est une variable ordinaire, qui peut être lue,
écrite ou manipulée. La surveillance des indices s'impose ; un indice trop grand peu correspondre

à un autre élément du tableau, à une autre zone mémoire, ou à n'importe quoi.

La déclaration du tableau précédent se fait comme ceci :

int a[3][4];

Le nombre d'éléments par ligne ou colonne peut aussi être défini dans une directive du préprocesseur

ou comme une constante entière :

Intro_C

48
const int nligne = 6, ncol = 5;

.........

double T[nligne][ncol];

L'initialisation d'un tableau peut se faire au moment de la déclaration, comme dans le cas d'un

seul indice : on donne les éléments ligne par ligne, groupés au besoin à l'intérieur d'accolades. Le

compilateur initialise à zéro les éléments pour lesquels on ne fournit pas de valeur. Voici un exemple

simple de création et de manipulation de tableaux.

1

// tab2d . cpp : a f f i c h a g e de t a b l e a u x d i v e r s
2

#include <ios t ream>
3

#include <c s t d l i b >
4

using namespace s td ;
5

const int NLG = 2 ;
6

const int NCL = 3 ;
7

void Af f i c h e ( char [ ] , const int [ ] [NCL] ) ;
8

int main ( ) {
9

int tab1 [NLG] [NCL] = {{ 1 , 2 , 3 } , { 7 , 8 , 9} } ,
10 tab2 [NLG] [NCL] = { 1 , 2 , 3 , 4 , 5 } ,

11 tab3 [NLG] [NCL] = {{4 ,5} ,{8}} ,

12 tab4 [NLG] [NCL] ;

13 Af f i c h e ( " tabl eau 1" , tab1 ) ;

14 Af f i c h e ( " tabl eau 2" , tab2 ) ;

15 Af f i c h e ( " tabl eau 3" , tab3 ) ;

16

for ( int l = 0 ; l < NLG; l++)
17

for ( int c = 0 ; c < NCL; c++)
18 tab4 [ l ] [ c ] = tab1 [ l ] [ c ] + tab2 [ l ] [ c ] + tab3 [ l ] [ c ] ;

19 Af f i c h e ( " tabl eau 4" , tab4 ) ;

20 system( " pause " ) ;

21

return 0 ;
22 }

23

void Af f i c h e ( char ph [ ] , const int a [ ] [NCL] ) {
24 cout << "\ t " << ph << endl ;

25 cout << "\ t " ;

26

for ( int c = 0 ; c < NCL; c++)
27 cout << c << "\ t " ;

28 cout << endl << endl ;

29

for ( int l = 0 ; l < NLG; l++){
30 cout << l << "\ t " ;

31

for ( int c = 0 ; c < NCL; c++)
32 cout << a [ l ] [ c ] <<"\ t " ;

33 cout << endl ;

34 }

35 cout << endl << endl ;

36 }

J'ai défini quatre tableaux, dont trois ont été plus ou moins complètement initialisés au même

moment. La fonction

Affiche ne fait que cela : afficher à l'écran le contenu de ces tableaux. Elle
utilise deux boucles emboîtées pour écrire les éléments, ligne par ligne. Les lignes 14,15,16 du

programme principal réalisent la somme, élément par élément, de trois tableaux, encore à l'aide

d'une double boucle. Plus surprenant peut-être, l'entête et la déclaration de la fonction

Affiche ne
contiennent pas l'indice (unique) de

ph , un tableau de caractères ni le premier indice du tableau à
deux dimensions : le compilateur peut reconstituer cette information (grâce aux variables globales

NCL, NLG

et la fonction est un peu plus générale comme cela et un peu plus compacte, un avantage
appréciable aux yeux des fanatiques.

Intro_C

49
6.6 Chaînes

6.6.1 caractères

Je rappelle que C++ définit le type caractère comme dans

char a = 'z'; qui définit une
variable

a de type char et l'initialise à la valeur de la constante 'z' . En fait, en interne, ce 'z'
est représenté (codé) par l'entier 122. Ceci fait que la distinction entre caractères et entiers sans

signe (compris entre 0 et 255) est assez ténue.

La correspondance entre caractères et codes est explicitée dans la «table ASCII». Cette table

représente le système de codage le plus fréquent, mais pas le seul (EBCDIC est utilisé par IBM).

Dans le système ASCII, les chiffres sont codés de 48 à 57, les majuscules de 65 à 90 et les minuscules

de 97 à 122. Divers signes d'imprimerie et des caractères non imprimables remplissent les autres

cases. De 128 à 255, on est dans un no man's land où toutes les conventions sont permises.

L'ordinateur peut donc classer des caractères (et aussi des chaines)par ordre alphabétique : il

lui suffit de classer par ordre de code croissant. Remarquez que A (majuscule) viendra avant a

(minuscule).

6.6.2 Définition de chaines

Une ensemble de caractères considérés comme un tout constitue une «constante chaine de

caractères». Elle s'écrit entre guillements. Les chaines de caractères sont en C/C++ des êtres

un peu hybrides, des tableaux avec des caractéristiques particulières. Les éléments d'un tableau

doivent être tous de même type, mais ce type peut être quelconque, par exemple le type

char . En
fait, une chaîne de caractères comme

bonjour ! * est considérée par C/C++ comme un tableau
de caractères TERMINÉ PAR LE CARACTÈRE «nul»,

'\0' (pas l'entier zéro mais le caractère
de code ASCII 0). La taille réelle de ce tableau est donc nombre-de-caractères + 1.

Attention :

Une chaine telle qu'elle vient d'etre définie est héritée du C. Sa construction est
complètement différente celle de la structure «string» décrite au chapitre précédent. Seules les

chaines de style C sont permises comme noms de fichiers. Rappel : On convertit une «string»

S en
une «chaine» par l'instruction

s = S.c_str()
6.6.3 déclaration et initialisation

Je peux déclarer et initialiser un tableau de caractères comme ceci :

char string[] = "bonjour !"

Ce tableau comporte

dix éléments . En effet, le compilateur ajoute automatiquement à la fin de
cette chaîne le « caractère nul ». Je peux tout aussi bien considérer la chaîne comme un tableau

de caractères individuels, que j'initialise comme un tableau, en fournissant moi-même le caractère

nul :

char string[] = {'b','o','n','j','o','u','r',' ','!','\0'}

Vous voyez que, dans ce formalisme, un caractère ne peut être confondu avec une chaîne de longueur

un (ce que l'on fait en Pascal).

6.6.4 exemple

On dispose encore d'autres méthodes pour initialiser une variable chaine. Certaines sont identiques

à ce que l'on a vu pour les tableaux standards. Voici quelques exemple de manipulation de

chaînes.

Intro_C

50
1

// chaine1 . cpp : d e f i n i t i o n s de chaine s
2

#include <ios t ream>
3

#include <cctype>
4

#include <c s t d l i b >
5

using namespace s td ;
6

int main ( void ){
7

char ch1 [ ] = " Li c enc e " , ch2 [ 4 0 ] ;
8

char ch3 [ ] = { 'm' , ' a ' , ' i ' , ' t ' , ' r ' , ' i ' , ' s ' , ' e ' , ' \0 ' } ;
9

char ch4 [ 1 0 ] ; char ? ch5 = " t ruc " ;
10 cout << " e n t r e r un mot \n" ;

11 c in >> ch2 ;

12

for ( char i = 0 ; i < 9 ; i++)
13 ch4 [ i ] = i + 4 8 ;

14 ch4 [ 9 ] = ' \0 ' ;

15 cout << ch1 << "

??? " << endl ;
16 cout << ch2 << "

??? " << endl ;
17 cout << ch3 << "

??? " << endl ;
18 cout << ch4 << "

??? " << endl ;
19 ch1 [ 1 ] = ' y ' ;

20 cout << ch1 << endl ;

21 ch1 [1]++;

22 cout << ch1 << endl ;

23

for ( int i = 0 ; i <= 8 ; i++) // imprime l e c a r a c t e r e nul
24 cout << ch3 [ i ] ;

25 cout << "

??? " << endl ;
26

for ( int i = 0 ; i < 7 ; i++)
27 ch1 [ i ] = toupper ( ch1 [ i ] ) ;

28 cout << ch1 << endl ;

29 cout << s t r l e n ( ch1 ) << ' \ t ' << s t r l e n ( ch2 )

30 << ' \ t ' << s t r l e n ( ch3 ) << ' \ t ' << s t r l e n ( ch4 ) << endl ;

31 ch1 [ 1 ] = ' i ' ;

32

for ( int i = 0 ; i < 7 ; i++)
33 ch1 [ i ] = tolowe r ( ch1 [ i ] ) ;

34 cout << ch1 << endl ;

35 cout << ch5 << endl ;

36

// ch5 [ 0 ] = 'T ' ; mo d i f i c a t i on d ' une chaine cons tant e
37

// ===> p l ant e Dev ¡ C++
38

// cout << ch5 << endl ;
39 system( " pause " ) ;

40 }

Ligne 3, j'appelle une nouvelle bibliothèque héritée du C, qui contient les fonctions

toupper()
(conversion en majuscules) et

tolower() (conversion en minuscules). La ligne 7 contient deux
définitions de chaines, comme tableaux. L'une est initialisée au moment de la déclaration (c'est

le compilateur qui compte le nombre d'éléments), l'autre est lue au clavier (la chaine se termine

au premier caractère blanc ou à la ligne). Dans ces deux cas, le compilateur introduit lui-même le

caractère final

'\0' .
Je définis ensuite (ligne Cool une autre chaine, élément par élément : il m'incombe de placer le

caractère nul final.

ch4[10] est un tableau de caractères de 10 éléments, numérotés de 0 à 9. Ils
sont initialisés un par un lignes 12-14. Ici, je définis des caractères par leur code ASCII : ce sont

en fait les entiers de 0 à 8. C'est toujours à moi d'insérer

'\0' .
Enfin,

ch5 est définie par l'intermédiaire d'un pointeur, ce qui sera expliqué bientôt. Attention :
beaucoup de compilateurs considèrent qu'une chaine ainsi définie est une constante inviolable et

la range dans une zone spéciale de la mémoire. Toute tentative de modification (comme je le fais

ligne 36) provoque une erreur d'exécution.

Intro_C

51
J'affiche ensuite ces chaines, suivies d'étoiles, pour que l'on voit bien où elles s'arrètent. Je

me livre après à quelques manipulations élémentaires : modification d'un caractère (ligne 19),

incrémentation d'un caractère (ligne 21) (incrémentation de son code ASCII en fait, donc passage

au caractère suivant). Ligne 22, je frole la catastrophe, en dépassant de un la longueur de la chaine.

On montre ensuite l'effet des deux fonctions

tolower et toupper , puis l'usage de strlen() , qui
renvoie la longueur de la chaine passée en argument, SANS COMPTER LE CARACTÈRE NUL.

entrer un mot

programme

Licence***

programme***

maitrise***

012345678***

Lycence

Lzcence

maitrise ***

LZCENCE

7 9 8 9

licence

truc1

C++ comprend (dans la bibliothèque

<cstring> ) un grand nombre d'autres fonctions de manipulation
de chaines, qui généralement font intervenir des pointeurs et seront abordées plus tard.

6.7 enregistrement

Un enregistrement est une structure de données qui permet de rassembler des variables de types

différents mais ayant un point commun, comme les renseignements figurant sur une carte d'identité

ou une fiche de bibliothèque. En Pascal, on parle de

RECORD , en C/C++ il s'agit de struct .
6.7.1 définition

Avant d'utiliser une de ces structutres, il faut la définir : il s'agit d'un type nouveau, sorti

de l'imagination du programmeur, mais tout aussi valable qu'un

float ou un char . Voici une
définition d'une «struct» destinée à représenter l'heure

struct HMS {

int heure;

int minute;

int seconde;

};

Un enregistrement de type

HMS contient trois «champs» (ou trois «membres») de type entier ; le
nombre et la nature des champs ne sont pas limités, sauf qu'une

struct ne peut pas contenir une
struct

de même nature. Notez le point-virgule final de la déclaration.
Ayant défini un type, je peux maintenant déclarer des variables (des objets ou des identificateurs)

de ce type, comme ceci :

HMS epoque, lediner, tabHMS[10];

qui réserve de la place en mémoire pour 12 enregistrements de type

HMS , dont 10 sont groupés dans
un tableau.

Intro_C

52
6.7.2 accès aux champs

Pour initialiser les champs des

struct que l'on vient de définir, on utilise le nom de l'enregistrement
suivi d'un point et du nom du champ ; on fait de même pour lire, écrire ou calculer avec le

contenu d'un champ. L'initialisation peut aussi se faire comme pour un tableau, avec des valeurs

entre accolades.

lediner.heure = 19; lediner.minute = 30;

epoque = {6,25,45};

epoque.heure = lediner.heure - 12;

cin >> epoque.minute;

cout << "heure du diner: " << lediner.heure <<" heure "

<< lediner.minute << endl;

6.7.3 exemple

Dans le programme qui suit, je mets en oeuvre quelques opérations d'arithmétique en nombres

complexes ; chaque nombre est représenté par une

struct , avec deux champs, une partie réelle et
une partie complexe. Chaque fonction a le type

COMPLEXE et renvoie donc DEUX valeurs vers le
programme appelant.

1

#include <ios t ream>
2

#include <c s t d l i b >
3

struct COMPLEXE{
4

double r e ;
5

double im;
6 } ;

7 COMPLEXE add (COMPLEXE a , COMPLEXE b){

8 COMPLEXE somme ;

9 somme . r e = a . r e + b . r e ;

10 somme . im = a . im + b . im;

11

return somme ;
12 }

13 COMPLEXE mult (COMPLEXE a , COMPLEXE b){

14 COMPLEXE prod ;

15 prod . r e = a . r e

? b . r e ¡ a . im ? b . im;
16 prod . im = a . r e

? b . im + a . im ? b . r e ;
17

return prod ;
18 }

19

void modif (COMPLEXE a ){
20 a . r e

? = 1 0 ; a . im ? = 1 0 ;
21 }

22

int main ( ) {
23 COMPLEXE u = {1 ,0} , v = {0 ,1} , s , p ;

24 s = add (u , v ) ;

25 cout << s . r e << ' \ t ' << s . im << endl ;

26 p = mult (u , v ) ;

27 cout << p . r e << ' \ t ' << p . im << endl ;

28 modif (u ) ;

29 cout << u . r e << ' \ t ' << u . im << endl ;

30 system( " pause " ) ;

31

return 0 ;
32 }

Ce programme affiche

1 1

Intro_C

53
0 1

1 0

Vous remarquez que la fonction

\modif n'a pas eu d'effet sur la variable u : les arguments de type
struct

, contrairement aux tableaux, sont transmis pas valeur.
Chapitre 7

Les Pointeurs

Le pointeur est un type défini en C/C++, tout comme en Pascal (et en Fortran depuis 1990).

C'est une caractéristique à la fois puissante et difficile du langage. Un pointeur permet de simuler

l'appel par référence, de créer et de manipuler des structures dynamiques et est largement utilisé

dans la programmation par objet. Ici, je ne fais qu'introduire le sujet et montrer les liens qui

existent entre pointeur, tableau et chaîne de caractères. Une variable ordinaire contient une valeur ;

un pointeur, au contraire, contient l'adresse d'une autre variable qui, elle, contient une valeur. On

dit que la variable habituelle est une référence directe à une valeur alors que le pointeur est une

référence indirecte.

7.1 Déclaration et initialisation

7.1.1 déclaration et notation

Comme toute autre variable, un pointeur doit être déclaré avant usage.

int a, *Pb, c = 3;

déclare un entier

a , un pointeur vers un entier Pb et un entier c initialisé à 3. Cette déclaration
se lit comme «a est un entier, Pb est un pointeur vers un entier, c est un entier de valeur 3» (la

parti pointeur se lit «à l'envers»). L'opérateur * n'est pas distributif, il faut l'écrire pour chaque

variable de type pointeur :

double x, *Py, *Pz;

déclare deux pointeurs (

Py, Pz ) vers des nombres en double précision. Pour limiter les risques
d'erreur, il est commode de donner aux pointeurs des noms aisément reconnaissables, comportant

par exemple les caractères

p ou ptr . On peut dire qu'il existe deux opérateurs homonymes :
l'opérateur de multiplication et l'opérateur d'indirection, représentés tous deux par une étoile.

7.1.2 Opérateur adresse et initialisation d'un pointeur

L'opérateur «adresse» & en C++, renvoie l'adresse de son unique opérande. Le fragment de

code suivant affecte à un pointeur l'adresse d'une variable :

int x = 5;

int *xP;

xP = &x;

54

Intro_C

55
J'ai déclaré et initialisé un entier

x , puis un pointeur (adresse) vers un entier xP et j'ai affecté à
xP

une valeur, l'adresse de x . On dit que xP «pointe» vers x . Si on pouvait lire le contenu de la
mémoire au moment de l'exécution de ce code, on verrait quelque chose comme

adresse contenu nom de la variable

320000 530000

xP
530000 5

x
Attention :

ces adresses, imaginaires et données à titre d'exemple, ne sont, de toute façon, pas
immuables : elles vont varier d'une machine à l'autre, d'une exécution à l'autre. Et c'est très bien

ainsi ! Vous verrez que la valeur absolue d'une adresse n'a pas d'intérêt pour le programmeur.

Attention :

déclarer un pointeur n'est en rien équivalent à réserver en mémoire de la place pour
l'objet vers lequel il pointe (pensez à un hôtelier qui vous indique un numéro de chambre dans une

aile de bâtiment qui sera construite dans deux ans).

7.1.3 l'opérateur «*»

Je répète ce que j'ai dit au paragraphe précédent, de façon plus abstraite (ou prétentieuse).

L'opérateur

* (opérateur d'indirection ou de «déréférencement») appliqué à un argument de type
pointeur, renvoie un synonyme de la variable désignée par ce pointeur.

cout << *xP << endl;
affiche la valeur de

x (si l'association entre x et xP est comme déclarée plus haut), pratiquement
comme le fait

cout << x << endl; . J'ai «déréférencé» le pointeur xP . Attention : déréférencer un
pointeur qui ne pointe sur rien provoque le plantage du programme.

On peut donc lire

*xP comme «contenu de l'adresse désignée par xP » et cette interprétation
est confirmée par l'utilisation de l'opérateur que je fais maintenant :

*xP = -100;

cout << *xP;

J'affecte à

x (la variable pointée par xP ) la valeur -100 et je l'imprime.
Quand on les applique à une variable de type pointeur, les opérateurs * et & sont inverses l'un

de l'autre et commutent entre eux, comme je le montre ci-dessous,

1

// point eur1 . cpp : p r o p r i é t é s de ? e t &
2

#include <ios t ream>
3

#include <c s t d l i b >
4

using namespace s td ;
5

int main ( void ){
6

int a , ? aP;
7 a = 7 ;

8 aP = &a ;

9 cout << " adr e s s e de a : " << &a ;

10 cout << "\ nval eur de aP: " << aP;

11 cout << "\ nval eur de a : " << a ;

12 cout << "\ nval eur de

? aP: " << ? aP;
13

? aP = ¡ 36;
14 cout << "\ nval eur de a : " << a ;

15 cout << "\ nval eur de

? aP: " << ? aP;
16 cout << "\n&

? aP: " << & ? aP;
17 cout << "\n

? &aP: " << ? &aP;
18 system( " pause " ) ;

19

return 0 ;
20 }

Intro_C

56
avec les résultats

adresse de a: 0x22ff7c

valeur de aP: 0x22ff7c

valeur de a: 7

valeur de *aP: 7

valeur de a: -36

valeur de *aP: -36

&*aP: 0x22ff7c

*&aP: 0x22ff7c

7.2 Passage d'argument par adresse

Nous avons rencontré quatre façons de faire circuler de l'information entre une fonction «appelée

» et un programme principal «appelant» : déclarer des variables communes au niveau global,

renvoyer une valeur unique par l'instruction

return , « partager » un tableau avec le programme
et enfin, mettre à disposition de la fonction des variables de

main sous forme de référence. Une
autre méthode, plus générale, de transmission par adresse (référence) fait appel à un pointeur

(méthode commune à C et C++). L'exemple suivant met en oeuvre les trois dernières méthodes

de transmission d'une valeur.

1

#include <ios t ream>
2

#include <c s t d l i b >
3

int cubeVal ( int x ){
4

return x ? x ? x ;
5 }

6

void cubeRef ( int & x ){
7 x = x

? x ? x ;
8 }

9

void cubePtr ( int ? xP){
10

? xP = ? xP ? ? xP ? ? xP;
11 }

12

using namespace s td ;
13

int main ( void ){
14

int nb = ¡ 5;
15 cout << "nb au début : " << nb << endl ;

16 nb = cubeVal (nb ) ;

17 cout << "nb apr è s cubeVal : " << nb << endl ;

18 nb =

¡ 5;
19 cubeRef (nb ) ;

20 cout << "nb apr è s cubeRef : " << nb << endl ;

21 nb =

¡ 5;
22 cubePtr (&nb ) ;

23 cout << "nb apr è s cubePtr : " << nb << endl ;

24 system( " pause " ) ;

25

return 0 ;
26 }

La seule nouveauté est le passage par un pointeur (lignes 9-10, 22). Le calcul du cube(ligne 10)

est délibérément obscur ; il fonctionne parce que l'opérateur de déréférencement (*) a une priorité

beaucoup plus élevée que l'opérateur de multiplication (*) : il est donc évalué en premier. En

pratique, on mettrait assez de parenthèses pour lever toute ambiguïté.

Intro_C

57
7.3 Pointeur constant et pointeur sur une constante

Une variable qualifiée de

const ne peut pas être modifiée par le programme : cela constitue
une bonne méthode pour sécuriser le programme. Ce qualificatif peut également s'appliquer à un

pointeur et aussi à une variable désignée par un pointeur.

On dispose en fait de quatre possibilités : pointeur vers une variable, pointeur vers une constante,

pointeur constant vers une variable, pointeur constant vers une constante. La première n'apporte

aucune restriction, les autres sont plus contraignantes. Les déclarations pourraient être les suivantes.

char * cP; //pointeur vers un caractère

const int *Pi // Pi est un pointeur sur un entier constant

float * const Px // Px est un pointeur constant

// vers un nombre fractionnaire

const double * const Ptruc // pointeur constant vers un

// réel double précision constant

Il appartient au programmeur de faire le meilleur usage de ces possibilités.

7.4 Arithmétique sur les pointeurs

On ne peut faire sur les pointeurs que quelques opérations arithmétiques (ce qui est assez évident

si l'on se souvient qu'il s'agit d'adresses) : incrémentation (

++ ), décrémentation ( -- ), addition
(

+,+= ) ou soustraction ( -, -= ) d'un entier. L'intérêt de telles opérations apparaîtra au paragraphe
suivant. Il ne s'agit pas d'une addition (soustraction) simple. En effet, supposons que

aP soit un
pointeur d'entier de valeur 40096, où 40096 désigne l'emplacement d'un OCTET en mémoire.

aP+1
désigne l'emplacement suivant pour un entier, soit 40100 parce que, en général, un entier occupe

4 octets. Ces considérations n'ont de sens que si

*aP et *(aP+1) sont tous les deux des entiers.
7.5 Pointeurs et tableaux

En C/C++, tableaux et pointeurs sont des entités très proches. En fait,

le nom d'un tableau
est un pointeur constant vers le premier élément du tableau (indice 0)

; autrement dit, le nom du
tableau est l'adresse (constante) de son premier élément.

Soient les déclarations

int b[5]; int * bP; . Le nom du tableau est l'adresse (un pointeur
vers) le premier élément. Je peut donc écrire

bP = b;

ce qui est équivalent à

bP = &b[0];

L'élément d'indice 3 peut maintenant être désigné comme

*(bP+3);

L'entier 3 est un «décalage» («offset») pour le pointeur. Les parenthèses sont rendues nécessaires

par la priorité de l'opérateur * ; l'expression

*bP + 3 ajoute 3 à la valeur désignée par bP (et donc
calcule

b[0] + 3 ).
L'adresse de l'élément d'indice 3 peut s'écrire

&b[3] ou bP + 3 . Le nom du tableau étant un
pointeur, on peut écrire, symétriquement,

*(b+3) pour désigner ce même élément.
Enfin, un pointeur peut être muni d'un indice, comme

pB[1] qui désigne le deuxième élément du
tableau, tout comme

b[1] . Vous voyez pourquoi, dans le jargon du C/C++, on parle «d'opérateur
crochet» : le brave pointeur

b , affublé de crochets, est transformé aussitôt en tableau.
Intro_C

58
Attention :

une écriture comme b += 2; est impossible, puisqu'elle tend à modifier un pointeur
constant.

En général, un programme qui manipule des tableaux est plus lisible lorsqu'il utilise des indices

plutôt que des pointeurs.

Le programme qui suit illustre les différentes méthodes d'accès aux éléments d'un tableau.

1

// tab_pt r . cpp : d i f f é r e n t e s méthodes pour accéde r
2

// aux é l ément s d 'un t a b l e a u
3

#include <ios t ream>
4

#include <c s t d l i b >
5

using namespace s td ;
6

int main ( void ){
7

int a [ ] = { ¡ 40 , ¡ 30 , ¡ 20 , ¡ 10 ,0}; //a e s t un t a b l e a u d ' e n t i e r s
8

int ? Pa = a ; //Pa e s t un p o int eur d ' ent i e r , qui d é s i gne a
9

int i , de c l g ;
10 cout << "\navec un i n d i c e " << endl ;

11

for ( i = 0 ; i < 5 ; i++)
12 cout << "a [ " << i << " ] = "<< a [ i ] << ' \ t ' ;

13 cout << "\navec un po int eur (nom du tabl eau ) e t un dé c a l a g e \n" ;

14

for ( de c l g = 0 ; de c l g < 5 ; de c l g++)
15 cout << "

? ( a+" << de c l g << " ) = "<< ? ( a+de c l g ) << ' \ t ' ;
16 cout << "\navec un po int eur e t un i n d i c e \n" ;

17

for ( i = 0 ; i < 5 ; i++)
18 cout << "Pa [ " << i << " ] = "<< Pa [ i ] << ' \ t ' ;

19 cout << "\navec un po int eur e t un dé c a l a g e \n" ;

20

for ( de c l g = 0 ; de c l g < 5 ; de c l g++)
21 cout << "

? (Pa+" << de c l g << " ) = "<< ? (Pa+de c l g ) << ' \ t ' ;
22 cout << endl ;

23 system( " pause " ) ;

24

return 0 ;
25 }

7.6 Pointeurs et chaînes

Une chaîne de caractères est un tableau : son nom est donc un pointeur constant vers l'adresse du

premier caractère. Les deux représentations sont en gros équivalentes, sauf qu'une chaîne désignée

par un pointeur est souvent considérée par le compilateur comme une constante non modifiable.

Rappel de déclarations possibles :

char vin[] = "bordeaux";

char *Pvin = "bourgogne";

char vin[] = {'c','h','i','n','o','n','\0'};

Je cite maintenant un certain nombre de fonctions de la bibliothèque

cstring> permettant la
manipulation de chaînes ; je donne d'abord le prototype, puis une description.

char * strcpy(char *s1, const char *s2)

copie la chaîne s2 dans le tableau s1 et renvoie la
valeur de

s1 .
char * strncpy(char *s1, const char *s2, int n)

copie au plus n caractères de s2 dans s1 et
renvoie

s1 .
chr * strcat(char *s1, const char *s2)

ajoute s2 à la fin de s1 ; le premier caractère de s2
écrase le 0 terminal de

s1 et renvoie la valeur de s1 .
Intro_C

59
chr * strncat(char *s1, const char *s2, int n)

ajoute au plus n caractères de s2 à la fin de
s1

; le premier caractère de s2 écrase le 0 terminal de s1 et renvoie la valeur de s1 .
int strcomp(char *s1, const char *s2)

compare s1 à s2 et renvoie une valeur nulle, négative
ou positive selon que

s1 est égale, plus petite ou plus grande que s2 .
int strncomp(char *s1, char *s2, int n)

compare au plus n caractères de s1 à s2 et renvoie
une valeur nulle, négative ou positive selon que

s1 est égale, plus petite ou plus grande que
s2

.
int strlen(const char *s)

renvoie le nombre de caractères non-nuls de l'argument.
Attention aux longueurs de chaînes lorsque vous utilisez

strcpy ; cette fonction copie le second
argument (avec son zéro) dans le premier, qui doit être assez grand pour recevoir le tout. Dans le

cas de

strncpy , il faut encore s'assurer que n est assez grand pour que le zéro terminal de s2 soit
recopié.

7.7 Et les «strings» ?

Soit la déclaration/initialisation

string ch1 = "que voici une belle petite chaine";

La norme C++ impose les propriétés de

ch1 mais ne dit rien sur la façon de les réaliser «à
l'intérieur» du compilateur. Une string n'est pas un vecteur, ne se termine pas par le caractère

nul. Son nom n'est pas un pointeur, et l'écriture

&ch1[0] n'a pas de signification. Il reste vrai que
ch1[10]

est le caractère «u».
Toutes les fonctions citées au paragraphe précédent ont leur équivalent pour les «strings».

Si je déclare

ch2 = "bonjour" , je peux comparer deux «strings» ; la condition ch1 > ch2 est
vraie (ordre lexicographique plus élevé) et

ch1 == ch2 est fausse.
cout << ch1.substr(10,3)

imprime une (la sous-chaîne qui commence au caractère de rang
10 et comporte 3 lettres).

J'emploie

ch1.find("petite") pour découvrir à quel rang commence la sous-chaine «petite».
Enfin, il est facile d'insérer des caractères dans une «string» ; l'instruction

ch1.insert(9,"voila ")
injectera «voila » après voici (après le caractère blanc de rang 9).

7.8 pointeurs et «struct»

Si j'ai défini un type d'enregistrement et si j'ai déclaré des variables de ce type, je peux déclarer

des pointeurs vers ces variables. De plus, un (ou plusieurs) des champs de l'enregistrement peut

être lui-meme un pointeur vers un objet quelconque (en particulier un objet de même type). Ces

remarques rendent possibles la contruction de structures de données extrèmement riches et variées

(listes, piles, queues, . . .) qui ne seront pas décrites ici. Je me contente de préciser quelques points

de syntaxe. Examinons les déclarations suivantes.

struct cpx {double re; double im;};

cpx u,v, *Pcpx, &Refcpx = u, Tcpx[123];

J'ai défini une

struct qui mime un nombre complexe, u et v sont deux exemplaires de cette
structure,

Pcpx est un pointeur vers un complexe, Refcpx est un pseudonyme de u (défini par
référence) et

Tcpx est un tableau de «nombres» complexes.
Pour le moment, le pointeur ne pointe sur rien. Je l'initialise et j'imprime ses deux champs

comme ceci par exemple

Pcpx = &v;

cout << (*Pcpx).re << '\t' << Pcpx->im << endl;

Intro_C

60
Les deux manières d'accéder aux champs de l'enregistrement pointé par

Pcpx sont équivalentes.
Les parenthèses de la première sont obligatoires parce que l'opérateur «point» a une priorité plus

élevée que l'opérateur de déréférencement ; la seconde est peut-être plus claire et plus concise : elle

a la faveur des spécialistes.
Revenir en haut Aller en bas
http://allah-ahad.blogspot.com/
 
Introduction au langage C/C++ (3)
Revenir en haut 
Page 1 sur 1
 Sujets similaires
-
» Introduction au langage C/C++ (1)
» Introduction au langage C/C++ (2)
» Introduction:p:p

Permission de ce forum:Vous ne pouvez pas répondre aux sujets dans ce forum
E N C G - Casablanca :: Espace Scientifique :: Technologie, Informatique & Internet-
Sauter vers:  
Ne ratez plus aucun deal !
Abonnez-vous pour recevoir par notification une sélection des meilleurs deals chaque jour.
IgnorerAutoriser