Aller au contenu

Langage C/Variables

Leçons de niveau 15
Une page de Wikiversité, la communauté pédagogique libre.
Début de la boite de navigation du chapitre
Variables
Icône de la faculté
Chapitre no 4
Leçon : Langage C
Chap. préc. :Rencontre avec le C
Chap. suiv. :Entrées-sorties
fin de la boite de navigation du chapitre
En raison de limitations techniques, la typographie souhaitable du titre, « Langage C : Variables
Langage C/Variables
 », n'a pu être restituée correctement ci-dessus.

Programmer, c’est avant tout donner des ordres à notre ordinateur. Ces ordres vont permettre à notre ordinateur de faire ce qu’on veut. Notre ordinateur peut manipuler un peu de tout : du texte, de la vidéo, des nombres, etc. Les ordres qu’on va donner à notre ordinateur vont ainsi lui permettre de manipuler de l’information sous différentes formes, plus ou moins variées. À ce stade du tutoriel, on sait que ces ordres, ces instructions, sont effectués par notre processeur. Mais on ne sait rien sur la façon dont notre ordinateur fait pour maintenir ces informations, ni sur comment les utiliser dans notre langage C. De même, on ne sait pas comment donner des ordres à notre ordinateur, pour qu’il fasse ce qu’on lui demande.

Ce chapitre va pallier ce problème : il vous expliquera comment manipuler les types de données les plus simples disponibles en langage C. Ceux-ci ne sont autre que des nombres et des lettres. Ils sont manipulables grâce à ce qu’on appelle des variables, qui sont l’objet de ce chapitre. Après ce chapitre, vous saurez notamment comment manipuler des nombres et des lettres en langage C. Vous pourrez ainsi profiter de votre ordinateur comme s’il s’agissait d'une grosse calculette, bien plus rapide et puissante. Néanmoins, rassurez-vous ; le niveau en maths de ce chapitre sera très très faible : si vous savez compter, vous pourrez comprendre le chapitre facilement !

Cela peut paraitre simple, et pas très intéressant. Mais il faut bien commencer par les bases, comme la manipulation de données simples : manipuler du texte ou de la vidéo est complexe, et nécessite en plus de savoir comment manipuler des nombres. Eh oui ! Comme vous allez le voir, tout est nombre pour notre ordinateur, même le texte, et même la vidéo.

Qu’est-ce qu’une variable ?

[modifier | modifier le wikicode]

Pour comprendre ce qu’est une variable, et comment manipuler celles-ci, il faut commencer par comprendre comment notre ordinateur fait pour stocker ces informations de base. Notre ordinateur a été conçu pour être assez polyvalent : il peut en théorie stocker tout type d’informations. Pour ce faire, celui-ci utilise une ruse particulièrement simple : il stocke ses informations en les découpant en petites unités d’information qu’on appelle des bits. Ces bits sont donc des unités très simples qui ne peuvent prendre deux valeurs : 0 ou 1.

Pour stocker des informations, il suffit de prendre plusieurs de ces bits et de les regrouper les uns à côté des autres. En faisant ainsi, on peut créer des suites de 0 et de 1 qui peuvent s’interpréter comme des nombres. On peut ainsi représenter des nombres positifs, des nombres négatifs, des nombres à virgule, etc. Tout ce que peut faire notre ordinateur, c’est manipuler ces suites de bits, ces nombres. En somme, notre ordinateur n’est qu’une grosse calculatrice.

Les informations plus complexes, comme de la vidéo, du texte, etc. sont toutes stockées dans notre ordinateur sous la forme de nombres. En utilisant plusieurs de ces bits, on peut ainsi représenter n’importe quoi : du texte, des nombres, de la vidéo, etc. Je suppose qu’il sera difficile de me croire, mais sachez tout de même que toute information qu’on trouve dans notre ordinateur est représentée avec seulement des 0 et des 1 !

