C si facile¶
Warning
Ce cours a été automatiquement traduit des transparents de M.Noyer par Félix qui continue le travail fait par Lorentzo et Elowan et Mehdi, nous ne nous accordons en aucun cas son travail, ce site à pour seul but d'être plus compréhensible pendant les périodes de révision que des diaporamas.
À propos
Ces transparents résument en quelques lignes de code le minimum à connaître pour s'en sortir en C dans les TD de début d'année.
Bien qu'il existe souvent plusieurs syntaxes équivalentes pour une même instruction, on se limite à une seule.
Thèmes abordés
- Variables : déclaration, affectation, affichage, saisie au clavier
- Compilation de projet en un fichier, exécution
- Opérateurs arithmétiques et bouléens
- Expressions conditionnelles
- Boucle while
- Déclarations et appels de fonctions simples.
- Déclaration de tableaux statiques à une dimension.
- Assertions
« \(\texttt{GCC}\) »
Squelette¶
- Commentaires en une ligne
// mon commentaire
. ET Commentaires sur plusieurs lignes/* mes commentaires */
- La fonction
main
renvoie un entier (en général). Cet entier est \(0\) par défaut (tout s'est bien passé). Autres valeurs renvoyées : code pour signaler un problème. - Une et une seule fonction main par programme (en cas de code sur plusieurs fichiers, un seul contient un main).
Déclaration, initialisation¶
Ouvrir un éditeur de texte comme emacs ou gedit (Linux) ou blocnote (Windows) \(\underline{\text{MAIS PAS UN TRAITEMENT DE TEXTE}}\).
- On déclare une variable en déclarant d'abord le type puis le nom. Point-virgule
;
à la fin de chaque instruction. - On peut initialiser immédiatement (cf
x
) ou attendre un peu (cfi
).
Compilation¶
Ouvrir un terminal :
- ♥ Compilation avec affichage des warning (mises en garde) (option
-Wall
):gcc -Wall exemple.c
Fichier exécutable produit :a.out
(nom par défaut) - ♥ Si on veut fixer le nom du fichier produit :
gcc -Wall initialiser.c -o toto
- Exécution.
- Récupérer la valeur renvoyée par le main :
Cette commande récupère en fait le retour de la dernière commande passée dans le terminal.
Exercice
Écrire un code qui soulève une erreur (d'exécution, pas de compilation) avant le return 0
du main. Compiler, exécuter et récupérer la valeur renvoyée par le programme. Vaut-elle zéro ?
Types de base¶
- Il y a trois familles de types de base : caractères, entiers et flottants.
- Chaque famille regroupe plusieurs types qui différent par leurs tailles et leurs aspects signés ou non signés.
- La liste des tailles données ci-dessous est non exhaustive :
- Entiers. Plusieurs tailles différente. On se contente ici de
int
(signés) etunsigned int
(non signés, au comportement cyclique). Au moins \(2\) octets (\(16\) bits) très souvent sur \(4\). Pour de gros entiers, préfererlong
etunsigned long
. Taille au moins \(4\) octets souvent sur \(8\). - Caractères.
char
. C'est la plus petite unité adressable de la machine. Souvent sur un octet. La taille des autres types en est un multiple. - Flottants :
float
(en général \(4\) octets) etdouble
(en général \(8\) octet) et leurs versions non signées.
- Entiers. Plusieurs tailles différente. On se contente ici de
- La taille des types dépend de la machine et de l'implémentation. Les bonnes infos sont dans les fichiers limits.h et float.h
Tableaux, chaînes de caractères¶
- Dans ce document, nous abordons brièvement la notion de tableau statique. Nous ne parlons pas des tableaux dynamiques (ou VLA) conformément à l'usage en MP2I.
- Il n'y a pas de type chaîne de caractères comme le
string
de Python. Les chaînes de caractères sont représentées- soit par le type
char *
ou constantes chaînes : pointeur sur un caractère, en général le contenu est non modifiable. - Soit par le type
char[]
ou tableau de caractères. Contenu modifiable.
- soit par le type
Types structurés¶
Définis plus tard
(cf cours Structures)
Affichage¶
Exemple d'appel d'affichages avec les différents spécifieurs de formats : %d,%f,%s
qui indiquent la nature de l'objet à afficher.
♥ Ne pas oublier de charger la bibliothèques d'entrées-sorties <stdio.h>
.
\n
pour passer à la ligne dans l'affichage.
Et toujours le return 0
du main.
Compilation puis exécution¶
Dans un terminal, entrer
- On exécute le programme produit en tapant
./hello
- Noter les commentaires en bash :
# un commentaire
Tableau de spécificateurs de formats¶
Symbole | Type | Impression comme |
---|---|---|
%d ou %i | int | entier relatif |
%u | uint | entier naturel non signé |
%o | int | entier exprimé en octal |
%x | int | entier exprimé en héxadécimal |
%c | char | caractère |
%s | char et char t[] | chaîne de caractères |
%f | double | flottants et doubles en notation décimale |
%e | double | flottant en notation scientifique |
%p | adresses |
A connaître %d %f %s %p
♥.
Saisie¶
scanf
prend au minimum deux paramètres : un spécifieur de format (%d,%f,%s
... ) et une adresse (celle de la variable qu'on veut renseigner). ♥
La saisie de chaînes de caractères doit se faire avec prudence
Saisie de chaînes de caractères¶
Pour les chaînes de caractères, tout séparateur (comme un espace) interrompt la lecture. On peut préciser qu'on veut ou ne veut pas certains caractères.
5 opérateurs sans surprise ♥¶
Les opérateurs arithmétiques ne devraient pas surprendre les utilisateurs de \(\texttt{Python}\) :
- l'addition
+
- la soustraction
-
- la multiplication
*
- la division
/
(euclidienne ou flottante) - le modulo
%
. - Pas d'opérateur d'exponentiation.
Pas de type bouléen importé par défaut¶
- En \(\texttt{C}\), il n'existe pas de type bouléen importé par défaut.
- À la place, la valeur \(0\) représente le bouléen
false
et toute autre valeur,true
. - Or, ce n'est pas l'esprit du programme d'info en CPGE. Une bonne façon de mettre des bouléens dans un programme \(\texttt{C}\) est alors d'importer la bibliothèque
#include <stdbool.h>
. ♥
Opérateurs bouléens ♥¶
Les voici :
Symbole | Signification |
---|---|
&& |
ET |
\|\| |
OU |
! |
NON |
Après compilation puis exécution :
Opérateurs bit-à-bit¶
Pour information
- Opérateurs de comparaison bit-à-bit
&, |, ∧
(\(\texttt{ET}\) bit-à-bit, \(\texttt{OU}\) bit-à-bit, \(\texttt{XOR}\) bit-à-bit) - Et également des opérateurs de décalage
>>, <<
: division/multiplication par une puissance de \(2\).
Les comparateurs ♥¶
On donne le tableau suivant déjà connu des utilisateurs de \(\texttt{Python}\) :
Symbole | Signification |
---|---|
== | est égal à |
> | est strictement supérieur à |
< | est strictement inférieur à |
>= | est supérieur ou égal à |
<= | est inférieur ou égal à |
!= | est différent de |
Comme en \(\texttt{Python}\), le symbole =
n'est pas un opérateur de comparaison mais d'affectation.
Expression conditionnelle¶
- La condition est indiquée entre parenthèse
- Les blocs sont écrits entre accolades.
- L'indentation ne fait pas sens en \(\texttt{C}\) contrairement à \(\texttt{Python}\)
Si alors sinon ♥¶
Détection et affichage de la parité d'un entier saisi
Sinon si ♥¶
Le elif
de \(\texttt{Python}\) s'écrit else if
en \(\texttt{Python}\) et se place entre if
et else
:
Nombre de racines d'un trinôme de degré \(2\)
Boucle while
♥¶
afficher les carrés des chiffres de 0 à 9 | |
---|---|
Attention aux boucles infinies¶
Pour arrêter : CTRL + C
Voici une boucle qui demande d'entrer un nombre jusqu'à ce que l'utilisateur saisisse \(10\) :
Le programme entre au moins une fois dans la boucle. Voici une trace d'exécution :
Programmation modulaire¶
- Un gros programme peut et doit être découpé en plusieurs modules (sous-parties du programme).
- Cela permet :
- d'améliorer la lisibilité (en gros : une idée = \(1\) module)
- d'éviter les séquences d'instructions répétitives, et cela d'autant plus facilement que la notion d'arguments permet de paramétrer certains modules.
- le partage d'outils communs qu'il suffit d'avoir écrits et mis au poin une seule fois. La compilation séparée est ici bien pratique pour ne compiler qu'une partie du programme indépendamment des autres.
Programmation modulaire en \(\texttt{C}\)¶
Fonctions et procédures¶
- Il n'existe qu'un seul type de module en \(\texttt{C}\) : les fonctions et procédures
- Les arguments sont transmis par valeur en \(\texttt{C}\) aux fonctions.
- Il semble donc impossible de modifier un argument transmis mais en réalité certaines valeurs (pointeurs et tableaux) sont en fait des adresses : cela fournit un moyen détourné de modifier l'agument transmis.
- La compilation séparée se fait par fichier source (alors qu'en Fortran par exemple, elle se fait par module).
Déclaration de fonction ♥¶
- Avant le nom de la fonction, on indique son type de retour (comme
int
,bool
,float
,char*
, ...) - Le nom de chaque paramètre est précédé de son type.
- Le corps de la fonction est entre accolades.
- La partie avant l'accolade est appelée prototype de la fonction
- Le mot
return
est obligatoire si la valeur de retour n'est pasvoid
. La valeur retournée doit être conforme au type annoncé. - Si la fonction ne retourne rien, on dit que c'est une procédure. Dans
ce cas, le type de retour est
void
.
Appel de fonction¶
- Le prototype de la fonction doit être placé avant son premier appel. Mais il est possible d'écrire le corps de la fonction après un ou plusieurs appels (cf plus tard). Les prototypes de
triple
etsalut
sont placés avant la fonctionmain
qui peut ainsi appeler ces fonctions.
Le mot clé void
¶
void
n'est pas un type, c'est un mot clé.- On l'utilise pour déclarer qu'une fonction ne renvoie pas de valeur :
void f(int x)
- Pour les fonctions sans argument, préférer
int f(void)
, (qui signifie explicitement quef
ne prend pas d'argument) àint f()
(qui indique que le nombre d'arguments def
n'est pas connu). - Enfin, si
void
n'est pas un type,void*
désigne un pointeur vers une valeur dont on ne connaît pas le type. Les règles de typage de \(\texttt{C}\) permettent d'utiliser une valeur de typevoid*
là où une valeur d'un certain type de pointeur est attendu :int *x = malloc(sizeof(int))
(malloc renvoie unvoid*
). - (PI) Enfin
void *
permet le polymorphisme. Exemple : une fonction qui agit sur un tableau dont les éléments sont de type quelconque. Nous n'utilisons pas cette fonctionnalité.
Tableaux statiques à une dimension¶
- La taille des tableaux statiques est connue à la compilation.
- Déclaration sous la forme
type nom [taille]
dans lequeltaille
est un nombre (pas une variable, sinon c'est un tableau à longueur variable appelé Variable Length Array (VLA)
- Pas de VLA en MP2I/MPI !!
- Les cases d'un tableau de taille \(N\) sont indicées de \(0\) à \(N −1\). Accès à la \(i\)-ème case :
t[i]
. - Contrairement à \(\texttt{Python}\) il n'y a pas de fonction
len
qui donne la longueur du tableau. C'est au programmeur de retenir la taille de son tableau (voir chapitre sur les Bytes).
Ecrire dans un tableau¶
Un tableau n'est pas une \(\color{red}\text{lvalue}\) ! ! ♥
Remplir puis parcourir un tableau ♥¶
Après compilation et exécution :
Initialisation de tableau¶
- Avec
int t[5]
on déclare un tableu de \(5\) entiers. Ce qui est dedans est impossible à prévoir. - Pour déclarer le contenu d'un tableau à sa création, on peut utiliser une syntaxe énumérative
- Si on écrit
int t[5]={10,20}
, les éléments \(2\),\(3\),\(4\) sont mis par défaut à \(0\).
Danger
- Ce programme peut parfois compiler (le compilateur peut ne pas détecter le dépassement de capacité) et même s'exécuter.
- Ce que fait alors le processus n'est pas prévu par la norme (comportement indéfini). Il peut afficher \(5\), s'arrêter en signalant une erreur, ou, plus grave, corrompre une autre partie de la mémoire du processus, rendant très difficile à prévoir son comportement.
- Faire très attention aux dépassements de capacité !
Passer un tableau en paramètre¶
En \(\texttt{C}\), lorsqu'on passe un tableau en argument d'une fonction, il est prudent de fournir sa taille. Ce n'est pas obligatoire mais cela permet d'éviter d'écrire où il ne faut pas.
Exemple d'appel
Exemple d'exécution
Assertions¶
Pour diverses raisons on peut souhaiter interrompre un programme si une condition n'est pas réalisée (ex : impossibilité d'allouer de la mémoire). Les assertions sont alors utiles.
- Trace d'exécution :