C : bases
Livre de référence
J'ai décidé de réapprendre le C. Et comme j'avais appris toutes mes bases de Python en suivant les cours open classrooms, je vais faire pareil ici avec leur cours "Apprenez à programmer en C".
Outils
Je vais utiliser les outils habituels :
- make ou clang pour la compilation
- gdb comme debugger (si je comprends comment il fonctionne)
- vim comme éditeur de texte.
Je ne rentrerais pas dans code::blocks ou autres.
BoilerPlate : includes, fonction main, syntaxe
Le langage a besoin d'un minimum de code, que voici présenté dans un hello world:
<source>
- include <stdio.h>
- include <stdlib.h>
int main(int argc, char *argv[]) { printf("Hello world !\n"); return 0; } </source>
Que signifie tout ça ?
- Les includes (qui sont elles-mêmes des directives de préprocesseur, car elles seront lues par le... préprocesseur): permettent d'inclure des librairies. Ici, on inclut stdio (Standard Input Output Header) qui est la librairie gérant les opérations d'entrée / sortie entre le processeur et les autres composants (RAM, ROM, etc). Stdlib est la librairie standard, qui inclut divers utilitaires très courants.
- int main etc: En C, on utilise une fonction principale (comme en python en fait, ou elle est implicite).
Fonctions (base)
Une fonction en C se décortique comme suit :
return_type nom(paramètres) accolade
- return type : le type de variable que va renvoyer ma fonction
- nom : son p'tit nom
- paramètres : ce qu'elle va prendre en entrée.
- accolade : la fonction est définie entre accolades.
- le corps de la fonction, qui fait des trucs.
- return : le retour de la fonction. Soit ça renvoie quelque chose comme un nombre, un str... soit ça peut renvoyer 0 pour dire que tout va bien. Pas de return(True) ici !
Exemple de fonction plus simple qu'un main: <source>
<source> /* function returning the max between two numbers */ int max(int num1, int num2) {
/* local variable declaration */ int result; if (num1 > num2) result = num1; else result = num2; return result;
} </source>
Alors, que signifie les paramètres d'une fonction main ? Si on se rappelle que le main() correspond au programme en lui-même, tel que lancé dans mon shell, on comprend vite :
- int argc : un main prend d'abord le nombre d'arguments envoyés au programme. Il est au moins de 1, car il y'a le programme en lui-même.
- char *argv[] : C'est un tableau de str, qui contiendra les paramètres en eux-mêmes.
Compiler avec clang
Une compilation simple de notre helloworld.c n'est pas compliquée : <source> clang hello.c
- Nous donne un a.out, qui est le programme compilé
</source>
Syntaxe
Point-virgules ?
Les points-virgules signifient que l'instruction en cours est terminée. Les retours à la ligne ne sont pas pris en compte (les tabs non plus), et on peut d'ailleurs coder comme des sagouins sur une seule ligne: <source>
- include <stdio.h>
- include <stdlib.h>
int main(int argc, char *argv[]) { printf("Hello !\n"); return 0; } </source> ...mais bon, code propre, tout ça :3
Les commentaires s'écrivent avec // pour une ligne, ou entre /* */ sur plusieurs lignes: <source> // Mon beau commentaire /* Mon commentaire entre balises */ </source>
Variables
En C, les noms de variables ont des contraintes : que des lettres, des chiffres, des underscores. On ne peut pas nommer ses variables avec des emojis :(
Asterisques et pointeurs
L’astérisque est généralement associé, en C, aux pointeurs (et à la multiplication, aussi). Par exemple, lorsque l'on déclare un pointeur: <source lang="c"> // i est un entier int i = 5; // p est un pointeur vers un entier, initialisé à NULL int *p = NULL; // &i correspond à l'adresse de i, qu'on assigne à p p = &i; /* Quand il ne s'agit pas d'une déclaration, * sert à déréférencer un pointeur.
* Ici, p pointe sur i; donc, i vaudra désormais 123 */
- p = 123;
/* Et d'ailleurs, quand on veut changer l'adresse sur laquelle un pointeur pointe, on
* a pas besoin d'astérisque. */
p = &une_autre_variable; </source>
Par déréférencer, dans "*p = 123;", il s'agit de dire "cette assignation ne va pas directement sur toi, p, mais sur la variable vers laquelle tu pointes".
On peut d'ailleurs déclarer et initialiser un pointeur en même temps :
int *p = &i;
Mais une subtilité à comprendre :
- "int i = 5" et "int i; i = 5" sont bien similaires;
- Mais "int *p = &i;" et "int *p; *p = &i;" ne donnent pas la même chose. En effet, le second va essayer de déréférencer un pointeur pas initialisé (j'ai pas compris).
Tableaux de caractères
Quelle est la différence entre "char i[10]" et "char *i" ? https://wiki.squi.fr/index.php/Fichier:Arraycharr.jpg Ce n'est pas clair... Je l'accorde volontiers.