Ces bits sont stockés dans un composant électronique particulier, présent dans notre ordinateur : la mémoire. Son rôle : stocker tous les bits qui permettent de représenter nos informations.

Enfin, je dis « la mémoire », mais en fait il y en a plusieurs. Tout comme un humain possède plusieurs mémoires (mémoire à court terme, mémoire à long terme, etc.) qui lui servent à mémoriser plein d’informations, l’ordinateur se sert aussi de plusieurs mémoires pour stocker tout un tas de données de différentes tailles.

Mais pourquoi plusieurs mémoires et pas une seule ?

Le fait est que si l’on souhaitait utiliser une seule grosse mémoire dans notre ordinateur, celle-ci serait donc fatalement très lente : il est impossible de créer des mémoires qui soient à la fois rapides et qui puissent contenir beaucoup de données. On ne peut donc utiliser une seule grosse mémoire capable de stocker toutes les données dont on a besoin. Ce problème s’est posé dès les débuts de l’informatique. Les inventeurs des premiers ordinateurs modernes furent rapidement confrontés à ce problème. Pour ceux qui ne me croient pas, regardez un peu cette citation des années 1940, provenant d’un rapport de recherche portant sur un des premiers ordinateurs existant au monde :

   Idéalement, nous désirerions une mémoire d’une capacité indéfiniment large telle que n’importe quelle donnée soit immédiatement accessible. Nous sommes forcés de reconnaître la possibilité de la construction d’une hiérarchie de mémoire, chacune ayant une capacité plus importante que la précédente, mais accessible moins rapidement.

Comme on le voit, cette citation (traduite de l’anglais) montre le problème, mais évoque aussi la solution adoptée face à ce problème. Pour résoudre ce problème, il suffit de segmenter la mémoire de l’ordinateur en plusieurs sous-mémoires, de taille et de vitesse différentes qu’on utilise suivant les besoins. On aura donc des mémoires pouvant contenir peu de données dans lesquelles on pourra lire et écrire rapidement et des mémoires plus importantes, mais plus lentes. Cette solution a été la première solution inventée pour résoudre ce problème et est encore massivement utilisée à l’heure actuelle : on n’a pas encore fait mieux !

Nous avons dit que l’ordinateur utilisait plusieurs mémoires. Et il faut savoir que trois de ces mémoires sont importantes, et doivent être connues de tout programmeur. Je vous présente donc :

  • les registres ;
  • la RAM ;
  • le disque dur.

Alors évidemment, ce ne sont pas les seules : on pourrait aussi citer la mémoire cache et d’autres encore, mais cela n’a rien à faire dans un tutoriel sur le C. Et puis il y a déjà des cours à ce sujet sur le Site du Zéro, citons par exemple Fonctionnement d'un ordinateur depuis zéro.

Les registres sont des mémoires intégrées dans notre processeur. Elles sont très rapides, mais ne peuvent contenir que des données très simples : on peut difficilement mettre plus qu’un nombre dedans. Leur utilité est de stocker des données temporaires afin d’y accéder plus rapidement.

La mémoire RAM est une mémoire un peu plus grosse, et plus lente que les registres. Elle peut contenir pas mal de données, et on l’utilise généralement pour stocker le programme qu’on vient de lancer, ainsi que les données qu’il va manipuler.

Cette mémoire a tout de même un léger défaut : elle perd son contenu quand on coupe le courant. Autant dire qu’on doit trouver une autre mémoire pour stocker notre système d’exploitation, nos programmes, etc. : c’est le rôle du disque dur, une mémoire très grosse, mais très lente.

En C, la mémoire la plus utilisée est la mémoire vive. Et donc, pour bien comprendre comment programmer en C, il faudra comprendre comment interagir avec cette mémoire RAM. Plus loin dans ce cours, nous verrons également comment manipuler des fichiers sur le disque dur. Mais pour ce qui est des registres, c’est autre chose : le C cache presque totalement la gestion de ceux-ci, qui est réalisée presque entièrement par le compilateur. Impossible de les manipuler directement !

