




Indications pour ceux qui veulent lire vite...
Les titres principaux des parties sont centrés en gras et soulignés. Les sous-parties sont alignées dans la gauche, en gras-italique et marron. Les récapitulatifs sont en bleu. Les codes C++ sont écrit en type "codé" et gras.
Quelques détails du langage
1.1 Portabilité du programe
1.2 Utilisation de la bibliothèque limits
1.3 Opérateur sizeof
1.4 Les pointeurs
1.5 Opérations élémentaires de calcul d'adresse
1.6 Initialisations atypiques de tableaux
1.7 Les structures
1.8 Utilisation de la bibliothèque ctype

Quelques détails du langage >>
vers le sommaire
1.1 Portabilité du programme >> vers le sommaire
Quand on parle de "porter le programme" cela veut
dire qu'on souhaite l'adapter à un système différent.
Par exemple, un programme tapé pour Windows peut-être "porté"
pour Linux. Il est important de savoir que les types de variables n'ont pas
la même possibilité de contenance sur tous les systèmes
; sur certaines machines, les int ont 16 bits et 32 sur
d'autres. Ainsi, l'astuce consiste à créer soit-même un
type facilement modifiable d'un système à l'autre. On utilise
pour cela typedef, comme dans l'exemple suivant :
typedef int int32;
Ici, on crée un nouveau type int32
calqué sur le type int. Toutes les fois que l'on
souhaitera déclarer une variable de type "nombre de 32 bits",
on utilisera int32, comme ci-dessous :
int32 exemple;
Si le programme construit par cette méthode doit, un
jour, être porté sur un système où les int
prennent 16 bits et les long 32 bits, alors on modifiera
la ligne typedef int int32; en typedef long int32;
ce qui évitera d'avoir à remplacer dans tout le programme des
int par des long.
Si vous souhaitez faire appel à des types classiques
(int, long, short...)
en les nommant différent, vous pouvez aussi utiliser cette technique
bien qu'il n'y ait pas d'intérêt particulier à exploiter
un code comme :
typedef short petite_otarie;
Récapitulatif sur la gestion des
variables dans la portabilité du programme :
- Les variables n'ont pas la même contenance en bit sur tous les systèmes.
- Quand il est possible qu'un programme soit adapté d'un système
à un autre, plutôt que d'avoir à remplacer toutes les
déclarations de variables il est préférable d'utiliser
typedef qui possède la syntaxe typedef typehabituel
copie; Par exemple : typedef int int32;
1.2 Utilisation de la bibliothèque limits >> vers le sommaire
Nous allons utiliser une nouvelle bibliothèque appelée
limits qui permet d'avoir des renseignements sur les types de variables. Ouvrez
le projet habituel Base, videz le, et tapez les instructions ci-dessous :
En premier, on déclare notre bibliothèque habituelle
iostream, ensuite on déclare la bibliothèque
limits. La dernière ligne demande l'utilisation
de l'espace de nom standard, nécessaire pour utiliser la bibliothèque
limits.
Maintenant, nous allons apprendre les fonctionnalités
les plus utiles de limits. La première est la
demande de la valeur minimale que peut prendre une variable, qui se fait de
la façon suivante :
numeric_limits<int>::max()
Cependant, la valeur affichée dépendra du type
demandé. Par exemple, un int vous affichera sa
valeur maximale en chiffre, mais un char vous l'affichera
en caractères. Tapez et exécutez ce code d'exemple pour comprendre
:
Le résultat sera comme ci-dessous :
Ainsi, si vous voulez exprimer la valeur maximale d'un char
sous la forme de chiffre, il faudra placer un type spécifique correspondant
au résultat avant la commande, de la façon suivante :
(int)numeric_limits<char>::max()
On demande le minimum d'une variable sur un principe quasiment
identique, à l'exception du remplacement de max
par min :
numeric_limits<int>::min()
Nous pouvons aussi demander la contenance d'un type de variable.
La commande suivante affiche le nombre de bits que représente le type
:
numeric_limits<int>::digits
Si vous voulez connaître le nombre de bits que possède
un char, voici la demande :
cout << "Le nombre de bits pour coder un char est "
<< numeric_limits<char>::digits << "\n";
Enfin, la dernière demande intéressante consiste
à savoir si la variable a un signe. Pour cela, on utilise :
numeric_limits<int>::is_signed
La réponse sera affichée en booléen, c'est-à-dire 0 ou 1. Si c'est 1, la variable possède un signe ; si c'est 0, elle n'en possède pas.
Pour récapituler tout cela, créez un programme
qui affiche les renseignements suivants :
- Valeur maximale et minimale d'un unsigned short
- Bits représentant un unsigned short
- Est-ce qu'un unsigned short a un signe
Le code répondant à ce petit cahier des charges
est le suivant :
Récapitulatif sur l'utilisation
de la bibliothèque limits :
- On doit la déclarer avec #include <limits>
Elle nécessite aussi l'utilisation de l'espace de nom standard, que
l'on déclare avec using namespace std;
- La syntaxe de son utilisation est numeric_limits<type>::fonction
- Pour savoir la valeur maximale que peut prendre un int,
on demande numeric_limits<int>::max()
- Pour savoir la valeur minimale que peut prendre un int,
on demande numeric_limits<int>::min()
- Pour savoir le nombre de bits que représente un int,
on demande numeric_limits<int>::digits
- Pour savoir si un int est signé, on demande numeric_limits<int>::is_signed
La réponse sera en booléen, c'est à dire 0 pour faux
et 1 pour vrai.
- Si on veut que la réponse s'affiche dans un type particulier, il
faut le préciser avant. Par exemple, pour afficher la valeur maximale
d'un char sous forme de chiffre : (int)numeric_limits<char>::max()
1.3 Opérateur sizeof >> vers le sommaire
Cet opérateur permet de connaître la taille non
pas en bits mais en octets. Voici un code d'exemple, exécutez le pour
comprendre :
A l'exécution, vous obtiendrez :
On voit qu'un int est codé sur 4 octects. Puisque essai
possède 10 cases de type char, et que char
est codé sur un octect, alors, sizeof(essai) renvoit
10. Voici un autre exemple :
L'exécution du programme nous donne le résultat
ci-dessous :
Il y a 10*3 cases donc 30 cases. Puisque char
est codé sur un octet, alors 30*1=30.
Récapitulatif sur l'opérateur
sizeof :
- La fonction sizeof() renvoit la taile en octet d'un
élément. Par exemple, sizeof(char) donne
1 car char n'est codé que sur un octet. Si on a
int exemple[2][3], sizeof(exemple)
donnera 24 car 2*3=6 et int étant codé sur
4 octects 6*4=24.
1.4 Les pointeurs >> vers le sommaire
On s'en sert surtout en algorithme. C'est "théoriquement"
important à savoir, mais pratiquement ce n'est pas vital. Comme vous
le savez, toutes les variables occupent de la place en mémoire. Pour
retrouver leur valeur, elles ont des adresses en mémoire : le pointeur
renvoit à ses adresses en mémoires, qui elles-mêment renvoient
à la valeur de la variable. Pour déclarer un pointeur, on utilise
un astéristique * de la façon suivante :
int* exemple;
Ceci est un pointeur de int. L'astéristique
se trouve à côté du type de pointeur, comme nous pouvons
encore le voir avec les exemples suivants :
double* exemple2;
char* exemple3;
Si vous êtes vraiment tordus, vous pouvez même faire
des pointeurs de pointeurs :
char** tordu;
Enfin, le but existentiel d'un pointeur est de pointer. Pour
attribuer au pointeur l'élément vers lequel il doit pointer,
on utilise "l'indirection" décrite par Bjarne Stroustrup
comme "l'opération fondamentale" qui consiste à faire
"référence à l'objet vers lequel est dirigé
le pointeur". Appelez cela l'adressage, ce sera plus simple. Pour cette
opération on utilise &, par exemple :
int variable(4);
int* pointeur=&variable;
Attention : pointeur ne renvoit pas la valeur
de variable mais son adresse. A présent, créez
un programme qui affiche la valeur d'une variable de votre choix et son adresse
en mémoire. Le code que je propose est le suivant :
Le résultat du programme est celui ci-dessous :
Vous remarquerez que l'adresse en mémoire est exprimée sous forme héxadécimale, en raison de 0x et de la combinaison lettres/chiffres.
Récapitulatif sur les pointeurs
:
- Une variable est stockée en mémoire. Le pointeur indique son
adresse en mémoire.
- Pour déclarer un objet de type pointeur, on utilise un astérisque
* à la fin du type qu'il pointe. Par exemple,
pelican est un pointeur de char :
char* pelican;
- Pour pointer une variable, c'est-à-dire vers son adresse mémoire,
on utilise &. Par exemple, &otarie;
pointe vers l'adresse en mémoire de la variable otarie.
On peut aussi faire char* pelican=&otarie;
1.5 Opérations élémentaires de calcul d'adresse >> vers le sommaire
Les pointeurs peuvent pointer la quasi-totalité des éléments
que vous connaissez, et particulièrement les tableaux. Créez
un tableau de type int de 3 éléments et affichez-en les adresses
en mémoire. Je propose le code suivant :
On obtient ce résultat :
Or, regardons les deux derniers chiffres, qui sont les seuls à varier : EC, F0, F4. Le lien est visible : on rajoute 4 pour passer à l'élément suivant. Si vous ne savez pas compter en héxadécimal, voici un tableau de correspondance :
|
Nombre en base 10 (décimal, courant)
|
Equivalent en hexadecimale
|
|
1
|
1
|
|
2
|
2
|
|
3
|
3
|
|
4
|
4
|
|
5
|
5
|
|
6
|
6
|
|
7
|
7
|
|
8
|
8
|
|
9
|
9
|
|
10
|
A
|
|
11
|
B
|
|
12
|
C
|
|
13
|
D
|
|
14
|
E
|
|
15
|
F
|
On continu après avec 16=10, 17=11, etc. etc. Donc, faites l'opération
EC+4. Si vous n'y arrivez pas, voici un tableau :
|
Ajout à EC
|
+1
|
+2
|
+3
|
+4
|
|
Résultat
|
ED
|
EE
|
EF
|
F0
|
Vous voyez ainsi que EC+4=F0 et F0+4=F4. Or, nous sommes dans un tableau
de int. Le chiffre 4 vous rappelles-t-il quelque chose ? Il s'agit de la taille
en octet d'un int. En effet, sizeof(int)=4. Ainsi, si
vous avez un élément d'un tableau, en ajoutant ou soustrayant
la taille en octet de son type, vous pouvez obtenir l'adresse d'autres éléments.
Nous allons faire un petit exercice d'entraînement. Nous avons int
tableau[5];, voici l'adresse de tableau[2] :
![]()
A partir de là, calculez l'adresse de tableau[1],
tableau[0], tableau[3] et tableau
[4].
La solution est :
- Adresse de tableau[1] : 0065FDC4-4 = 0065FDC0
- Adresse de tableau[0] : 0065FDC0 - 4 = 0065FDBC
- Adresse de tableau[3] : 0065FDC4+4= 0065FDC8
- Adresse de tableau[4] : 0065FDC8+4= 0065FDCC
Il est possible de soustraire deux pointeurs naturellement, comme dans le
code ci-dessous :
int tableau[5];
cout << &tableau[3]-&tableau[2];
Cependant, le résultat affiché ne correspondra pas à la différence d'adressage ! Il correspondra à la différence d'emplacement dans le tableau, soit 3-2=1.
L'opération d'addition de pointeurs est, quant à elle, impossible.
Récapitulatif sur les opérations élémentaires
de calcul d'adresse :
- Si, dans un tableau, on connait l'adresse de l'un des éléments,
alors on peut connaître les éléments précédents
ou suivants ou soustrayant ou additionnant la taille en octet du type de tableau.
Par exemple, si le tableau est de type int, on soustraira
4 pour obtenir l'élément précédent et on aditionnera
4 pour obtenir l'élément suivant.
- La soustraction de deux pointeurs donne l'écart entre les pointeurs
dans le tableau mais pas en adresse. Par exemple, &tableau[7]-&tableau[5]=2.
- L'addition de deux pointeurs est impossible.
1.6 Initialisations atypiques de tableaux >> vers le sommaire
Il est possible de créer des tableaux sans entrer leur taille mais
en entrant uniquement leur contenu. Voici un code d'exemple :
D'après vous, quel sera le message qui apparaîtra à l'exécution
du programme ? Les deux codes suivants sont équivalents :
int tableau[]={1,2,3,4,5};
et
int tableau[5];
for(int i(0);i<5;i++)
{
tableau[i]=i+1;
}
Partant de ce fait, on sait que nous avons fabriqué un tableau de
5 éléments. Puisque ces éléments sont des int,
alors la taille du tableau est de 5*4 soit 20 bits et le message affiché
sera "Le tableau fait 20 bits." Pour créer un tableau avec
des valeurs numériques sans entrer sa taille, on donne immédiatement
={}; avec les valeurs successives entre accolades. Cependant, pour des caractères,
on utilisera des guillements, par exemple :
char exemple[]="bonjour";
Un tableau de caractère, appelé "chaîne de caractères",
se finit toujours par '\0' qui indique la fin de la chaîne. Ce caractère
est hors de notre contrôle et placé automatiquement. Ainsi, puisque
"bonjour" fait 7 lettres, on rajoute 1 lettre qui est '\0' pour
avoir le total du contenu de la chaîne, soit 8 lettres. Un char
valant 1 bits, on peut donc s'attendre à ce que le code suivant affiche
"Le tableau fait 8 bits" :
Dans le cadre des chaînes de caractères, deux ensembles de guillements
suivis sont regroupés. Par exemple, les deux codes suivants sont équivalents
:
char tableau[]="Bonjour";
et
char tableau[]="Bon" "jour";
Si vous souhaitez initialiser des tableaux de cette manière, je vous conseilles de laisser un commentaire en dessous de la ligne de création du tableau, indiquant la taille de celui-ci. Il n'est pas en effet souhaitable de perdre du temps à compter les caractères ou les nombres...
Récapitulatif sur les initialisations atypiques
de tableaux :
- On peut créer un tableau sans indiquer sa taille mais en lui attribuant
directement les valeurs qu'il contiendra. Sa taille sera alors égale
au nombre de valeurs qu'on lui a attribué. Par exemple, int
tableau[]={1,2,3}; vient de faire la déclaration int
tableau[3]; tout en remplissant le tableau.
- Dans le cas de valeurs numériques, elles sont entre accolades et
séparées par des virgules.
- Dans le cas de caractères, ils sont entre guillements. Par exemple,
char tableau[]="bonjour"; La taille d'un tableau
de caractères, aussi appelée chaîne de caractères,
est égale au nombre de caractères contenus + 1, pour le caractère
automatique '\0' qui indique la fin de chaîne.
- Deux séries de guillements suivies sont regroupées. Exemple
: char tableau[]="bonjour"; est égal
à char tableau[]="bon""jour";
1.7 Les structures >> vers le sommaire
Vous pouvez créer des espèces d'objets que l'on appelle des
structures. Vous pouvez en rencontrer dans certains programmes, généralement
de bas niveau, il est donc utile d'en connaître le fonctionnement. Cependant,
quand vous aurez appris les classes vous privilégierez ces dernières.
Une structure se déclare par struct suivit du nom
que vous lui donnez. Ensuite, entre accolade, vous définissez un certain
nombre de variables associées à cette structure. Voici un exemple
:
struct human{
int matricule;
int code_postal;
short age;
bool sexe;
};
Nous avons créée une structure appelée human
et possédant plusieurs paramètres : matricule,
code_postal, age, sexe.
Nous allons maintenant fabriquer un objet utilisant cette structure. Pour
cela il faut donner le nom de la structure suivie du nom que nous attribuons
à l'objet, par exemple :
human henry;
henry est un objet de type human,
et il possède donc les paramètres matricule,
code_postal, age, sexe.
Pour accéder à ces paramètres on utilise l'opérateur
".", voici un exemple :
henry.matricule=32;
cout << "Le matricule de l'objet est " << henry.matricule
<< "\n";
Si votre objet peut prendre un nom, il y a deux cas :
- Soit le nom ne fait pas partie d'une liste, auquel cas vous utiliserez des
char
- Soit il fait partie d'une lise, et vous mettez à disposition un int
avec, en commentaire, une équivalence entre les valeurs et le nombres
A présent, créez un objet dont les paramètres sont prix,
masse et matiere ; ensuite, attribuez-lui des valeurs et affichez-les. Le
code est le suivant :
Récapitulatif sur les structures :
- Pour créer une structure, on utilise struct suivie
du nom qu'on donne à la structure. Après, entre accolades, on
met les paramètres de la structure. Un exemple :
struct achat{
short nombre;
double prix_unitaire;
};
- Pour créer un objet d'une certaine structure, on marque le nom de
la structure puis celui de l'objet, exemple :
achat exemple;
- Les paramètres de l'objet sont accessibles par l'opérateur
., par exemple : exemple.nombre=3;
- Si votre objet peut prendre un nom parmi plusieurs possibles, faites un
int dont les valeurs auront une équivalence avec
le nom indiquée en commentaires. Sinon, utilisez des caractères.
1.8 Utilisation de la bibliohèque ctype >> vers le sommaire
Cette bibliothèque permet de faire des tests sur des char
pour voir s'ils contiennent des espaces, de la ponctuation, des majuscules,
etc. etc. Vous pouvez faire exactement le même test en une ligne de
vérification, mais puisqu'il y a une bibliothèque pour ça,
autant la connaître. On la déclare simplement par #include
<ctype.h>, elle n'a besoin de rien de plus. La fonction ispunct
permet de vérifier s'il y a des signes de ponctuation ; s'il n'y en
a pas, elle renvoit 0, et sinon une autre valeur. Voici un code d'exemple
:
Voici le test avec la lettre 'g' :
Et le test avec un signe de ponctuation :
Récapitulatif sur l'utilisation de la bibliothèque
ctype :
- On la déclare uniquement avec #include <ctype.h>
- Ses fonctions vérifient si un caractère contient un certain
type. S'il ne contient pas le type en question, la fonction renvoit 0 et sinon
elle renvoit un autre nombre.
|
Fonction
|
Vérifications
|
ispunct |
ponctuations
|
isalpha |
lettres, majuscules et minuscules
|
isupper |
lettres majuscules
|
islower |
lettres minuscules
|
isdigit |
nombre décimal : de 0
à 9
|
isxdigit |
nombre héxadécimal
: 0 à 9, a à f et A à F
|
isspace |
espace
|
iscntrl |
caractères de contrôles
|
isalnum |
lettres ou nombres
|
isprint |
caractère imprimable
ascii
|
isgraph |
lettres, nombre ou ponctuation
|
Aller au tutorial suivant (tutorial 7) >>