Et oui, ici aussi vous n’y échapperez pas, notre premier programme C vas nous permettre d’afficher ce fameux Hello world dans la console.
Avant de commencer à coder, réfléchissons un peu. Pour rappel le C est une suite de fonction dont une obligatoire la fonction main( ), c’est elle qui sera exécutée en premier d’où son appellation point d’entrée. Nous allons devoir trouver le moyen d’afficher du texte dans la console.
En programmation C, il est aussi impératif de réfléchir à quel genre de “chose” doit renvoyer la fonction, comme par exemple un entier, une chaîne de caractères, un caractère, un booléen, … autrement dit, quel type la fonction va renvoyer.
Le point d’entrée main( )
Lorsqu’un programme commence à s’exécuter il appellera toujoursmain( )en premier. C’est une fonction qui permet de diriger les appels aux autres fonctions du programme.
Voyons ce qu’il se passe pour un programme qui n’utilise pas la fonction main().
Malgré tout quelques contraintes s’appliquent à main( ) :
On considère le code suivant associé à son résultat à la compilation :
#include <stdio.h>int somme(int a, int b){ return a+b;}
... /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o : dans la fonction « _start » :(.text+0x1b) : référence indéfinie vers « main »collect2: error: ld returned 1 exit status
L’erreur spécifie directement que la fonction main est indéfinie, en gros qu’il manque la fonction main.
Elle ne peut pas être définit comme static.
En fait, le mot clé static possède deux utilités différentes selon le contexte :
Placé dans un fichier en global, il permet de limiter la visibilité au fichier courant.
Placé dans une fonction, appliquée à une variable elle lui donne une durée de vie statique.
Ainsi, si on définit la fonction maincomme étant static alors cette dernière sera invisible lors de l’édition des liens, le système sera donc incapable de la retrouver pour démarrer le programme.
Elle ne peut pas être appelée
Toute fonction en langage C possède le même squelette :
typeRetour représente le type de la donnée que doit renvoyer la fonction. C’est à dire si la fonction doit retourner un entier, un caractère, un tableau, …
nomFonction représente le nom que vous donnez à la fonction permettant de l’appeler.
arguments représentent les paramètres de la fonction (une fonction n’a pas forcément de paramètres).
return est l’instruction permettant de retourner un résultat.
WARNING
Si votre fonction doit retourner un entier et que vous retournez un charactère, la compilation ne fonctionnera pas.
Si on revient à notre fonction main( ),
Par convention, elle retourne 0 donc un entier de type intque l’on détaillera après.
On connaît son nom.
Elle n’a pas besoin d’arguments/paramètres.
Ainsi en suivant le squelette, notre fonction main( ) devrait ressembler à cela :
int main( ){ // Instructions de la fonction main( ) return 0;}
WARNING
Sans oublier le return 0; puisqu’on définit que la fonction principale revoie un entier.
Ainsi, ce tout petit code nous permet d’introduire des spécificités de la programmation C
Chaque fonction est un bloc délimitée entre accolades { ... }.
Chaque instruction se termine avec un point-virgule ;qui permet de spécifier la fin d’une instruction.
Écrire des commentaires
En C il est possible d’écrire deux sortes de commentaires :
Sur une ligne //...
Sur plusieurs lignes /* ... */
// Un commentaire sur une ligne/*Un commentaire sur plusieurs lignes*/
Afficher des informations dans la console
La fonction printf(...) permet d’afficher du texte ou des valeurs à l’écran. Il faut se souvenir que printf n’est pas directement utilisable, elle vient d’une bibliothèque appelée stdio.h. Ainsi cela implique que pour pouvoir utiliser la fonction printf il faudra spécifier en entête la bibliothèque. C’est donc là qu’intervient les #include évoqués lors du premier cours.
“Signature” de la fonction printf :
printf(const char* format, ...);
La fonction prend comme premier paramètre une chaîne de caractères entre "...". Cette dernière peut-être formatée ou non.
On dit qu’une chaîne est formatée lorsqu’elle permet d’afficher des données sous un format donné. Le format est spécifié par un symbole pourcentage suivit du format correspondant : %....
Les autres paramètres sont les valeurs des différents formats spécifié dans la chaîne. Si aucun format, alors aucune valeur/variable à spécifier à la fonction.
Voici comment inclure la bibliothèque stdio.h dans votre fichier C et d’afficher ce bon vieux Hello world.
Pour rappel :
main( ) est le point d’entrée du programme qui renvoie un entier, 0.
Pour afficher une donnée on utilise printf issu de la bibliothèque stdio.h.
Et voilà, votre premier main en langage C, plutôt cool non ? Bon je suis d’accord, on a pas encore vu grand chose, mais déjà quelle fierté d’avoir son premier code qui fonctionne !!
TIP
Les header(= include) se font au début du code, c’est à dire avant toutes les fonctions. La quasi totalité du temps, les premières lignes de vos fichiers C seront des include.
Grossièrement votre code devrait ressembler au squelette suivant :
#include<...>#include<...>//... // Toutes les fonctions// À la fin, la fonction mainint main( ){ // Instructions return 0;}
Les types usuels
Bon je suis d’accord avec toi, ça fait plusieurs fois que je parle de type. C’est donc le moment idéal pour les introduire un à un. Prenons les plus fréquents pour commencer. Les autres pourront être introduits au moment voulu.
Le type caractère
Le mot clé char désigne un objet de type caractère, ce dernier peut contenir n’importe quel caractère que la machine utilise. Le plus souvent, un objet de type char est codé sur 1 octet(= 8 bits) et les caractères pris en compte sont ceux qui correspondent au codage ASCII.
Decimal
Hex
Char
Decimal
Hex
Char
Decimal
Hex
Char
Decimal
Hex
Char
0
00
[NULL]
32
20
[SPACE]
64
40
@
96
60
`
1
01
[START OF HEADING]
33
21
!
65
41
A
97
61
a
2
02
[START OF TEXT]
34
22
"
66
42
B
98
62
b
3
03
[END OF TEXT]
35
23
#
67
43
C
99
63
c
4
04
[END OF TRANSMISSION]
36
24
$
68
44
D
100
64
d
5
05
[ENQUIRY]
37
25
%
69
45
E
101
65
e
6
06
[ACKNOWLEDGE]
38
26
&
70
46
F
102
66
f
7
07
[BELL]
39
27
'
71
47
G
103
67
g
8
08
[BACKSPACE]
40
28
(
72
48
H
104
68
h
9
09
[HORIZONTAL TAB]
41
29
)
73
49
I
105
69
i
10
0A
[LINE FEED]
42
2A
*
74
4A
J
106
6A
j
11
0B
[VERTICAL TAB]
43
2B
+
75
4B
K
107
6B
k
12
0C
[FORM FEED]
44
2C
,
76
4C
L
108
6C
l
13
0D
[CARRIAGE RETURN]
45
2D
-
77
4D
M
109
6D
m
14
0E
[SHIFT OUT]
46
2E
.
78
4E
N
110
6E
n
15
0F
[SHIFT IN]
47
2F
/
79
4F
O
111
6F
o
16
10
[DATA LINK ESCAPE]
48
30
0
80
50
P
112
70
p
17
11
[DEVICE CONTROL 1]
49
31
1
81
51
Q
113
71
q
18
12
[DEVICE CONTROL 2]
50
32
2
82
52
R
114
72
r
19
13
[DEVICE CONTROL 3]
51
33
3
83
53
S
115
73
s
20
14
[DEVICE CONTROL 4]
52
34
4
84
54
T
116
74
t
21
15
[NEGATIVE ACKNOWLEDGE]
53
35
5
85
55
U
117
75
u
22
16
[SYNCHRONOUS IDLE]
54
36
6
86
56
V
118
76
v
23
17
[END OF TRANS. BLOCK]
55
37
7
87
57
W
119
77
w
24
18
[CANCEL]
56
38
8
88
58
X
120
78
x
25
19
[END OF MEDIUM]
57
39
9
89
59
Y
121
79
y
26
1A
[SUBSTITUTE]
58
3A
:
90
5A
Z
122
7A
z
27
1B
[ESCAPE]
59
3B
;
91
5B
[
123
7B
{
28
1C
[FILE SEPARATOR]
60
3C
<
92
5C
\
124
7C
|
29
1D
[GROUP SEPARATOR]
61
3D
=
93
5D
]
125
7D
}
30
1E
[RECORD SEPARATOR]
62
3E
>
94
5E
^
126
7E
~
31
1F
[UNIT SEPARATOR]
63
3F
?
95
5F
_
127
7F
[DEL]
TIP
Les caractères en C peuvent être utilisés comme des entiers, il est donc possible de faire des opérations arithmétiques sur eux.
Exemple :
On considère une variable a qui contient le caractère 'a' et on souhaite afficher la lettre b à partir de a. On sait grâce à la table ASCII que la différence entre le code de b et le code de a vaut 1, il faut donc ajouter 1 à la variable contenant 'a' pour obtenir b.
#include<stdio.h>int main( ){ char a = 'a'; char b = a+1; printf("%c", b);}
b
WARNING
Une variable de type char ne peut contenir qu’un seul et unique caractère. Pour pouvoir stocker plusieurs caractères, il faudra utiliser :
Un tableau de char
Un pointeur vers char
Ces deux aspects seront évoqués plus tard dans ce cours. cours 6 et 7
En conséquence, cela implique directement qu’une variable de type char contenant plusieurs caractères déclenchera une erreur et empêchera la compilation de votre programme.
Tip
Un objet de type char ne peut contenir qu’un seul caractère, et en réalité chaque caractère représente une valeur numérique qui correspond en fait à son codage dans la table ASCII.
Ainsi, on peut avoir besoin d’afficher la valeur d’une variable de type char sous forme de caractère ou sous forme numérique. Cela est évidemment possible en langage C.
Voilà comment procéder :
#include<stdio.h>int main( ){ char a = 'A'; printf("%c", a); // Afficher le caractère printf("%d", a); // Afficher la valeur numérique}
A
65
Où 65 représente le code ASCII de la lettre A.
Pour le moment, ne nous préoccupons pas de %c et %d, on en reparle un peu après. Pour spoiler un peu on peut les voir comme des formats qui permettent de dire je veux afficher la valeur dans un certain type de la variable truc.
Le type entier
Les entiers sont représentés par le mot clé int, qui peut être précédé :
d’un attribut de précisionshort ou long
d’un attribut de représentatiosigned ou unsigned
Remarque
La taille d’une variable dépend aussi de la machine sur laquelle vous codez.
Type
Taille (en octets)
Plage de valeur possible
int
4
-2 147 483 648 à 2 147 483 647
unsigned int
4
0 à 4 294 967 295
short ou short int
2
-37 768 à 37 767
unsigned short
2
0 à 65 535
long ou long int
4 ou 8
dépend du pc
unsigned long
4 ou 8
uniquement valeurs positive
long long
8
très grands nombres
unsigned long long
8
les positifs
Remarque
unsigned pour des valeurs positives.
signed pour les valeurs positives et négatives.
short petite taille
long grande taille
La taille des entiers selon le format peut dépendre aussi du système sur Windows par exemple on note certaines différences entre 32 et 64 bits. Le compilateur peux aussi jouer un rôle.
Exemple :
Si on souhaite définir un entier non signé, il suffit de spécifier le type de l’entier choisit, un nom de variable puis une valeur. Dans la pratique si on choisit que la variable var contiendra 155 alors, en programmation C on écrira :
unsigned int var = 155;
TIP
La taille d’un short int est comprise entre la taille d’un objet de type char et la taille d’un objet de type int, on peut aussi le noter :
sizeof(char) <= sizeof(short int) <= sizeof(int)
L’opérateur sizeof
L’opération sizeof permet de déterminer la taille (en octets) d’un type de données ou d’une variable. Ce dernier se révèle très utilise lorsqu’il faut gérer la mémoire, et pour travailler avec les structures complexes.
Utiliser sizeof pour un type de données
Il est possible d’obtenir la taille d’un type de donnée spécifié lors de l’appel de l’opérateur.
Remarque
Les types de données sont int, char, float, …
Ainsi, il suffit d’écrire sizeof(type_de_donnees).
Exemple :
#include<stdio.h>int main( ){ printf("Taille d'un entier : %d", sizeof(int)); printf("Taille d'un caractère : %d", sizeof(char)); printf("Taille d'un flottant : %d", sizeof(float)); return 0;}
Warning
La taille des données peut changer selon votre système mais en général, les tailles données ci-dessus sont dans la majeure partie des cas celles-ci.
Utiliser sizeof sur une variable
#include<stdio.h>int main( ){ int a = 1452; printf("Taille de la variable a : %d", sizeof(a)); return 0;}
Il est évidemment possible de calculer la taille des tableaux et des structures mais nous verrons ces aspects plus tard dans ce cours.
Remarque
L’opérateur sizeof est évalué à la compilation, ce qui signifie qu’il n’a pas d’impact sur la performance à l’exécution.
Les types flottants
En langage C, le type flottant (floating-point) est utilisé pour représenter les nombres réels avec une partie décimale. Il existe deux types flottants :
float précision simple
généralement sur 32bits
environ 7 chiffres significatifs
double précision double
généralement sur 64bits
environ 15-16 chiffres significatifs
WARNING
Le nombre de chiffres significatif représente la précision avec laquelle est donnée un nombre.
Les valeurs minimales et maximales sont définies dans le header <float.h> :
FLT_MIN
FLT_MAX
DBL_MIN
DBL_MAX
…
WARNING
Il est possible de convertir un flottant vers un entier, cela peut néanmoins entraîner une parte de précision.
Les arrondis peuvent entraîner des erreurs à cause de leur représentation en binaire.
Exemple :
#include <stdio.h>int main( ){ float var = 14.5f; double val = 14.2;}
TIP
Par défaut, les flottant sont de type double alors c’est pour cette raison que si il est de type float on ajoute un f à la fin.
Caster une variable en C
Le terme “caster une variable” ça veut dire convertir un type de variable en un autre. On utilise ainsi la syntaxe suivante en langage C.
(type_var) var
Exemple :
#include <stdio.h>int main() { double x = 5.8; int y; y = (int) x; // cast explicite de double vers int printf("x = %f\n", x); printf("y = %d\n", y); return 0;}
x = 5.8
y = 5
Exemple :
int a = 10;double b = 3.5;// Cast implicite (devient un double)double result1 = a + b; // a est converti en double// Cast expliciteint result2 = (int)b; // b devient 3
Portée des variables
La portée des variables en C (aussi appelée scope), c’est la partie du programme dans laquelle une variable est accessible (où tu peux l’utiliser). Il y a plusieurs types de portée selon où et comment tu déclares ta variable.
Warning
Une variable doit être déclarée et initialisée avant d’être utilisée… !
Prenons l’instruction suivante :
int j = 0, c;
En C, on peut déclarer plusieurs variables en même temps sans pour autant les initialiser. Hors, quand on est en C, si on initialise pas les variables, elles ont ce qu’on appelle une valeur indéfinie, ce qui signifie que tu ne peux pas savoir ce qu’elle contient.
Du coup dans l’instruction ci-dessus, tu initialises bien j à 0, donc ta variable j stocke bien la valeur 0. Alors que pour la variable c, tu ne lui donne pas de valeur.
Ainsi, quand tu voudras afficher les valeurs de j et de c, tu obtiendra pour c une valeur différente à chaque exécution du programme.
Exemple :
#include <stdio.h>int main() { int j = 0, c; printf("j=%d et c=%d", j, c); return 0;}
Suivit de trois exécutions du programme.
j=0 et c=-1392444720
j=0 et c=-1370719536
j=0 et c=1561864912
Ainsi, tant qu’une variable n’est pas explicitement initialisée/définie, alors elle contient une valeur indéterminée.
Variable locale
C’est la déclaration à l’intérieur d’un bloc. Dans ce cas la variable est dite LOCALE et est accessible uniquement dans ce même bloc.
Exemple :
void maFonction() { int x = 5; // portée locale printf("%d\n", x); // Pas d'erreur ici}printf("%d\n", x); // Erreur, x n'est pas visible ici
Variable globale
Déclaration en dehors de toute fonction, elle est appelée variable GLOBALE et est accessible partout dans le fichier.
Exemple :
int y = 10; // portée globalevoid afficher() { printf("%d\n", y);}
TIP
On peut aussi avoir accès à une variable globale partout dans d’autres fichiers en l’exportant avec extern.
Exemple d’export de variable globale dans d’autres fichiers
Fichier : fichier1.c
int compteur = 0; // Définition de la variable globale...
Fichier : fichier2.c
extern int compteur; // Déclaration : "Je sais qu'elle est définie ailleurs"...
Retour sur printf( )…
Je ne sais pas si tu as remarqué mais quand on veut afficher la taille ou la valeur d’une variable par exemple, on précise à l’intérieur de printf ce qu’on appelle le format. En gros, on dit qu’on souhaite afficher la valeur d’une certaine variable dans un certain format.
On utilise le caractère % pour chaque variable suivit de l’initiale associé au format dans lequel on souhaite afficher la variable.
On considère deux variables que l’on souhaite afficher dans un format bien précis alors de manière générale, on utilisera printf comme suit :
entier short int signé entier short int non signé hexadécimal (unsigned short)
Base 10 Base 10 Base 16
-1246390AF
short signé : −32768 à 32767 unsigned short : 0 à 65535
%ld%lu%lX
entier long int signé entier long int non signé hexadécimal (unsigned long)
Base 10 Base 10 Base 16
-128946399B4E98A0F
long signé (64 bits) : −9223372036854775808 à 9223372036854775807 unsigned long : 0 à 18446744073709551615
%d%X
entier int signé entier int en hexadécimal
Base 10 Base 16
-5469A0F
int signé (32 bits) : −2147483648 à 2147483647 unsigned int : 0 à 4294967295
%le%lf
réel double précision double
scientifique ou flottant
-3.195874-45e-7
environ ±1.7×10−38 à ±1.7×1038(15-16 chiffres de précision)
%e%f
réel simple précision float
scientifique ou flottant
-3.195874-45e-7
environ ±1.2×10−38 à ±3.4×1038(6-7 chiffres de précision)
%s
chaîne de caractères
—
Hello world
dépend de la mémoire disponible
Il est aussi possible d’ajouter des options entre % et la lettre qui définit le format.
Ajouter un entier qui précise sur combien de caractère est affiché la variable. Par exemple, si on souhaite afficher une variable entière sur 5 caractère on utilisera le format %5d.
WARNING
Le texte est aligné automatiquement à droite, alors lorsque la variable s’affiche sur plus de caractère, le nombre fournit est ignoré.
Exemple :
#include <stdio.h>int main(){ int n = 4; printf("Le nombre n vaut %6d et voilà.", n); return 0;}
Le nombre n vaut 4 et voilà.
Pour aligner à gauche en utilise le signe -.
Exemple :
#include <stdio.h>int main(){ int n = 4; printf("Le nombre n vaut %-6d et voilà.", n); return 0;}
Le nombre n vaut 4 et voilà.
On peut ajouter deux nombres séparés par un point . très utilise sur les réels pour spécifier sur combien de caractère il est affiché puis sa précision.
%nbChar.precisionFORMAT
Exemple :
On souhaite afficher le nombre 12.874 sur 10 caractères avec une précision après la virgule de 2.
#include <stdio.h>int main(){ int n = 12.874; printf("Le nombre n vaut %10.2lf et voilà.", n); return 0;}
Le nombre n vaut 12.87 et voilà.
Il existe aussi des constantes caractères permettant d’effectuer un sout de ligne par exemple.
constante caractère
signification
\n
saut de ligne
\t
tabulation
\r
retour chariot
\f
saut de page
\'
apostrophe
\?
point d’interrogation
Les constantes
Justement et si on parlait des constantes en programmation C.
Généralités
En C une constante représente une donnée dont la valeur ne peux pas changer après sa définition. Contrairement aux variables, les constantes garantissent que leur valeur ne changera pas tout au long du programme.
Il existe deux manières de déclarer des constantes :
Avec le mot clé const
Avec la directive préprocesseur #define
On utilise les constantes pour une meilleure lisibilité, maintenabilité du code et sécurité puisqu’elle empêche la modification de la valeur.
Initialiser une constante
En utilisant le mot clé const
const int TEINTE = 14;TEINTE = 130; // Erreur : on ne peut pas modifier une constante
Toute modification impliquera une erreur de compilation
La constante doit être initialisée pendant sa déclaration
const int VITESSE;VITESSE = 140;// Erreur à la compilation
Avec #define
#define PI 3.14159
Dans notre exemple PI est une constante symbolique.
Le préprocesseur remplace chaque occurrence de PI par 3.14159 dans le programme.
Pas de type directement associé (attention aux erreurs)
Quelques conseil
Tip
Utilisez const pour des constantes typées.
Utilisez #define pour des macros, ou des constantes globales (valeur fixe, configuration, …)
Les constantes prédéfinies
Il existe évidemment de multiples constantes prédéfinies, on en a vu quelques unes comme FLT_MIN et FLT_MAX dans l’entête <float.h>.