Hé, une minute : si je stocke une donnée dans ma mémoire, comment je fais pour la récupérer ?

Eh bien dans ce cas-là, vous n’avez pas trop le choix : vous devez savoir où se trouve votre donnée dans la mémoire de l’ordinateur. Généralement, cette donnée se trouvera en mémoire RAM. On peut bien sûr copier notre donnée dans un registre, ou sur le disque dur, mais passons. Et pour retrouver notre donnée en RAM, rien de plus simple.

Bytes et octets

[modifier | modifier le wikicode]

Dans notre RAM, les bits sont regroupés en « paquets » contenant une quantité fixe de bits : des « cases mémoires », aussi appelées bytes. Généralement, nos mémoires utilisent des bytes de 8 bits. Autrefois, certaines mémoires avaient des bytes de 6 ou 5 bits, parfois plus. Mais maintenant, la situation s’est un peu normalisée et la grande majorité des mémoires utilisent des bytes de 8 bits. Un groupe de 8 bits s’appelle un octet.

Avec un octet, on peut stocker 256 informations différentes. Par exemple, on peut stocker un nombre avec 256 valeurs différentes. On peut stocker les lettres de l’alphabet, ainsi que les symboles alphanumériques. On peut aussi stocker tous les nombres de 0 à 255, ou de -128 à 127, tout dépend de comment on s’y prend.

Pour stocker plus d’informations (par exemple les nombres de -1024 à 1023), on peut utiliser plusieurs octets, et répartir nos informations dedans. Nos données peuvent prendre un ou plusieurs octets qui se suivent en mémoire, sans que cela pose problème : nos mémoires et nos processeurs sont conçus pour gérer ce genre de situations facilement. En effet, nos processeurs peuvent parfaitement aller lire 1, 2, 3, 4, etc. octets consécutifs d’un seul coup sans problème, et les manipuler en une seule fois.

Adresse mémoire

[modifier | modifier le wikicode]
MemoryAccess

Chacun de ces octets se voit attribuer un nombre unique, l’adresse, qui va permettre de la sélectionner et de l’identifier celle-ci parmi toutes les autres. Il faut imaginer la mémoire RAM de l’ordinateur comme une immense armoire, qui contiendrait beaucoup de tiroirs (les cases mémoires) pouvant chacun contenir un octet. Chaque tiroir se voit attribuer un numéro pour le reconnaitre parmi tous les autres. On pourra ainsi dire : je veux le contenu du tiroir numéro 27 ! Pour la mémoire c’est pareil. Chaque case mémoire a un numéro : son adresse.

En fait, on peut comparer une adresse à un numéro de téléphone (ou à une adresse d’appartement) : chacun de vos correspondants a un numéro de téléphone et vous savez que pour appeler telle personne, vous devez composer tel numéro. Les adresses mémoires fonctionnent exactement de la même façon !

Pour retrouver votre donnée dans la RAM, on doit donc simplement préciser son adresse. Ce principe peut se généraliser aux autres mémoires : on doit fournir ce qu’on appelle une référence, qui permet d’identifier la localisation de notre donnée dans la mémoire : dans quel registre elle est (l’« adresse » du registre est alors ce qu’on appelle un nom de registre), à quel endroit sur le disque dur, etc. Ainsi, toute donnée est identifiée dans notre ordinateur par une référence, qui permet d’accéder à notre donnée plus ou moins directement. Notre adresse n’est donc qu’un cas particulier de référence, cette notion étant plus générale.

Manipuler nos données se fait alors via des références, plus ou moins compliquées, qui peuvent permettre de calculer l’adresse de notre donnée, et déterminer si elle est dans un registre, la RAM, le disque dur, etc.

