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 toujours main() 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;
}
Lorsque vous allez compiler votre programme voici ce qu'il va se passer :
... /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 main comme é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.
La fonction main() :
Renvoie généralement 0 lorsque tout se passe bien.
On connaît son nom, et ne peux être appelée.
Elle ne prend pas forcément de paramètres. on détaillera ceci plus tard...
Ainsi, de manière générale on a :
int main(){
// Votre programme : Variables, appels de fonctions, ...
return 0;
}
Le return 0; est obligatoire car vous dites que main() renvoie un entier, il faut donc lui faire renvoyer un entier, de manière générale on renvoie 0.
Point route
Ainsi, ce tout petit code permet d'introduire deux spécificités importantes de la programmation en C :
Chaque bloc est délimité entre accolades : { ... }
Chaque instruction se termine par un point-virgule ;ce qui permet de dire que c'est "la fin de la ligne"
Les commentaires
En programmation C il existe deux manières d'écrire des commentaires :
Sur une seule ligne
// Commentaire
sur plusieurs lignes
/* Un bloc de commentaire
* sur plusieurs lignes */
Afficher des informations dans la console
La fonction printf( ... ) permet f'afficher des informations (texte, valeur, ...) sur le terminal. Hormis ceci, souvenez vous que printf, n'est pas directement utilisable ! Et oui... il faut importer ce qu'on appelle une bibliothèque ici, stdio.h, cela implique que sans elle vous ne pouvez pas utiliser la fonction.
C'est de là d'où vient nos #include ..., ils permettent d'ajouter des "header" qui en fait permettent d'appeler des méthodes prédéfinies dans des bibliothèques.
printf(const char* format, ...);
C'est normalement là que vous vous dites "oh bordel, c'est quoi ça". Rassurez-vous, c'est pas si compliqué à comprendre :
La fonction printf prend en paramètre :
const char* format c'est ce qu'on appelle une chaîne de caractères pouvant être formatée.
Les autres paramètres dépendent du paramètre format. Si elle ne possède aucun format, pas de paramètres supplémentaires. Dans le cas contraire, il y aura autant de paramètres que de format utilisé dans la chaîne de caractères format.
Définition
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 : %..., nous détaillerons ces formats plus tard.
Ainsi, voici le code permettant d'afficher "Hello world" dans la console :
#include <stdio.h>
int main(){
printf("Hello world");
return 0;
}
Enfin !! Votre premier programme en C est fonctionnel ! PLutôt cool ? non ?
Bon okay, vous ne vous attendiez peut-être pas à ça... Mais ce n'est que le début, on verra des choses plus badass quand on aura plus de connaissances !
#include <...>
#include <...>
// ...
// Toutes vos fonctions
// Le point d'entrée du programme
int main(){
// programme principal
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
31
1F
[UNIT SEPARATOR]
63
3F
?
95
5F
_
127
7F
[DEL]
Table ASCII
Exemple
On considère une variable a qui contient la lettre 'a' et on souhaite afficher la lettre 'b' à partir de la variable 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);
}
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.
1
Propriété
À retenir
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 : A
printf("%d", a); // Afficher la valeur numérique : 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écision short ou long
d’un attribut de représentation signed ou unsigned
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 positives
long long
8
très grands nombres
unsigned long long
8
les positifs
Table des types entiers
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;
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.
AInsi, il suffira 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;
}
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.
Le type flottant
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
Les valeurs minimales et maximales sont définies dans le header <float.h> :
FLT_MIN
FLT_MAX
DBL_MIN
DBL_MAX
…
Exemple
#include <stdio.h>
int main( ){
float var = 14.5f;
double val = 14.2;
}
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 -> int
printf("x = %f\n", x); // 5.8
printf("y = %d\n", y); // 5
return 0;
}
Exemple
#include <stdio.h>
int main(){
int a = 10;
double b = 3.5;
// Cast implicite (devient un double)
double result1 = a + b; // a est converti en double
// Cast explicite
int result2 = (int)b; // b devient 3
return 0;
}
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.
1
Propriété
À retenir
Une variable doit être déclarée ET initialisée avant d'être utilisée en C.
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.
Exemple
#include <stdio.h>
int main() {
int j = 0, c;
printf("j=%d et c=%d", j, c);
return 0;
}
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.
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 globale
void afficher() {
printf("%d\n", y); // Affiche 10
}
Exemple
Fichier_1.c
int compteur = 0; // Définition de la variable globale
...
Fichier_2.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ée 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 :
On souhaite afficher la valeur entière, puis caractère d’une variable. Ainsi on codera :
#include <stdio.h>
int main( ){
char lettre = "A";
printf("Format entier : %d et format caractère : %c.", lettre, lettre);
return 0;
}
Format
Type de l’argument affiché
Format d’affichage
Exemple
Bornes usuelles
%c
caractère (char)
ASCII
a G u
signed char : −128 à 127
unsigned char : 0 à 255
%hd%hu%hX
entier short int signé
entier short int non signé
hexadécimal (unsigned short)
Base 10
Base 10
Base 16
-12 463 90AF
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
-1289 46399 B4E98A0F
long signé (64 bits) : −9223372036854775808 à 9223372036854775807
unsigned long : 0 à 18446744073709551615
%d%X
entier int signé
entier int en hexadécimal
Base 10
Base 16
-546 9A0F
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−308 à ±1.7×10308
(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.
Exemple
#include <stdio.h>
int main(){
int n = 4;
printf("Le nombre n vaut %6d et voilà.", n);
return 0;
}
// Affiche : 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;
}
// Affiche : 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;
}
// Affiche : Le nombre n vaut 12.87 et voilà.
Il existe aussi des constantes caractères permettant d’effectuer un saut 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
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
En utilisant #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)
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>.