L'algorithme est une sequence d'actions qui décrivent pas-à-pas la résolution de problèmes.
Par exemple :
Certains algorithmes vous sont déjà proposés couramment dans des livres de recettes
Les algorithmes informatiques sont du même ordre que les algorithmes de la vie courante, mais les objets manipulés sont immatériels et représentés par des données numériques
De plus, un algorithme calculatoire pourrait être exprimé dans un langage naturel, mais les langages que nous utilisont peuvent être ambigus ou manquent de précision et de rigueur.
prendre le rayon, calculer la circonferenceAinsi des notations plus strictes ont été établies pour écrire un algorithme, parmi lesquelles :
Algorithme calculerCirconference
Donnees
Constante
PI : reel <-- 3.1415927
Variables
r : entier // rayon, saisi
circ : reel // circonférence, calculée
Debut Traitement
lire r
circ <-- 2 * PI * r
ecrire circ
Fin Traitement
Les langages de programmation sont apparus avec l'ordinateur, dans les années 1950. Les langages de programmation ont été conçus afin de répondre :
| génération | caractéristiques | exemples |
|---|---|---|
| L1G, Langage de 1ère Génération | Correspond au langage machine : chaque instruction machine est codée sous forme binaire, une succession de 0 et de 1, sous forme plus compacte en hexadécimal | C’est le langage de base des microprocesseurs composé d’un jeu d’instructions.
Voilà par exemple une séquence d'instructions codées en binaire :
0010 0100 0001 0000 0000 0000 0000 0011 0010 0100 0001 0001 0000 0000 0000 0101 0000 0010 0001 0001 1000 0000 0010 0000ou pour en "simplifier" l'écriture, codage en hexadécimal : 0x24100003 0x24110005 0x02118020 |
| L2G : Langages de 2nde génération | à chaque instruction machine, on associe un code mnémonique, plus simple à retenir qu’une suite de 0 et de 1. | Le langage Assembleur (spécifique à une architecture donnée) est plus lisible :
li $s0,3 # charger la valeur 3 dans reg. $s0 li $s1,5 # charger la valeur 5 dans reg. $s1 add $s0,$s0,$s1 # additionner $s0 et $s1 , ranger dans $s0(cf. simulateur MARS |
| L3G :Langage de 3ème génération | La syntaxe des L3G se rapproche beaucoup plus du langage naturel et du pseudo-code. On parle alors de langage de haut niveau. Des compilateurs assurent la traduction en langage machine. | Cobol, C, Pascal, C++, Java, C#, Visual Basic, Ada, etc.
Exemple en Cobol87 :
compute total = total + montant.Exemple en C90 : total+=montant; |
| L4G : Langages de 4ème génération | La syntaxe est de plus haut niveau encore : quelques (macros)instructions suffisent à construire des programmes complets de manière très rapide. On parle de RAD pour Rapid Application Development. | W-langage, le langage de Windev / ICL Application Master : L4G mainframes ICL) |
| paradigme | caractéristique | Exemples de langages |
|---|---|---|
| PROGRAMMATION IMPERATIVE des instructions manipulent des données constituant l’état du programme (effets de bord) C, VB, PHP, C++, etc. | ||
| Programmation procédurale | On conçoit un programme comme un ensemble de procédures et fonctions qui vont modifier les variables d’état du programme. | C, Cobol, Pascal, Basic Fortran PHP C++, Cobol, Pascal, Java, C#, Visual Basic Bash |
| Programmation à objets | On associe des variables, des procédures et des fonctions pour former une classe d’objets ; un programme sera constitué d’un ensemble de ces classes. A l’exécution, le programme créé des objets (instanciation) qui s’envoient des messages (appels de méthodes d’instances) | Eiffel, Smalltalk
Java Avec possibilité de créer des classes d’objets : C++, Cobol Objet,Pascal Objet, C#, VB.net, PHP5, etc. |
| PROGRAMMATION FONCTIONNELLE Des fonctions manipulent des ensembles de données constitués par d’autres fonctions (pas d’effet de bord) Scheme, Lisp, XSLT | ||
| PROGRAMMATION LOGIQUE Un programme est constitué d'une suite de règles et de faits, et d'un "moteur d’inférence" va déduire des conclusions à partir de ces règles appliquées aux faits Prolog | ||
| Mode exéc. | caractéristique | exemples |
|---|---|---|
| interprétés | Les instructions du programme source sont exécutées par un programme interpréteur : celui-ci lit chaque instruction et la traduit en instruction machine (au fur et à mesure) L’exécution est (relativement) lente | Logo PHP Bash Javascript, VBscript |
| compilés | Le programme source est compilé L’exécution est très rapide | C, C++, Pascal |
| semi-compilés | Le source est traduit en un code semi-compilé (on parle de bytecode - non directement exécutable par la machine). Un programme particulier, appelé "machine virtuelle" (en anglais : VM, Virtual Machine) se charge de convertir le bytecode en langage machine au moment de l’exécution. Un "ramasse-miettes" (en anglais garbage collector) nettoie la mémoire L’exécution est rapide | Java C#, VB.net, etc. |
D'autres composants interviennent dans l'exécution, parmi lesquels la mémoire de masse matérialisée le plus souvent par un disque dur. Celui-ci stocke de manière permanent programmes installées et données enregistrées sous forme de fichiers.
Les unités de capacité utilisées en informatique sont les suivantes :
| système d'unité classique | système d'unité informatique (depuis 2008) | ||
|---|---|---|---|
| ko, kilo octet | 1000 o, 103 octets | kio, kibi octet | 1024 o, 210 octets |
| Mo, Mega octet | 1000 000 o, 106 octets | Mio, Mebi octet | 1 048 576 o, 220 octets |
| Go, Giga octet | 1000 000 000 o, 109 octets | Gio, Gibi octet | 1 073 741 824 o, 230 octets |
| To, Tera octet | 1000 000 000 000 o, 1012 octets | Tio, Tebi octet | 1 099 511 627 776 o, 240 octets |
La capacité de la mémoire vive est de l'ordre de 4Go, soit environ 4.000.000.000 octets. L'octet est divisé en 8 éléments binaires (BInary digiT, bit). Pour avoir un ordre d'idée :
Le programmeur devra avoir en tête ces critères afin de produire des applications de qualité (Cf. CERT C++ Secure Coding Standard , recommandations pour l'écriture de programmes sûrs, issues des CERT (Computer Emergency Response Team) : centres d'alerte et de réaction aux attaques informatiques).
Le langage C a été conçu par deux chercheurs des laboratoires Bell (Brian Kernighan et Dennis Ritchie – K & R) dans les années 1970 (livre de référence "The C programming Language", 1978). Il est normalisé au début des années 1990 : il devient ISO C 90 (appelé aussi ANSI C90), puis des améliorations sont inclues dans la version ISO C 99 (afin d’assurer, autant que possible, la portabilité de C vers C++)
Le C est un langage de haut niveau intégrant des types de données de base, des structures de contrôles et des structures de données. Des bibliothèques donnent accès aux fonctions du système d’exploitation : entrées et sorties (clavier/écran, fichiers, etc.), fonctions mathématiques, etc.
Le langage C++ est une extension du langage C (Bjarne Stroustrup) afin de prendre en compte les évolutions en terme de "paradigmes de programmation" : le paradigme objet est en effet aujourd’hui la référence en conception d’applications. Le langage C++ inclut donc de nouvelles bibliothèques de classes (non compatibles avec le C).La portabilité du langage C/C++ ("pouvoir compiler un source aussi bien sous Linux que sous Windows", par exemple), est donc toute relative, de nombreux compilateurs incorporant en effet des bibliothèques spécifiques. Il faut donc s’attacher à n’utiliser que les éléments définis dans les standards ou des bibliothèques tierces portables.
C++ a évolué indépendamment de C depuis sa création. Ainsi différentes normes se sont succédées : C++98 (la première) et C++11 (la dernière en date) et la compatibilité ascendante est assurée (un programme C++98 est aussi conforme à la norme C++11, mais pas l'inverse !). De plus, il existe un décalage entre la norme et son implémentation dans les compilateurs : ainsi toutes les améliorations de la version C++11 ne sont pas mises en oeuvre dans tous les compilateurs.
/* commentaires bloc,
sur plusieurs
lignes */
// commentaire sur une ligne
.... // commentaire de fin de ligne
Il est souvent utile d’ajouter des commentaires pour apporter des informations supplémentaires au sujet de données utilisées ou de traitements effectués.
a = b + f(5)Pour que cet exemple puisse avoir un sens, il est indispensable de décrire les objets présents : les identifier et définir leur nature - le type de donnée ou domaine de définition - :
float a; int b = 7; float f(int);soit :
Les objets sont des emplacements identifiés par un nom et associés à un espace de la mémoire (à une certaine adresse de la RAM) permettant ainsi le stockage de leur contenu.
En C++, l'identifiant doit commencer par une lettre, il peut contenir des lettres, chiffres et le caractère '_'. Il doit être clair mais concis, ne doit pas faire partie des mots réservés du langage C++.
(+)
alignas, alignof, and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, char, char16_t, char32_t, class, compl, const, constexpr, const_cast, continue, decltype, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, noexcept, not, not_eq, nullptr, operator, or, or_eq, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_assert, static_cast, struct, switch, template, this, thread_local, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while, xor,
Le langage C++ est sensible à la casse des caractères (lettres majuscules et minuscules) : 'carnaval' est différent de 'carnavaL'.
Toute donnée doit être déclarée avant d'être utilisée.
| type | espace occupé | plage de valeurs | |
|---|---|---|---|
| signed (par défaut) | char | 1 octet | [-128, +127] |
| short int | 2 octets (au moins 16 bits) | [-32768,+32767] | |
| int | 4 octets (au moins 16 bits, 32 bits généralement) | [-2.147.483.648, +2.147.483.647] | |
| long int | 4 octets(au moins 32 bits) | Idem. | |
| long long int | 8 octets (au moins 64 bits) | [-9.223.372.036.854.775.808, +9.223.372.036.854.775.807] | |
| unsigned | char | 1 octet | [0, +255] |
| short int | 2 octets (au moins 16 bits) | [0,+65535] | |
| int | 4 octets (au moins 16 bits, 32 bits généralement) | [0, 4.294.967.295] | |
| long int | 4 octets (au moins 32 bits) | Idem. | |
| long long int | 8 octets (au moins 64 bits) | [0, +18.446.744.073.709.551.615} | |
Remarque : Les valeurs signées sont codées selon le complément à 2 (complément à 1, plus 1, ce codage rend les opérations arithmétiques plus simples).
L’inclusion du fichier "climits" (#include <climits>) donne accès à des constantes système fournissant les valeurs limites de chacun des types :
Exemple de valeurs littérales entières :
Le 4 juin 1996, un débordement d'entier (capacité d'un nombre entier trop petite pour la valeur reçue) provoque l'echec du lancement et l'auto-destruction du lanceur après 37 secondes de vol. L'information de la msure d'accélération était donnée avec une valeur en 64 bits mais reçue et traitée dans un registre mémoire de 16 bits...
| type | espace occupé | Plage de valeurs permises |
|---|---|---|
| float | 4 octets | 32 bits : 1 bit de signe, 8 bits d'exposant, 23 bits de mantisse [1.175494e-038, 3.402823e+038 ], Simple précision |
| double | 8 octets | 64 bits : 1 bit de signe, 11 bits d'exposant, 52 bits de mantisse [2.225074e-308, 1.797693e+308 ], Double précision |
| long double | 12/16 octets | 80/116 bits : 1 bit de signe, 15 bits d'exposant, 64/112 bits de mantisse, Quadruple précision |
Remarque : les implémentations peuvent varier en fonction de l'architecture matérielle (x86-x86-64, Sparc, PowerPC, etc.) et de l'implémentation du compilateur sur cette architecture.
Exemple de valeurs littérales réelles :
La codification ASCII définit une table de correspondance entre la valeur numérique d'un octet et le caractère qui lui est associé. Par exemple une valeur binaire de '0100 0001' (soit 65 en décimal) correspond à la lettre 'A' :
| type | espace occupé | Plage de valeurs permises |
|---|---|---|
| signed char | 1 octets | 1+7 bits : lettres, chiffres, caractères de ponctuation, etc. |
| unsigned char | 1 octets | 8 bits : lettres, chiffres, caractères de ponctuation, etc. |
| type | espace occupé | Plage de valeurs permises |
|---|---|---|
| bool | 1 octets | true (1), false (0) |
Les types numériques entiers peuvent également être utilisés comme des booléens (et vice-versa) pour représenter les valeurs true ou false :
Un pointeur est un type numérique identifié susceptible de contenir l'adresse d'un autre objet stocké dans la mémoire vive (un pointeur faire référence, pointe, un autre objet et son contenu).
(+)
La taille d'un pointeur dépend de l'architecture matérielle, du compilateur et elle détermine sa capacité d'adressage. Les pointeurs ont en général une taille de 32 bits (leur permettant l'adressage de 4.294.967.295 emplacements mémoire, 232).(cf. chapitre relatif aux pointeurs).
Le transtypage correspond à la tentative de changement temporaire du type d'une donnée dans une expression de calcul. Il est réalisé automatiquement lorsqu'il s'agit d'une promotion de type (d'un plus petit vers un plus grand en terme de capacité de stockage), par exemple short vers int (un int peut contenir une valeur de type short, mais l'inverse n'est pas vrai).
Il doit être parfois demandé explicitement. Par exemple, la division de 2 entiers donne une valeur entière comme résultat : ici on transtype (cast) dividende, un entier, en double afin que le résultat de l'opération conserve la partie décimale :
int dividende = 7; int diviseur = 3; double resultat ; resultat = static cast<double>(dividende) / diviseur ;ou bien à la mode C :
int dividende = 7; int diviseur = 3; double resultat ; resultat = ((double)dividende) / diviseur ;
L'instruction typedef permet de définir un alias sur un type existant. Les déclarations peuvent ensuite déclarer des variables de ce type :
typedef type alias; typedef defType alias;où :
type unsigned int distance_t; distance_t d1, d2; // déclaration de 2 variables de ce type(plus)
using alias = type; using alias = defType;où :
using distance_t = unsigned int; distance_t d1, d2; // déclaration de 2 variables de ce type
type idVar; type idVar = valInit;où :
bool b; char c; short i; unsigned int length; float f;Il est possible (et souhaitable) de donner une valeur initiale à toute variable déclarée :
bool b = true; char c = 'a'; short i = 65; unsigned int length = 65; float f = 65.0;
const type idConst; const type idConst = init;où :
const char CONTINUER = 'c'; const unsigned int MAX_LENGTH = +200000; const double PI = 3.1415927;Il est également possible de définir des constantes 'à la mode C', en utilisant la directive de compilation #define.
#define CONTINUER 'c' #define MAX_LENGTH +200000 #define PI 3.1415927
enum idEnum{ NOM1, NOM2, ...};
enum idEnum{ NOM1 = valeur1, NOM2 = valeur2, ...};
où :
enum genre{ MASCULIN = 1, FEMININ = 2};
enum feu{ ROUGE, ORANGE, VERT};
enum booleen{ FAUX = 0, VRAI = 1};
enum carte{ CARREAU = 1, COEUR = 2, TREFLE = 3, PIQUE = 4};
// déclaration d'une variable de ce type
carte uneCarte = COEUR;
feu unFeu = ROUGE;
A ces noms de constantes, on affecte un nombre entier qui correspond généralement (sauf indication d'une valeur particulière) à la position de la constante dans la liste : ainsi ROUGE a pour valeur 0, ORANGE a pour valeur 1 et VERT a pour valeur 2.
string ch1; // chaine vide
string ch2("un texte");
string ch3(10,'-'); // contient 10 -
string ch4(ch2,3,5); // contient "texte"
string ch5(ch2,3,5); // contient "texte"
// affectation d'une nouvelle valeur :
ch1 = "ceci est une chaine de caractères";
Les chaines de caractères peuvent également être représentées à l'aide de tableaux de caractères (comme en C).
Utilisez des parentheses pour definir clairement la priorite des opérations à effectuer dans une expression de calcul.
Les valeurs resultant de l’evaluation d’une expression sont perdues, a moins d’etre conservees : c’est l’objet de l’opération d’affectation.
lvalue = rvalue;où
int i, j; i = 0; i = 1; i = j = 2;L'opérateur d'affectation renvoie la valeur qui a été affectée, d'où la possibilité d'affectations en cascade.
Les expression de calcul numériques fournissent un résultat de type numérique.
(operande operateur operande)où
| opérateur | description | exemple |
|---|---|---|
| + | a plus b | (a + b) |
| - | a moins b | (a - b) |
| * | a multiplié par b | (a * b) |
| / | a divisé par b | (a / b) |
| % | a modulo b | (a % b) |
(2 + 12); (i * 2); (i + 5) * 2); (i / 3);Ces expressions sont calculées, mais leur résultat est perdu ! Il est souvent nécessaire de conserver ces résultats intermédiaires en utilisant l'opération d'affectation (sauf dans le cas de calculs intermédiaires dans une expression plus complexe) :
int i; i = (2 + 12); i = (i * 2); i = (i + 5) * 2; i = (i / 3);La division de nombres entiers donne comme résultat un quotient entier. Le reste peut être obtenu grâce à l'opérateur modulo : %
int i = 2; int j = 5; int q = 0; int r = 0; q = j / i; // q vaut 2 r = j % i; // r vaut 1
| opérateur | exemple | équivalent à |
|---|---|---|
| += | a+=b; | a=a+b; |
| -= | a-=b; | a=a-b; |
| *= | a*=b; | a=a*b; |
| /= | a/=b; | a=a/b; |
| opérateur | exemple | équivalent à |
|---|---|---|
| ++ | a++ | utilise la valeur de a puis l'incrémente |
| ++a | incrémente a puis utilise sa valeur | |
| -- | a-- | utilise la valeur de a puis la décrémente |
| --a | décrémente a puis utilise sa valeur |
Les expressions de calcul logiques fournissent un résultat de type booléen.
(operande operateur operande)où
| opérateur | description | exemple |
|---|---|---|
| == | a est égal à b ? | (a == b) |
| != | a est différent de b ? | (a != b) |
| < | a est plus petit que b ? | (a < b) |
| <= | a est plus petit ou égal à b ? | (a <= b) |
| > | a est plus grand que b ? | (a > b) |
| >= | a est plus grand ou égal à b ? | (a >= b) |
int i = 2; int j = 5; bool t = false; t = (i < j); // t vaut true
int a = 2; int b = 2; int c = 2; bool test; test = ( a < b < c ) ;// test vaut VRAI, FAUX est plutôt attendu test = ( a == b == c ) ;// test vaut FAUX, VRAI est attenduExemple à utiliser :
int a = 2; int b = 2; int c = 2; bool test; test = ( a < b && b < c ) ; // FAUX : OK test = ( a == b && b == c ) ; // VRAI : OK
| opérateur | description | exemple |
|---|---|---|
| && | condition1 ET condition2 ? | ((a == b) && (b == c)) |
| || | condition1 OU condition2 ? | ((a == b) || (b == c)) |
| ! | non condition1 ? | !(a < b) |
int age; int note; bool resultat = false; ... resultat = ((age >= 18) && (note > 10)) // VRAI si age >= 18 ET note > 10 resultat = ((age >= 18) || (note > 10)) // VRAI si age >= 18 OU note > 10
Précisions : Les conditions sont évaluées de la gauche vers la droite
sizeof(type); sizeof(expression); sizeof idVar;où
char c; size_t taille; taille = sizeof c; taille = sizeof(int); taille = sizeof(2*4);Le type size_t est une redéfinition de unsigned int.
&idVaroù
int i; int * ptri = &i;
Il est impératif d'initialiser les pointeurs
L'opérateur de déréférentement (ou d'indirection) * donne accès au contenu situé à une adresse mémoire pointée.*idPtroù
*ptri = 2; *(&i) = 2;soit : le contenu à l'adresse mémoire pointée par ptr1, ou le contenu à l'adresse de i, prend la valeur 2.
| flux | description |
|---|---|
| cin | flux d'entrée standard : clavier |
| cout | flux de sortie standard : écran (console) |
| cerr | flux de sortie des erreurs : écran (console par défaut) |
| clog | flux de sortie des journalisations : écran (console par défaut) |
cout << donnees;
int n1 = 1, n2 = 2; double f1 = 3.1415927, f2 = 9.81, f3 = 98.6; // pi m/s2 37deg celsius char c1 = 'a', c2 = 'z'; string ch1 ="hello", ch2 = "world"; cout << n1 << n2 << f1 << f2 << f3 << c1 << c2 << ch1 << ch2 << endl;résultat :
123.141599.8198.6azhelloworldExemple setw :
cout << setfill('.'); // pour montrer les espacements
cout << setw(10) << n1 << setw(10)<< n2 << setw(10)<< f1 << setw(10)<< f2 << setw(10)<< f3 << endl;
cout << setw(4) << c1 << setw(4)<< c2 << setw(8)<< ch1 << setw(8) <<ch2 << endl;
Résultat :
.........1.........2...3.14159......9.81......98.6 ...a...z...hello...worldExemple setfill :
cout << setw(40) << setfill('-') << '-' << endl;
cout << setfill('*');
cout << setw(10) << n1 << setw(10)<< n2 << setw(10)<< f1 << setw(10)<< f2 << endl;
cout << setfill(' ');
cout << setw(4) << c1 << setw(4)<< c2 << setw(8)<< ch1 << setw(8) <<ch2 << endl;
Résultat :
---------------------------------------- *********1*********2***3.14159******9.81 a z hello worldExemple setprecision :
cout << setprecision(2); cout << setw(10)<< f1 << setw(10)<< f2 << setw(10)<< f3 << endl;Résultat :
3.1 9.8 99
a z hello world
Exemple left :
cout << left; cout << setw(4) << c1 << setw(4)<< c2 << setw(8)<< ch1 << setw(8) <<ch2 << endl;Résultat :
a z hello world
cin >> variable;L'extraction s'arrête au premier espace rencontré (ou tabulation).
getline(cin,variableChaine);Une fois la ligne récupérée, il est possible de convertir la chaine en nombre, par exemple.
La fonction clear efface d'indicateur d'erreur d'une fonction.
La fonction ignore efface un nombre de caractères qui ont été saisis (qui restent dans le buffer clavier), afin de permettre une nouvelle saisie par exemple.
Exemple de captation d'erreur de saisie :
/* demander la saisie d'un nombre entier*/
cout << "entrer un nombre entier:";
while (!(cin >> nombre))
{ /* tant que cin ne se passe pas bien */
cout << "c'est pas bon, recommencer :";
cin.clear(); // efface l'erreur de cin
cin.ignore(256,'\n'); // ignorer les prochains 256 car. ou jusqu'au prochain retour ligne
}
Exemple de captation d'erreur de saisie :
if (cin >> choix) {
// ok
} else if (cin.bad()) {
// error d'entrées/sorties
} else if (cin.eof()) {
// fin de flux (et erreur de format)
} else {
// pb de format
}
Une structure conditionnelle offre une rupture dans l'exécution en séquence des instructions d'un programme. Elle permet, si une condition est vérifiée, l'exécution d'un bloc d'instructions; dans le cas contraire, l'exécution d'un bloc alternatif peut être proposé. La condition est exprimée sous forme d'une expression logique.
| de la séquence : |
| au choix : |
![]() |
if (condition)
{
// bloc d'instructions exécuté
// si la condition est vraie
}
où :
int i = 1;
int j = 2;
int k;
if (i < k)
{ k = i;}
int i;
int max;
// ...
if ( (i >= 0 && (++i) <= max) ) {
// ...
}
Exemple à utiliser :
int i;
int max;
// ...
if ( (i >= 0 && (i + 1) <= max) ) {
i++;
// ...
}
if (condition)
{
// bloc d'instructions exécuté
// si la condition est vraie
}
else
{
// bloc d'instructions exécuté
// si la condition n'est pas vraie
}
où :
int i = 1;
int j = 2;
int k;
if (i < k)
{ k = i;}
else
{ k = j;}
if (condition1)
{
// bloc d'instructions exécuté
// si la 1ère condition est vraie
}
else if (condition2)
{
// bloc d'instructions exécuté
// si la 2ème condition est vraie
}
... etc...
else
{
// bloc d'instructions exécuté
// si aucune des conditions n'est satisfaite
}
où :
int mois;
cin >> mois;
if (mois == 1)
{ printf("janvier");}
else if (mois == 2)
{ printf("fevrier");}
...
else if (mois == 12)
{ printf("decembre");}
else
{ printf("mois incorrect");}
condition ? resultat1 : resultat2 ;où
int i,
j;
...//calculs qui modifient la valeur de i...
...
j = (i < 0) ? (i * -1) : i;
cette expression est équivalente à :
if (i < 0) {j = (i * -1);} else {j = i;}
switch (intExpr)
{
case valeur1 :
// liste d'instructions exécutées
// si intExpr = valeur1
break;
case valeur2 :
case valeur3 :
// liste d'instructions exécutées
// si intExpr = valeur2 ou intExpr = valeur3
break;
default :
// liste d'instructions exécutées
// si aucun des cas n'a été satisfait
break;
} // fin du switch
où :
int m = 0;
int s = 0;
// traitement qui modifie la valeur de m
...
switch (m)
{
case 1:
case 2:
case 3: s = 12; break;
case 4:
case 5:
case 6: s = 20; break;
default: s = 0; break;
}
while (condition)
{
//instructions si la condition est vraie et tant qu'elle reste vraie
} // fin du while
où :
int i = 0; // initialiser
while (i < 10) // tester
{
// instructions exécutée si la condition est vraie
// et tant qu'elle reste vraie
i++;
} // fin du while
do
{
// instructions (exécutées au moins une fois)
} while (condition);
où :
int i = 0;
do
{
//instructions si la condition est vraie et tant qu'elle reste vraie
i++;
} while (i < 10);
for(initialiser; condition; modifier)
{
// instructions
} // fin du for
où :
initialiser;
while (tester)
{
// instructions
modifier;
} // fin du while
int i = 0;
for (i=0;i < 10;i++)
{
//instructions si la condition est vraie et tant qu'elle reste vraie
};
int i = 0;
while (i < 10)
{
//instructions si la condition est vraie et tant qu'elle reste vraie
i++;
}
break;Exemple :
int i = 0;
for (i < 10)
{
// instructions
if (i==v) break; // si i est égal à la variable v
// instructions
i++;
}
continue;Exemple :
int sum = 0;
for (int i=0; i < 100; i++)
{
if ((i%2)!=0) continue;
sum+=i;
}
type idTab[nb];
type idTab[] = {lv};
où :
bool b[10]; // tableau nommé b de 10 booléens char ch[10]; // tableau nommé ch de 10 caractères const unsigned int NB = 10; //(constante) double t[NB]; // tableau nommé t de NB réels (ici 10)
type idTab[nb] = {lv};
type idTab[] = {lv};
où :
bool b[10] = {true, false, true, false}; // valeurs 1 0 1 puis des 0
char ch1[10] = {'h','e','l','l','o'}; // valeurs h e l l o puis des caractères nuls
char ch2[10] = "hello"; // valeurs h e l l o puis des caractères nuls
const unsigned int NB = 10; //(constante)
double t[NB] = {0}; // valeur 0 puis des 0
ou bien ultérieurement, dans une boucle de traitement :
for(int i=0;i<TAILLE;i++)
{
idTab[i] = vInit;
}
où :
for(int i=0;i<NB;i++)
{
t[i] = (i + 1);
}
int nbElem = ( sizeof idTab / sizeof(type) );Exemple :
const unsigned int NB = 10; int t[NB]; cout << sizeof t << endl; // --> 40 cout << sizeof(int) << endl; // --> 4 cout << ( sizeof t / sizeof(int) ) << endl; // --> 10Ainsi, si on on souhaite être indépendant une valeur de constante de taille de tableau ou si, à l'endroit du programme où on se trouve, on ne connait pas le nombre d'éléments du tableau, on peut le retrouver simplement (à condition de connaitre le type de données du tableau...). Ainsi pour le tableau d'entier nommé tab:
for(int i=0;i<(sizeof tab / sizeof(int));i++)
{
tab[i] = 0;
}
cout << ch1 << " " << ch2;
type idTab[nb1][nb2];
type idTab[nb1][nb2] = {{lv},{lv}, etc.};
où :
short int p[2][3]; // tableau de 6 éléments
short int compteur = 1;
for(int i;i<2;i++)
{
for(int j;j<3;j++)
{
p[i][j] = compteur;
compteur++;
}
}
short int compteur = 1;
for(int i;i<(sizeof p / sizeof p[0]);i++)
{
for(int j;j<(sizeof p[0] / sizeof(short int);j++)
{
p[i][j] = compteur;
compteur++;
}
}
On peut donner un sens à ces dimensions :
double p[10][20][20];
for(unsigned int i;i<(sizeof p / sizeof p[0]);i++)
{
for(unsigned int j;j<(sizeof p[0]/ sizeof p[0][0]);j++)
{
for(unsigned int k;k<(sizeof p[0][0] / sizeof(double));k++)
{
p[i][j][k] = 0;
}
}
}
C++ offre la possibilité de définir des tableaux plus évolués : ce sont des objets qui possèdent des propriétés, au delà de leur contenu.
La déclaration a une syntaxe différente, mais l'utilisation est identique (utilisation des indices).
Ainsi pour un tableau idTab comportant nb1 tableau de nb2 éléments d'un certain type :
array<type, nb> idTab;où :
Exemple :
const int NBELEM = 10; ... array<int, NBELEM> t; // tableau de 10 entiers
Pour un tableau idTab comportant nb1 tableau de nb2 éléments d'un certain type :
array<array<type, nb2>, nb1> idTab;où :
Exemple :
const int NBELEM1 = 2; const int NBELEM2 = 12; ... array<array<int, NBELEM2>, NBELEM1> t; // tableau de 2x12 entiers
Ainsi pour un tableau idTab comportant nb1 tableau de nb2 éléments d'un certain type :
vector<type> idTab; vector<type> idTab (nb);où :
Exemple :
const int NBELEM = 10; ... vector<int> t (NBELEM); // tableau de 10 entiers
struct idStr
{
déclaration1;
déclaration2;
...
déclarationN;
};
où :
struct Point
{
double x,y,z;
string n;
};
idStr idVarStr;où :
Point p1, p2;
idVarStr.idVar1 = valeur;où :
p1.x = 0, p1.y = 0, p1.z = 0; p1.n = "origine"
typedef unsigned char byte; // alias sur le type unsigned char
struct Couleur
{
byte rouge, vert, bleu;
}
struct Point
{
double x,y,z;
string n;
Couleur c;
}
Utilisation :
Point p1; p1.x = 0,p1.y = 0, p1.z = 0; p1.n = "origine"; p1.c.rouge = 255, p1.c.vert = 255, p1.c.bleu = 255;
const unsigned int NB_POINTS = 20; Point points[NB_POINTS];Utilisation (tous les points sont noirs):
for(int i=0;i<NB_POINTS;i++)
{
points[i].c.rouge = 0;
points[i].c.vert = 0;
points[i].c.bleu = 0;
}
enum figure {CERCLE, POLYREG};
struct Cercle {
unsigned int r
};
struct Polyreg {
unsigned int nbc;
unsigned int c;
};
struct Figure {
Point pRef;
figure fig;
union {
Cercle unCercle;
Polyreg unPolyreg;
};
};
Utilisation :
Figure f[10];
for(int i=0;i<10;i++)
{
switch (f[i].fig)
{
case CERCLE :
cout << "cercle : r=" << f[i].unCercle.r;
break;
case POLYREG :
cout << "polygone : " << f[i].unPolyreg.nbc <<"cotes";
cout << " c=" << f[i].unPolyreg.c;
break;
}
}
type idSsProg (listeParams)
{
// corps du sous-programme
// = liste d' instructions à exécuter
}
où :
idSsProg (listeArgum);où :
void idSsProg (listeParams)
{
// corps de la procédure
// = liste d' instructions à exécuter
}
Exemple :
void afficherNombre (int n)
{
cout << n;
return; // optionnel
} // fin
L'instruction return est optionnelle; elle peut être placée à n'importe quel endroit et renvoie le contrôle à l'instruction qui suit l'appel. Sans instruction return, le sous-programme s'exécute jusqu'à la fin du code de son corps.
int n = 10; afficherNombre(n*2);
type idSsProg (listeParams)
{
// corps de la fonction
// = liste d' instructions à exécuter
return exprType;
}
où :
unsigned int valeurAbsolue (const int n)
{
unsigned int resultat;
if (n>=0) {resultat = n;}
else {resultat = (n * -1);}
return resultat;
}
ou bien :
unsigned int valeurAbsolue (const int n)
{
if (n>=0) {return n;}
else {return (n*-1); }
}
ou encore (utilisation de l'opérateur conditionnel):
unsigned int valeurAbsolue (const int n)
{
return ((n>=0) ? n : (n * -1));
}
L'instruction return est obligatoire; elle peut être placèe à n'importe quel endroit et renvoie une valeur qui pourra être récupérée par l'instruction d'appel.
int n = -10; n = valeurAbsolue(n*2) * n;
void afficherNombre (int); unsigned int valeurAbsolue (const int);
void permutter(int & x, int & y)
{
int z = x;
x = y;
y = z;
}
int main()
{
int a = 1, b = 2;
permutter(a,b);
}
La notion de portée (anglais scope) fait référence à la région d’un programme à l’intérieur de laquelle une déclaration (donnée, sous-programme) est connue. La portée démarre à sa déclaration et se prolonge jusqu'à la fin du bloc où elle a été déclarée.
La notion de visibilité fait référence au fait qu'une déclaration effectuée à un niveau inférieur puisse masquer une déclaration effectuée à un niveau supérieur, celle-ci n'étant plus visible jusqu'à la fin de la portée de la déclaration qui la masque (cf. exemple plus bas).
Dans un programme C++, on peut distinguer 3 niveaux de portée (de 1 à 3, 1 étant le plus élevé), une déclaration effectuée au niveau 1 étant accessible des niveaux inférieurs :
#include <iostream>
const unsigned int NB = 10; // niveau fichier
void afficher(unsigned int n);
int main()
{
cout << "(1)" << NB << endl;
const unsigned int NB = 11; // niveau fonction
cout << "(2)" << NB << endl;
{
const unsigned int NB = 12; // niveau bloc
cout << "(3)" << NB << endl;
}
cout << "(4)" << NB << endl;
afficher(NB);
}
void afficher(unsigned int n)
{
cout << "(5)" << NB << endl;
const unsigned int NB = 13; // niveau fonction
cout << "(6)" << NB << endl;
}
résultat :
(1)10 (2)11 (3)12 (4)11 (5)10 (6)13
A sa déclaration, une variable est associée à un espace mémoire pouvant stocker son contenu. De même, lé définition d'une fonction nécessite un espace mémoire utile au stockage des instructions qui y seront exécutées.
Un pointeur est une variable à part entière (un espace mémoire lui est réservé) qui peut contenir l'adresse mémoire d'un autre objet : variable, fonction
Les pointeurs permettent d’accéder à n’importe quel emplacement de la mémoire réservée à un programme : ils présentent un risque s'ils sont mal initialisés ou pas correctement utilisés. En effet, c'est au développeur que revient entièrement leur contrôle. Les pointeurs non initialisés (ou mal initialisés) sont la cause d’erreurs fréquentes d’exécution (écran bleu).
type * idPtr1 = NULL; type * idPtr2 = &idVar;où
char c = 'a'; char * ptrc = &c; int i = 2014; int * ptri = &i;
type * idPtr; type * idPtr = NULL;où :
int * ptrInt = NULL; double * ptrDbl = NULL; char * ptrCh = NULL;
idPtr = & idObj;où :
int n = 10; double v = 12.5; char c = 'a'; ptrInt = & n; ptrDbl = & v; ptrCh = & c;
* idPtroù :
(*ptrInt) ++; (*ptrDbl) +=2; *ptrCh = *ptrCh + 1; cout << "n:" << n << " " << (*ptrInt)<<" " << ptrInt << endl; cout << "v:" << v << " " << (*ptrDbl)<<" " << ptrDbl << endl; cout << "c:" << c << " " << (*ptrCh)<< " " << ptrCh << endl;
struct point
{
double x, y;
};
point * ptrPt;
point p1; ptrPt = & p1;
ptrPt->x = 2; ptrPt->y = 5; // ou bien : (*ptrPt).x = 2; (*ptrPt).y = 5;
const unsigned int NB = 10; int tab[NB]; int * ptrInt;
ptrInt = tab; ptrInt = & tab[0];
ptrInt[4] = 10 ; *(ptrInt+3) = 10 ; // est équivalent à : tab[4] = 10 ; *(tab+3) = 10 ;
int fSomme(int n1, int n2)
{
return (n1 + n2) ;
};
// déclaration d'un pointeur vers fonction à 2 paramètres entiers :
int (*ptrFonc)(int, int);
ptrFonc = &fSomme;
int n1 = 10; int n2 = 20; int n3 = (*ptrFonc)(n1, n2) ;
// définition de fonctions de calculs arithmétiques
int fSomme(int Vnb1, int Vnb2)
{ return (Vnb1+Vnb2) ; }
int fDiff(int Vnb1, int Vnb2)
{ return (Vnb1-Vnb2) ;}
int fProduit(int Vnb1, int Vnb2)
{ return (Vnb1*Vnb2) ; }
int fQuotient(int Vnb1, int Vnb2)
{ return (Vnb1/Vnb2) ;}
int fModulo(int Vnb1, int Vnb2)
{ return (Vnb1%Vnb2) ;}
typedef int (*ptrf)(int, int); // décl. pointeur sur fonction
ptrf Tfonc[5] ; // allocation d’un tableau de pointeurs
int main (void)
{
int n1, n2, numFonc ;
Tfonc[0]= &fSomme ;
Tfonc[1]= &fDiff ;
Tfonc[2]= &fProduit ;
Tfonc[3]= &fQuotient ;
Tfonc[4]= &fModulo ;
cout << "entrez 2 nombres :" ;
cin >> n1 >> n2 ;
cout << " entrez un numéro de fonction (0 à 4) " ;
cin >> numFonc;
cout << " resultat = " << (*(Tfonc[numFonc]))(n1, n2) );
return 0 ;
}
T * idPtr = new T(); T * idPtr = new T[nombre];où :
int n; cout << "entrer le nombre d'éléments"; cin >> n; int * ptr = new int[n];
int i;
for(i=0;i<n;i++)
{
*(ptr+i) = 0;
}
delete idPtr; delete [] idPtr;où :
struct cel
{
double x, y; // données, coordonnées
cel * suivant; // pointeur vers suivant
};
cel * tete; // tete de liste
cel * dern; // dernier de liste
cel * nouv; // pour définir un nouveau point
cel * surf; // pour passer en revue la liste
Pour ajouter des éléments :
nouv = new cel; // nouv pointe vers un nouveau point nouv->x = 0; nouv->y = 0; nouv->suivant = NULL; // pas de suivant pour le moment tete = nouv; dern = nouv; nouv = new cel; nouv->x = 10; nouv->y = 20; nouv->suivant = NULL; dern->suivant = nouv; dern = nouv; nouv = new cel; nouv->x = 30; nouv->y = 40; nouv->suivant = NULL; dern->suivant = nouv; dern = nouv;Pour parcourir la liste :
surf = tete;
while(surf != NULL)
{
cout << endl << surf->x << " " << surf->y;
surf = surf-> suivant;
}
La référence est un type de donnée spécifique au C++, proche du pointeur mais plus sûr. En effet, contrairement aux pointeurs, les références doivent être initialisées à la déclaration
int a = 1,
b = 2;
int & c = a;
cout << a << "=" << c;
c = b;
cout << b << "=" << c;
affiche "1=1";
Les références sont utilisées dans le passage des paramètres
void afficher(int & x)
{
cout << "la valeur est " << x << endl;
}
void doubler(int & x)
{
x *= 2;
}
int main()
{
int a = 5;
int & b = a;
afficher(a);
afficher(b);
doubler(a); afficher(a);
doubler(b); afficher(b);
return 0;
}
affiche :
la valeur est 5 la valeur est 5 la valeur est 10 la valeur est 20
#includeusing namespace std; const int TAILLE = 10; const int TAILLE1 = 12; const int TAILLE2 = 15; /* sans ref */ void f1(int t[]) { int taille = sizeof t / sizeof(int); int i; for(i=0;i<taille;i++) t[i] = 0; } void f2(int t[][TAILLE2]) { int taille = (sizeof t / sizeof(int)) / TAILLE2; int i,j; for(i=0;i<taille;i++) for(j=0;j<TAILLE2;j++) t[i][j] = 0; } /* avec ref */ void f1ref(int (&t)[TAILLE]) { for(int i=0;i<TAILLE;i++) t[i] = i; } void f2ref(const int (&t)[TAILLE]) { for(int i=0;i<TAILLE;i++) cout << t[i] << endl; } void f1refdim2(int (&t)[TAILLE1][TAILLE2]) { for(int i=0;i<TAILLE1;i++) for(int j=0;j<TAILLE2;j++) t[i][j] = i*j; } void f2refdim2(const int (&t)[TAILLE1][TAILLE2]) { for(int i=0;i<taille1;i++) for(int j=0;j<taille2;j++) cout << t[i][j] << " "; } int main() { int t1[TAILLE]; int t2[TAILLE1][TAILLE2]; f1(t1); f2(t2); f1ref(t1); f2ref(t1); f1refdim2(t2); f2refdim2(t2); return 0; }
| flux | description |
|---|---|
| ofstream | flux de sortie |
| ifstream | flux d'entrée |
ofstream f("fichier.txt");
Pour ouvrir un fichier pour lire son contenu(...en lecture) :
ifstream f("fichier.txt");
if (!f.is_open()) {
// gestion de l'erreur
}
f.close();
f << x << " " << y << endl;L'ajout de 'endl' permet la constituion d'une ligne de donnée qu'il sera plus facile de relire.
f >> x >> y >> endl;
#include#include using namespace std; int main() { const char * nomFic = "test.txt"; /* écriture dans un fichier */ ofstream fic(nomFic); if (!fic.is_open()) { cout << "erreur d'ouvertire fichier..." << endl; return 9999; } for (int i=0;i<10;i++) { fic << i << " "; } fic.close(); /* lecture d'un fichier (1) */ string ligne; ifstream fic1(nomFic); if (!fic1.is_open()) { cout << "erreur d'ouvertire fichier..." << endl; return 9999; } while (! fic1.eof() ) { getline (fic1,ligne); cout << ligne << endl; } fic1.close(); /* lecture d'un fichier (2) */ ifstream fic2(nomFic); if (!fic2.is_open()) { cout << "erreur d'ouvertire fichier..." << endl; return 9999; } int a; while (true) { fic2 >> a; if (fic2.eof()) break; cout << a << endl; } fic2.close(); return 0; }
La Programmation Orientée Objet est un démarche de conception des programmes (un paradigme de programmation) dans lequel interviennent les notions d'objets et de classes d'objets, et d'interactions entre objets.
Dans un programme classique, les "objets" modélisés sont représentés sous forme de listes de variables et les opérations qui les manipulent sous forme de procédures et fonctions.
Déclaration des entêtes des fonctions :(point.h)
struct point {
double x,y;
};
double calcDistance(point p1, point p2);
point rotation(point p1, double a);
void afficher(point p1);
Définition des fonctions : (point.cpp)
#include <iostream>
#include <cmath>
#include "point.h"
using namespace std;
double calcDistance(point p1, point p2)
{
return sqrt(pow(p2.x - p1.x,2)+(pow(p2.y - p1.y,2)));
}
point rotation(point p1, double a)
{
point r;
r.x = p1.x * cos(a) - p1.y * sin(a);
r.y = p1.x * sin(a) + p1.y * cos(a);
return r;
}
void afficher(point p1)
{
cout << "Point (" << p1.x << "," << p1.y << ")" << endl;
}
Fonction principale :(main.cpp)
#include <iostream>
#include "point.h"
using namespace std;
int main()
{
/* declarations */
const double PI = 3.1415927;
point p1, p2;
double d;
/* initialisation */
p1.x = 1, p1.y = 1, p2.x = 2, p2.y = 2;
/* traitement */
afficher(p1);
afficher(p2);
d = calcDistance(p1,p2);
cout << "distance=" << d << endl;
p1 = rotation(p1, PI);
afficher(p1);
return 0;
}
En POO, les caractérisques qui décrivent un objet et les fonctions qui les manipulent sont regroupés dans une superstructure, la classe, qui décrit ainsi un ensemble d'objets de même type. Dans le programme, les "objets" modélisés sont représentés sous une forme plus proche de la réalité.
Déclaration de la classe :
#include <string>
using namespace std;
class Point {
private:
// ses membres attributs privés
double x,y;
public:
// ses constructeurs
Point (); // point à l'origine
Point (double , double); // point en x y
// ses autres méthodes
void setXY(double , double); // modifier x y
double calcDistance(Point p2);
void rotation(double a);
string getTexte();
};
Définition de la classe :
#includeDéfinition du programme#include "Point.h" #include Point::Point() { x = 0; y = 0; } Point::Point(double xn, double yn) { x = xn; y = yn; } void Point::setXY(double xn, double yn) { x = xn; y = yn; } double Point::calcDistance(Point p2) { return sqrt(pow(p2.x - x,2)+(pow(p2.y - y,2))); } void Point::rotation(double a) { Point r(0,0); r.x = x * cos(a) - y * sin(a); r.y = x * sin(a) + y * cos(a); x = r.x; y = r.y; } string Point::getTexte() { char buffer [50]; int n, a=5, b=3; sprintf (buffer, "Point (%lf, %lf)", x,y); return buffer; }
#include#include "Point.h" void afficher(Point p) { cout << p.getTexte() << endl; } int main() { /* declarations */ Point p1, p2; const double PI = 3.1415927; double d; /* initialisation */ p1.setXY(1,1); p2.setXY(2,2); /* traitement */ afficher(p1); afficher(p2); d = p1.calcDistance(p2); cout << "distance=" << d << endl; p1.rotation(PI); afficher(p1); return 0; }
#includeExemple 2:using namespace std; ... cout << "test";
#include... std::cout << "test";
...
namespace monEsp1 {
void maFonc() {
...
}
}
...
namespace monEsp2 {
void maFonc() {
...
}
}
...
monEsp1::maFonc();
monEsp2::maFonc();
La STL est une bibliothèque C++ utilisant des templates (introduit la possibilité d'écriture d'un code indépendamment du type de donnée)
#include#include using namespace std; void afficher(vector<int> & v) { int taille=v.size(); cout << endl; for (int i=0; i<taille; i++) { cout << v[i] << " "; } } void doubler(vector<int> & v) { int taille=v.size(); for (int i=0; i<taille; i++) { v[i]*=2; } } void afficher2d(vector< vector<int> > & m) { int taille1 = m.size(); int taille2 = m[0].size(); cout << endl; for(int i=0;i<taille1;i++) for(int j=0;j<taille2;j++) cout << m[i][j] << " "; } int main() { const int MAX = 10; /* dim 1*/ vector v(MAX); for(int i=0;i<MAX;i++) v[i] = i; // ou bien : v.push_back(i); cout << endl; for(int i=0;i<MAX;i++) cout << v[i] << " "; // ou bien : cout << v.at(i) << " "; afficher(v); doubler(v); afficher(v); /* dim 2 */ vector< vector<int> > v2d(MAX, vector<int>(MAX)); for(int i=0;i<MAX;i++) for(int j=0;j<MAX;j++) v2d[i][j] = i*j; cout << endl; for(int i=0;i<MAX;i++) for(int j=0;j<MAX;j++) cout << v2d[i][j] << " "; afficher2d(v2d); return 0; }