Le seul problème, c’est que manipuler explicitement des références est un vrai calvaire. Si vous ne me croyez pas, essayez de programmer en assembleur, le seul langage dans lequel on doit manipuler des références explicitement. C'est une horreur. Mais rassurez-vous : on a moyen de se passer de ce genre de choses. Pour ce faire, on peut décider de camoufler ces références plus ou moins efficacement. Pour cela, on peut décider de remplacer ces références par autre chose.

Dans nos langages de programmation, et notamment dans le langage C, on remplace des références par des variables. Cette variable correspondra à une portion de mémoire, appelée objet, à laquelle on donnera un nom. Ce nom permettra d’identifier notre variable, tout comme une référence permet d’identifier une portion de mémoire parmi toutes les autres. On va ainsi pouvoir nommer les données qu’on manipule, chacun de ces noms étant remplacés par le compilateur en référence vers un registre ou vers une adresse mémoire.

Déclarer une variable

[modifier | modifier le wikicode]

Déclarer une variable

[modifier | modifier le wikicode]

Entrons maintenant dans le vif du sujet en apprenant à déclarer nos variables. Pour bien commencer, il faut savoir qu’une variable est constituée de deux éléments obligatoires :

  • Un identificateur : c’est en gros le « nom » de la variable ;
  • Un type.

Le type d’une variable permet d’indiquer ce que l’on veut stocker : un nombre entier, un nombre à virgule (on dit aussi un flottant), un caractère, etc. Pour préciser le type d’une variable, on doit utiliser un mot-clé, spécifique au type que l’on souhaite donner à notre variable.

Une fois qu’on a décidé le nom de notre variable, ainsi que son type, on peut la créer (on dit aussi la déclarer) comme ceci :

type identificateur;

En clair, il suffit de placer un mot-clé indiquant le type de la variable, et de placer le nom qu'on lui a choisi immédiatement après.

Faites bien attention au point-virgule à la fin !

Comme dit précédemment, un type permet d’indiquer au compilateur quel type de données on veut stocker. Ce type va permettre de préciser :

  • toutes les valeurs que peut prendre la variable ;
  • et les opérations qu’on peut effectuer dessus, histoire de ne pas additionner une lettre avec un nombre à virgule.

Définir le type d’une variable permet donc de préciser son contenu potentiel et ce qu’on peut faire avec.

Le langage C fournit 8 types de base :

Type Contenu
char un caractère ou un entier
short un entier
int un entier
long un entier
float un nombre à virgule
double un nombre à virgule
long double un nombre à virgule

Les types short, int et long servent tous à stocker des nombres entiers qui peuvent prendre des valeurs positives, négatives, ou nulles. On dit qu’il s’agit de types signés. Pour ces trois types, il existe un type équivalent non signé. Un type entier non signé est un type entier qui n’accepte que des valeurs positives ou nulles : il ne peut pas stocker de valeurs négatives. Pour déclarer des variables d’un type non signé, il vous suffit de faire précéder le nom du type entier du mot-clé unsigned.

Le char peut lui aussi servir à stocker des nombres. Il sert surtout au stockage de caractères, mais ces derniers étant stockés dans l'ordinateur sous forme de nombres, il est possible de stocker des nombres dans un char. Le seul problème, c’est que ce char peut très bien être signé sur certains compilateurs et pas sur d’autres. Suivant le compilateur utilisé, le char sera soit signé par défaut, soit il sera non signé. Pour éviter les ennuis en utilisant un char comme un nombre, vous pouvez déclarer explicitement vos char non signés : unsigned char ou signés : signed char.

Capacité d’un type

[modifier | modifier le wikicode]

Tous les types stockant des nombres (tous sauf le type char) ont des bornes, c’est-à-dire une limite aux nombres qu’ils peuvent stocker. Il faut dire que le nombre de bytes occupé par une variable d’un certain type est limité, et est généralement fixé définitivement pour toutes les variables de ce type par le compilateur. En conséquence, on ne peut pas mettre tous les nombres possibles dans une variable de type int, float, ou double. On aura forcément une valeur minimale et une valeur maximale : certains nombres seront trop grands ou trop petits pour rentrer dans une variable d’un certain type. Ces bornes (que vous pouvez trouver au paragraphe 2.2.4.2 de la norme) sont les suivantes[1] :

Type Minimum Maximum
signed char -128 127
unsigned char 0 255
short -32 767 32 767
unsigned short 0 65 535
int -32 767 32 767
unsigned int 0 65 535
long -2 147 483 647 2 147 483 647
unsigned long 0 4 294 967 295
float
double
long double

Si l’on regarde bien le tableau, on remarque que certains types ont des bornes identiques. En vérité, les valeurs présentées ci-dessus sont les minima garantis par la norme et il est fort probable qu’en réalité, vous puissiez stocker des valeurs plus élevées que celles-ci (le type int s’apparente souvent à un long, par exemple). Cependant, dans une optique de portabilité, vous devez considérer ces valeurs comme les minima et les maxima de ces types, peu importe la capacité réelle de ces derniers sur votre machine.

Le type "unsigned int" équivaut à un "unsigned", ne soyez pas surpris si plus tard en lisant les codes d'autrui vous ne trouveriez seulement ce mot-clé.

Taille d’un type

[modifier | modifier le wikicode]

Peut-être vous êtes vous demandés pourquoi existe t-il autant de types différents. La réponse est toute simple : la taille des mémoires était très limitée à l’époque où le langage C a été créé. En effet, le PDP-11 sur lequel le C a été conçu ne possédait que 24 ko de mémoire (pour comparaison une calculatrice TI-Nspire possède 100 Mo de mémoire, soit environ 4000 fois plus). Il fallait donc l’économiser au maximum en choisissant le type le plus petit possible. Cette taille dépend des machines, mais de manière générale vous pouvez retenir les deux suites d’inégalités suivantes : char ≤ short ≤ int ≤ long et float ≤ double ≤ long double.

Aujourd’hui ce n’est plus un problème, il n’est pas nécessaire de se casser la tête sur quel type choisir (excepté si vous voulez programmer pour de petits appareils où la mémoire est plus petite). En pratique, on utilisera surtout char pour les caractères, int pour les entiers et double pour les flottants. Les autres types ne servent pas à grand-chose.

Les identificateurs

[modifier | modifier le wikicode]

Maintenant que l’on a vu les types, parlons des identificateurs. Comme dit précédemment, un identificateur est un nom donné à une variable pour la différencier de toutes les autres. Et ce nom, c’est au programmeur de le choisir. Cependant, il y a quelques limitations à ce choix.

  • On ne peut utiliser que les 26 lettres de l’alphabet latin : pas d’accents, pas de ponctuation ni d’espaces. Le caractère underscore (« _ ») et les chiffres sont cependant acceptés.
  • Un identificateur ne peut pas commencer par un chiffre.
  • Les mots-clés ne peuvent pas servir à identifier une variable ; on ne peut donc pas utiliser ces mots :
    • auto
    • break
    • case
    • char
    • const
    • continue
    • default
    • do
    • double
    • else
    • enum
    • extern
    • float
    • for
    • goto
    • if
    • int
    • long
    • register
    • return
    • short
    • signed
    • sizeof
    • static
    • struct
    • switch
    • typedef
    • union
    • unsigned
    • void
    • volatile
    • while
  • Pour simplifier, on peut parfaitement considérer que deux variables ne peuvent avoir le même identificateur (le même nom). Il y a parfois quelques exceptions, mais cela n’est pas pour tout de suite.
  • Les identificateurs peuvent être aussi longs que l’on désire, toutefois le compilateur ne tiendra compte que des 32 premiers caractères.

À noter que le C fait la différence entre les majuscules et les minuscules (on dit qu’il respecte la casse).

D’autres mots-clés

[modifier | modifier le wikicode]

En plus des mots-clés qui servent à indiquer le type de notre variable, on peut utiliser d’autres mots-clés lors de la déclaration de nos variables. Le but : donner un peu plus d’informations sur nos variables. On peut ainsi préciser que l’on veut que nos variables soient constantes et non modifiables, ou d’autres choses encore. On ne va pas voir tous les mots-clés existants, et pour cause : il nous manque quelques informations pour vous expliquer le rôle de certains. Nous allons seulement parler des mots-clés const, volatile et register.

Comme vous l’avez surement deviné, ces mots-clés se placent avant le type et le nom de la variable, lors de la déclaration.

Le premier que je vais vous montrer est const. Ce mot-clé signifie « constant » en français. Il sert donc à déclarer une variable comme étant constante, c’est-à-dire qu’on ne pourra pas modifier sa valeur au cours du programme. Sa valeur restera donc inchangée durant toute l’exécution du programme. À quoi ça sert ? C’est utile pour stocker une variable qui ne changera jamais, comme la constante \pi qui vaudra toujours 3,14159265 ou e qui vaudra toujours 2,718281828.

Une recommandation qui est souvent faite est de déclarer comme étant const tout ce qui est possible. Cela permet d’éviter pas mal d’erreurs et aide à éclaircir le code.

Par convention, une variable constante est souvent écrite en majuscule. Voir une variable constante en minuscule peut paraître étrange pour certains. De plus, il est extrêmement horripilant de voir des variables non constantes en majuscules ! Smiley

Vient ensuite register. Celui-ci permet de dire au compilateur que l’on veut que notre variable soit stockée de préférence dans un registre du processeur, au lieu de devoir être placée en mémoire RAM. C’est en effet le compilateur qui décide quelle variable stocker dans les registres, durant combien de temps, et à quel moment. On dit qu’ils se chargent d’allouer les registres. register permettait autrefois d’indiquer au compilateur que la variable désignée register était à placer (ou à copier) dans les registres dès que possible.

L’utilité de register est très simple : un registre est au bas mot plus de 100 à 200 fois plus rapide que la mémoire RAM de notre ordinateur. Ainsi, placer (ou copier) une variable dans les registres permet d’accéder à celle-ci bien plus rapidement que si on devait la lire ou l’écrire depuis la mémoire RAM. Idéalement, on voudrait donc mettre toutes nos variables dans ces registres. Mais le problème, c’est que notre processeur ne possède que peu de registres. Il n’est ainsi pas rare d’avoir à se débrouiller avec seulement 4 à 8 registres. Autant dire qu’il faut alors réfléchir consciencieusement aux variables à placer dedans : il faut mettre de préférence des variables auxquelles on va accéder souvent (et ne pas hésiter à déplacer des variables entre registres et mémoire si besoin est). register permettait de préciser quelles étaient les variables à mettre en priorité dans les registres, histoire d’orienter le choix du compilateur. Cela permettait alors de rendre nos programmes plus rapides.

Mais c’était il y a longtemps : de nos jours, register ne sert plus à rien (ou presque). La raison est très simple : les compilateurs actuels disposent d’algorithmes mathématiques qui permettent de gérer les registres de façon quasi optimale. En tout cas, nos compilateurs se débrouillent nettement mieux que les programmeurs pour décider quel registre utiliser et quelles données placer dedans. Ils n’ont donc plus besoin d’aide, et register est souvent ignoré ou sous-utilisé par ces compilateurs. En clair : register est une antiquité, qui ne doit plus être utilisé, et ne sert strictement à rien. Après, libre à vous de tenter d’utiliser register, mais au moins, vous savez d’avance que c’est inutile.

Le dernier est moins connu, car moins utilisé : il s’agit de volatile. C’est un peu l’inverse de register. Une variable marquée volatile ne peut pas être copiée ou placée dans les registres du processeur.

volatile sert dans certains cas bien particuliers, que vous ne rencontrerez surement jamais. Il arrive qu’une variable soit modifiée par autre chose que le programme dans lequel on a déclaré cette variable. Par exemple, certaines variables peuvent être modifiées par des périphériques, comme la souris, le clavier, etc. Ou encore, on peut avoir à manipuler des variables accessibles par plusieurs programmes, qui peuvent être mises à jour à n’importe quel moment. Ces modifications de la variable se feront alors en mémoire RAM : il est en effet impossible pour un périphérique ou un programme d’aller modifier le contenu d’un registre déjà attribué à un autre programme.

Si on stocke notre variable dans un registre, les mises à jour effectuées en mémoire RAM ne seront pas répercutées sur la copie de la variable stockée dans les registres. Le programme qui aura stocké cette variable dans ses registres continuera donc de manipuler une variable périmée, non mise à jour. Cela peut donner lieu à des bugs relativement bizarres ou catastrophiques.

Pour éviter toute catastrophe, ces variables spéciales doivent donc être marquées volatile, histoire de ne pas pouvoir être placées dans les registres du processeur, et lues ou écrites en mémoire RAM.

Je tiens à préciser que volatile n’est toutefois utile que pour certaines variables, potentiellement accessibles par autre chose que le programme qui l’a déclaré (un autre programme, un périphérique, etc.), et qui peuvent être modifiées n’importe quand. Ce genre de cas est très rare, et n’arrive que quand on doit travailler avec du matériel très spécial, ou qu’on veut créer des programmes très compliqués, qui manipulent directement le matériel, comme des pilotes de périphériques des systèmes d’exploitation, etc. Autant être franc, vous n’aurez certainement jamais à utiliser volatile dans un programme, tellement ce genre de cas est rare et particulier. Mais un peu de culture générale ne fait jamais de mal, et peut être utile au cas où.

Déclaration et initialisation

[modifier | modifier le wikicode]

Maintenant que nous savons toutes les bases, entrainons-nous à déclarer quelques variables :

double taille;
volatile unsigned int age;
char caractere;
short petite_valeur;

On peut aussi déclarer plusieurs variables de même type sur une même ligne, en séparant leurs noms par une virgule :

int age, taille, nombre;

Je vous conseille d’utiliser les deux méthodes de déclaration que vous venez de voir (multiligne et monoligne) simultanément, comme ceci :

	
int annee, mois, jour;
int age, taille;
int x, y, z;

J’ai regroupé les déclarations de variables selon les « rapports » qu’ils ont entre eux.

Je vous présente du code, des explications, encore du code puis encore des explications. Mais durant tout ce temps, vous avez peut-être essayé de compiler ces codes. Êtes-vous surpris de voir qu’il ne se passe rien ? Les plus malins d’entre vous auront peut-être compris qu’il ne se passe rien en apparence. Je dis bien en apparence car, en réalité, l’ordinateur fait parfaitement son travail : il va réserver des cases mémoire pour nos variables. Votre ordinateur fait donc tout ce que vous lui demandez de faire : déclarer des variables, et non modifier leurs valeurs et encore moins les afficher !

OK, notre case mémoire est réservée pour notre variable, mais quelle est la valeur qu’il y a dedans (quel est l’objet dans le tiroir) ?

Eh bien en fait, c’est indéterminé. Il peut y avoir n’importe quelle valeur (n’importe quel objet dans le tiroir). Initialisation

Mais heureusement, on peut donner une valeur à une variable dès sa déclaration. On dit aussi qu’on initialise notre variable. Ainsi on est sûr que la case mémoire ne contient pas n’importe quoi.

Pour initialiser une variable, on procède ainsi si c’est une variable destinée à contenir une valeur numérique :

type identificateur = valeur;

Ou comme ceci si c’est un caractère :

char identificateur = 'lettre';

Voici quelques exemples de déclarations de variables :

volatile unsigned int age = 25;
short petite_valeur = 1;
const long abc = 3141596;
char caractere = 'h';

Petite note sur const : il faut donner une valeur à la variable dès la déclaration puisque l’on ne pourra plus la modifier après !

Petite précision : la norme C89 réclame que l’on sépare les déclarations du reste du code : on ne peut pas déclarer une variable où l’on veut. Si l’on veut vraiment suivre la norme, on déclare d’abord toutes les variables en début de bloc (c’est-à-dire après une accolade ouvrante) et ensuite vient le reste des instructions. Initialisation des nombres flottants

Je tiens à retenir votre attention sur la manière d’initialiser les variables flottantes (soit donc de type float ou double).

En fait, ces variables sont faites pour contenir des nombres à virgule. À l’initialisation, il ne faut donc pas se contenter de donner sa valeur, il faut aussi mettre la « virgule ». Sauf que l’on ne met pas une virgule : on met un point.

const double pi = 3.14;

Cela vient du fait que le C est une invention américaine, et que les anglophones utilisent le point à la place de la virgule, on met un point là où nous autres francophones mettons une virgule.

Et vous devez impérativement mettre ce point, même si vous voulez stocker un nombre entier dans un float ou un double. Par exemple, vous ne devez pas écrire double a = 5; mais double a = 5.; (certains préfère double a = 5.0;, cela revient au même). Si vous ne le faites pas, vous risquez d’avoir quelques problèmes.

Type Initialisation
char 0
int 0
long 0
short 0
float 0.
double 0.
long double 0.
unsigned int 0
unsigned short 0
unsigned long 0

Nous savons donc déclarer (créer) nos variables, et les initialiser (leur donner une valeur à la création). Il ne nous reste plus qu’à voir la dernière manipulation possible : l’affectation. Cette affectation permet de modifier la valeur contenue dans une variable, pour la remplacer par une autre valeur.

Il va de soi que cette affectation n’est possible que pour les variables qui ne sont déclarées avec const : par définition, de telles variables sont en effet constantes et ne peuvent voir leur contenu changer. Cela interdit toute affectation pour ces variables déclarées constantes.

Pour faire une affectation, il suffit d’opérer ainsi :

identificateur = nouvelle_valeur;

On voit que la syntaxe est similaire à celle d’une déclaration avec initialisation : la seule différence, c’est qu’on n’a pas à préciser le type. Ce type est en effet fixé une fois pour toutes lors de la déclaration de notre variable : pas besoin de le préciser lors d’une affectation.

Si je veux changer la valeur de mes variables, je procède tout simplement comme suit.

	
age = 30;
taille = 177.5;
petite_valeur = 2;

Il n’y a aucune limite, voyez par exemple :

	
petite_valeur = 2;
petite_valeur = 4
petite_valeur = 8;
petite_valeur = 16;
petite_valeur = 8;
petite_valeur = 4;
petite_valeur = 2;

À chaque affectation, la variable va prendre une nouvelle valeur.

Attention : ne mettez pas le type quand vous voulez changer la valeur, sinon vous aurez le droit à une belle erreur du type « redefinition of 'nom_de_votre_variable' » car vous aurez créé deux variables avec le même identificateur !

Le code suivant est donc incorrect :

	
int age = 15;
int age = 20;

Si vous exécutez tous ces codes, vous verrez qu’ils n’affichent toujours rien. Mais pourquoi ? Tout simplement parce qu’on n'a pas demandé à notre ordinateur d'afficher quoique ce soit. Et ce n’est pas pour tout de suite : on apprendra comment faire pour afficher quelque chose sur la console au chapitre suivant. Quoiqu’il en soit, ne soyez pas pressés et prenez bien le temps d’assimiler toutes les notions présentées dans ce chapitre.


  1. « « Sizes of integer types », ISO-IEC 9899, 5.2.4.2.1. », p. 454