Licence CC BY-SA

Le langage C

Vous souhaitez apprendre à programmer, mais vous ne savez pas comment vous y prendre ? Vous connaissez déjà le C, mais vous avez besoin de revoir un certain nombre de points ? Ou encore, vous êtes curieux de découvrir un nouveau langage de programmation ? Si oui, alors permettez-nous de vous souhaiter la bienvenue dans ce cours de programmation consacré au langage C.

Pour pouvoir suivre ce cours, aucun prérequis n’est nécessaire : tout sera détaillé de la manière la plus complète possible, accompagné d’exemples, d’exercices et de travaux pratiques.

Remerciements

Avant de commencer, nous souhaitons remercier plusieurs personnes :

  • Mewtow pour sa participation à la rédaction et à l’évolution de ce cours ainsi que pour ses nombreux conseils ;
  • @Arius, @Saroupille, @amael et @Glordim pour la validation de ce cours ;
  • @Pouet_forever, SofEvans, @paraze et Mathuin pour leur soutien lors des débuts de la rédaction ;
  • @Dominus Carnufex et @patapouf pour leur suivi minutieux et leur bienveillance face à nos (nombreuses) fautes de français ;
  • @Karnaj, @Ifrit et @AScriabine pour leurs suggestions et corrections ;
  • @Maëlan pour sa relecture attentive du chapitre sur les encodages ;
  • toute l’équipe de Progdupeupl et de Zeste de Savoir ;
  • tous ceux qui, au fil du temps et de la rédaction, nous ont apporté leurs avis, leurs conseils, leurs points de vue et qui nous ont aidés à faire de ce cours ce qu’il est aujourd’hui ;
  • et surtout vous, lecteurs, pour avoir choisi ce cours.

Premiers pas

  1. Présentation du langage C

    1. La programmation, qu’est-ce que c’est ?

    2. Le langage C

    3. Notre cible

  2. Les outils nécessaires

    1. Windows

    2. GNU/Linux et *BSD

    3. Mac OS X

  3. Notre premier programme C

    1. Premier programme

    2. Erreur lors de la compilation

    3. Les commentaires

Les bases du langage C

  1. Les variables

    1. Qu’est-ce qu’une variable ?

    2. Déclarer une variable

    3. Initialiser une variable

    4. Affecter une valeur à une variable

    5. Les représentations octale et hexadécimale

  2. Manipulations basiques des entrées/sorties

    1. Les sorties

    2. Interagir avec l'utilisateur

  3. Les opérations mathématiques

    1. Les opérations mathématiques de base

    2. Raccourcis

    3. Le type d'une constante

    4. Le type d'une opération

    5. Les conversions

    6. Exercices

  4. Tests et conditions

    1. Les booléens

    2. Les opérateurs de comparaison

    3. Les opérateurs logiques

    4. Priorité des opérations

  5. Les sélections

    1. La structure if

    2. L'instruction switch

    3. L'opérateur conditionnel

  6. TP : déterminer le jour de la semaine

    1. Objectif

    2. Première étape

    3. Correction

    4. Deuxième étape

    5. Correction

    6. Troisième et dernière étape

    7. Correction

  7. Les boucles

    1. La boucle while

    2. La boucle do-while

    3. La boucle for

    4. Imbrications

    5. Boucles infinies

    6. Exercices

  8. Les sauts

    1. L'instruction break

    2. L’instruction continue

    3. Boucles imbriquées

    4. L'instruction goto

  9. Les fonctions

    1. Qu'est-ce qu'une fonction ?

    2. Définir et utiliser une fonction

    3. Les prototypes

    4. Variables globales et classes de stockage

    5. Exercices

  10. TP : une calculatrice basique

    1. Objectif

    2. Préparation

    3. Correction

  11. Découper son projet

    1. Portée et masquage

    2. Partager des fonctions et variables

    3. Fonctions et variables exclusives

    4. Les fichiers d'en-têtes

  12. La gestion d'erreurs (1)

    1. Détection d'erreurs

    2. Prévenir l'utilisateur

    3. Un exemple d'utilisation des valeurs de retour

Agrégats, mémoire et fichiers

  1. Les pointeurs

    1. Présentation

    2. Déclaration et initialisation

    3. Utilisation

    4. Pointeurs génériques et affichage

    5. Exercice

  2. Les structures

    1. Définition, initialisation et utilisation

    2. Structures et pointeurs

    3. Portée et déclarations

    4. Les structures littérales

    5. Un peu de mémoire

  3. Les tableaux

    1. Les tableaux simples (à une dimension)

    2. La vérité sur les tableaux

    3. Les tableaux multidimensionnels

    4. Les tableaux littéraux

    5. Exercices

  4. Les chaînes de caractères

    1. Qu'est-ce qu'une chaîne de caractères ?

    2. Définition, initialisation et utilisation

    3. Afficher et récupérer une chaîne de caractères

    4. Lire et écrire depuis et dans une chaîne de caractères

    5. Les classes de caractères

    6. Exercices

  5. TP : l'en-tête <string.h>

    1. Préparation

    2. Correction

    3. Pour aller plus loin : strtok

  6. L'allocation dynamique

    1. La notion d'objet

    2. Malloc et consoeurs

    3. Les tableaux multidimensionnels

    4. Les tableaux de longueur variable

  7. Les fichiers (1)

    1. Les fichiers

    2. Les flux : un peu de théorie

    3. Ouverture et fermeture d'un flux

    4. Écriture vers un flux de texte

    5. Lecture depuis un flux de texte

    6. Écriture vers un flux binaire

    7. Lecture depuis un flux binaire

  8. Les fichiers (2)

    1. Détection d'erreurs et fin de fichier

    2. Position au sein d'un flux

    3. La temporisation

    4. Flux ouverts en lecture et écriture

  9. Le préprocesseur

    1. Les inclusions

    2. Les macroconstantes

    3. Les macrofonctions

    4. Les directives conditionnelles

  10. TP : un Puissance 4

    1. Première étape : le jeu

    2. Correction

    3. Deuxième étape : une petite IA

    4. Correction

    5. Troisième et dernière étape : un système de sauvegarde/restauration

    6. Correction

  11. La gestion d'erreurs (2)

    1. Gestion de ressources

    2. Fin d'un programme

    3. Les assertions

    4. Les fonctions strerror et perror

Notions avancées

  1. La représentation des types

    1. La représentation des entiers

    2. La représentations des flottants

    3. La représentation des pointeurs

    4. Ordre des multiplets et des bits

    5. Les fonctions memset, memcpy, memmove et memcmp

  2. Les limites des types

    1. Les limites des types

    2. Les dépassements de capacité

    3. Gérer les dépassements entiers

    4. Gérer les dépassements flottants

  3. Manipulation des bits

    1. Les opérateurs de manipulation des bits

    2. Masques et champs de bits

    3. Les drapeaux

    4. Exercices

  4. Internationalisation et localisation

    1. Définitions

    2. La fonction setlocale

    3. La catégorie LC_NUMERIC

    4. La catégorie LC_TIME

  5. La représentation des chaînes de caractères

    1. Les séquences d'échappement

    2. Les tables de correspondances

    3. Des chaînes, des encodages

  6. Les caractères larges

    1. Introduction

    2. Traduction en chaîne de caractères larges et vice versa

    3. L'en-tête <wchar.h>

    4. <wchar.h> : les fonctions de lecture/écriture

    5. <wchar.h> : les fonctions de manipulation des chaînes de caractères

    6. L'en-tête <wctype.h>

  7. Les énumérations

    1. Définition

    2. Utilisation

  8. Les unions

    1. Définition

    2. Utilisation

  9. Les définitions de type

    1. Définition et utilisation

  10. Les pointeurs de fonction

    1. Déclaration et initialisation

    2. Utilisation

    3. Pointeurs de fonction et pointeurs génériques

  11. Les fonctions et macrofonctions à nombre variable d'arguments

    1. Présentation

    2. L'en-tête <stdarg.h>

    3. Méthodes pour déterminer le nombre et le type des arguments

    4. Les macrofonctions à nombre variable d'arguments

  12. Les sélections génériques

    1. Définition et utilisation

  13. T.P. : un allocateur statique de mémoire

    1. Objectif

    2. Première étape : allouer de la mémoire

    3. Correction

    4. Deuxième étape : libérer de la mémoire

    5. Correction

    6. Troisième étape : fragmentation et défragmentation

    7. Correction

Annexes

  1. Index

    1. Index



Ainsi s’achève ce cours, mais pas votre parcours dans le monde de la programmation ! En effet, même si vous avez appris certaines choses, vous ne connaissez pas tout : le C est un langage fabuleux qui réserve bien des surprises. Pour continuer votre apprentissage, voici quelques derniers conseils :

  • Soyez curieux : fouillez sur Internet pour découvrir de nouvelles méthodes, approfondissez celles que vous connaissez, renseignez-vous, testez de nouveaux outils, etc.
  • Entrainez-vous : c’est le meilleur moyen de progresser. Faites des projets qui vous tiennent à cœur, mettez en œuvre des algorithmes connus, réalisez des exercices, etc.
  • Lisez des codes produits par d’autres personnes : découvrez comment elles procèdent, apprenez d’elles de nouvelles techniques ou façons de faire et progressez en suivant leurs conseils. Vous pouvez par exemple commencer en visitant les forums de ce site.
  • Enfin, le plus important : amusez-vous ! ;)

Ces contenus pourraient vous intéresser

107 commentaires

Bonjour,

Dans le chapitre sur la représentation des types, je trouve cette phrase : "Ces types sont définis dans l’en-tête <stdint.h>". Ce n’est pas la première fois que je trouve l’emploi de "défini" au lieu de ce qui devrait-être (il me semble), "déclaré". En effet, si on définit un type ou toute autre variable dans un .h, on aura une erreur de multiple définition lors de la phase d’édition de lien de la compilation si notre fichier .h est inclus dans plusieurs .c du projet ? (à l’exception des macro constantes puisque celle-ci "n’existent plus après le passage du préprocesseur…")

Question d’ordre très général : tout au long de ce cours on parle de multiplets plutôt que d’octets, mais pourquoi au juste ? Y a-t-il des systèmes qui ne comptent pas par octets ?

Aussi, sur la partie du boutisme d’une machine : un pointeur renvoie-t-il toujours l’adresse du premier multiplet ? Par exemple, dans le cas d’un int, le pointeur sur int, contient-il l’adresse du multiplet de poids fort ou de poids faible ? Ou pointe-t-il toujours "la case de gauche" (peu importe son poids) ?

+0 -0

Bonjour,

Les limites des types présentées dans le chapitre "limites des types" dans l’en-tête <limits.h> tiennent compte des éventuels bites de bourrage ? Et si je comprends bien ces limites sont utiles parce qu’un simple calcul à partir de sizeof(int) est incertain à cause de ces éventuels bits de bourrage ? J’imagine bien que oui mais c’est pour être sûr :)

Bonjour,

Les limites des types présentées dans le chapitre "limites des types" dans l’en-tête <limits.h> tiennent compte des éventuels bites de bourrage ? Et si je comprends bien ces limites sont utiles parce qu’un simple calcul à partir de sizeof(int) est incertain à cause de ces éventuels bits de bourrage ? J’imagine bien que oui mais c’est pour être sûr :)

AScriabine

Les bits de bourrage, sont dans les structures.
limits.h définit les limites supporter par le compilateur.

Je suis désolé mais pour les questions, il faut créer un sujet sur le forum associé. La section des commentaires du tutoriel n’est pas l’endroit approprié. Tes questions sur la différence entre la définition et la déclaration d’un type ansi que sur l’utilisation du mot multiplet devraient également être posées ailleurs je pense. La différence entre remarque et question est mince mais ça aide tout le monde de bien faire les choses.


Les réponses courtes cependant.

typedef lang; /// Le type `lang` existe, c'est une déclaration

typdef int lang; /// Le type `lang` existe, c'est un int, il est définit. 

La norme parle de bytes et pas d’octet. Je suppose que c’est pour ça que les auteurs utilisent multiplets plutôt qu’octet (qui impose 8bit alors qu’un byte n’a pas forcément 8bits).

+3 -0

Il y a une ambiguïté que le cours ne lève pas sur les opérateurs de manipulation de bits. A priori un décalage de bits ne produit pas le même résultat en gros boutisme et petit boutisme : unsigned int a = 0x80000000; //a == 1000000000000000000000000000000. L’opération "a « 1" devrait, en petit boutisme, en décalant à gauche, conserver le 1 (car celui-ci arrive plus tard en mémoire) ! Et en gros boutisme, le 1 est "évacué". Il faudrait préciser explicitement que la question du boutisme est transparente pour le programmeur (on peut raisonner comme si la machine était en gros boutisme en bits et en octets, et le compilateur se débrouille pour que tout fonctionne). Cela est plus ou moins sous entendu lors de l’explication avec l’équivalence avec la division par deux mais cela reste un peu flou.

Pour répondre à l’injonction de ne pas poser des questions ici mais plutôt dans un forum, j’en prends acte et je vous remercie pour la précision. Cependant il se trouve que pour la très grande majorité des points que je soulève ici, il est important qu’ils soient portés à la connaissance des auteurs car ils soulèvent, à mon sens, des éléments du cours qui sont à améliorer car essentiels et pas assez développés. N’y voyez pas de mauvais jugement, je n’aurais pas perdu mon temps ici si je ne pensais pas que le tutoriel est de grande qualité. Cela reste à l’appréciation des auteurs de juger la pertinence de mes remarques, si elles ne sont pas pertinentes alors en effet je ferai plus attention, voire je me rétracterai.

Bien à vous et merci pour vos réponses

+0 -0

Dans le chapitre sur la représentation des types, je trouve cette phrase : "Ces types sont définis dans l’en-tête <stdint.h>". Ce n’est pas la première fois que je trouve l’emploi de "défini" au lieu de ce qui devrait-être (il me semble), "déclaré". En effet, si on définit un type ou toute autre variable dans un .h, on aura une erreur de multiple définition lors de la phase d’édition de lien de la compilation si notre fichier .h est inclus dans plusieurs .c du projet ? (à l’exception des macro constantes puisque celle-ci "n’existent plus après le passage du préprocesseur…")

AScriabine

En ce qui concerne les types, la différence entre une déclaration et une définition tient au caractère complet ou non du type (plus précisément si ça taille est connue ou non).

Ainsi, écrire struct test; est parfaitement correct et déclare un type incomplet struct test . À l’inverse, si le corps de la structure est fourni, il s’agira d’une définition.

Le terme définition dans le cours est donc correct, il s’agit bien de définitions. À l’inverse des définitions de variables ou de fonctions, une définition de type ne peut pas être « globale », elle doit donc être incluse dans chaque fichier qui la nécessite, d’où sa présence dans les fichiers d’en-tête.

Question d’ordre très général : tout au long de ce cours on parle de multiplets plutôt que d’octets, mais pourquoi au juste ? Y a-t-il des systèmes qui ne comptent pas par octets ?

AScriabine

C’est expliqué succintement dans le chapitre sur les variables, mais fut un temps (pas si) lointain où certaines machines n’adressait par exemple que des bytes de 36 bits.

Aussi, sur la partie du boutisme d’une machine : un pointeur renvoie-t-il toujours l’adresse du premier multiplet ? Par exemple, dans le cas d’un int, le pointeur sur int, contient-il l’adresse du multiplet de poids fort ou de poids faible ? Ou pointe-t-il toujours "la case de gauche" (peu importe son poids) ?

AScriabine

Le boutisme ne concerne que la représentation des entiers. L’adresse d’un entier référence toujours le premier multiplet qui le compose. Celui-ci sera toutefois le multiplet de poids faible ou de poids fort suivant le boutisme.

Il y a une ambiguïté que le cours ne lève pas sur les opérateurs de manipulation de bits. A priori un décalage de bits ne produit pas le même résultat en gros boutisme et petit boutisme : unsigned int a = 0x80000000; //a == 1000000000000000000000000000000. L’opération "a « 1" devrait, en petit boutisme, en décalant à gauche, conserver le 1 (car celui-ci arrive plus tard en mémoire) ! Et en gros boutisme, le 1 est "évacué". Il faudrait préciser explicitement que la question du boutisme est transparente pour le programmeur (on peut raisonner comme si la machine était en gros boutisme en bits et en octets, et le compilateur se débrouille pour que tout fonctionne). Cela est plus ou moins sous entendu lors de l’explication avec l’équivalence avec la division par deux mais cela reste un peu flou.

AScriabine

La question est traitée dans le chapitre sur la représentation des types, dans une infobulle. Il y est fait expressément mention des opérateurs de décalage. ;)

Pour répondre à l’injonction de ne pas poser des questions ici mais plutôt dans un forum, j’en prends acte et je vous remercie pour la précision. Cependant il se trouve que pour la très grande majorité des points que je soulève ici, il est important qu’ils soient portés à la connaissance des auteurs car ils soulèvent, à mon sens, des éléments du cours qui sont à améliorer car essentiels et pas assez développés. N’y voyez pas de mauvais jugement, je n’aurais pas perdu mon temps ici si je ne pensais pas que le tutoriel est de grande qualité. Cela reste à l’appréciation des auteurs de juger la pertinence de mes remarques, si elles ne sont pas pertinentes alors en effet je ferai plus attention, voire je me rétracterai.

AScriabine

Disons que s’il s’agit d’une question ou d’une incompréhension concernant le C, le forum est plus adapté (par exemple les questions de définition de type ou de multiplets). Si en revanche il s’agit d’un point d’amélioration relatif au tutoriel, les commentaires sont plus indiqués. ;)

+2 -0

Perso j’ai installé une version de MinGW (+ modif de la variable d’environnement, pour avoir la commande gcc) MSYS2 interfère avec un python déjà installé. De mémoire, il me semble que j’arrivais plus à me servir des commandes pip. En plus il installe plein de trucs totalement inutiles à un débutant en C. Évidemment, je peux me tromper par manque de recul. Mais intuitivement ça ne me semble pas être la meilleure solution. Sinon ça marche sous VSC avec MinGW et l’extension code runner, il me compile et run en 1 étape sans problème. Je pense qu’ajouter un print pour constater le résultat aurait pas été mal, quite à reporter les explications. du genre "on va maintenant ajouter deux lignes à notre code pour constater l’effet" zcc? bon vraiment je capte rien à cette 1ère page moi je fais juste gcc main.c -o main et c’est bon

+0 -0

Salut @zgorg2004,

Perso j’ai installé une version de MinGW (+ modif de la variable d’environnement, pour avoir la commande gcc) MSYS2 interfère avec un python déjà installé. De mémoire, il me semble que j’arrivais plus à me servir des commandes pip. En plus il installe plein de trucs totalement inutiles à un débutant en C. Évidemment, je peux me tromper par manque de recul. Mais intuitivement ça ne me semble pas être la meilleure solution.

zgorg2004

Msys2 installe un environnement similaire à un Unix, donc oui, c’est plus large qu’un compilateur.

Sinon ça marche sous VSC avec MinGW et l’extension code runner, il me compile et run en 1 étape sans problème.

Nous avons fait le choix lors de l’écriture du tutoriel de nous passer d’IDE. Le fait est que c’est un secteur qui évolue rapidement, qui nécessite de mettre à jour des screenshots et explications fréquemment et qui demande de prendre en main une GUI souvent ésotérique pour une débutant. Pour ces raisons, nous sommes partis sur le choix d’une compilation à la main.

Je pense qu’ajouter un print pour constater le résultat aurait pas été mal, quite à reporter les explications. du genre "on va maintenant ajouter deux lignes à notre code pour constater l’effet"

zgorg2004

Que veux-tu dire par « ajouter un print » ?

zcc? bon vraiment je capte rien à cette 1ère page moi je fais juste gcc main.c -o main et c’est bon

zgorg2004

Lis les explications d’installation, zcc est un alias, le but est de faire en sorte que le lecteur utilise certaines options de compilation.

+0 -0

Non il n’y a pas de problème pour programmer avec un macbook air M2. C’est largement assez puissant pour ça.

+1 -0

Bonjour! Je voudrais me mettre au langage C mais je voudrais savoir s’il est possible de programmer en C avec un macbook air M2 ? Ou si je dois changer pour un macbook pro ? :)

Iceprincess

fais juste attention de base tu as clang avec xcode (et pour le debugueur c’est lldb). Une fois que tu es alaise avec la compilation l’ide xcode n’est pas mauvais (c’est mon avis)

Bonjour à tous, mon premier post. Probablement le meilleur cours (et de très loin )sur le C que j’au eu l’occasion de voir sur le web. Clair, compréhensible, merci aux auteurs ! Et j’ai l’habitude des cours, puisque je suis moi-même formateur, mais en réseaux (Cisco) ;)

Ce cours m’est particulièrement utile pour me mettre au C sur les microcontrôleurs PIC, environnement (ou IDE) MPLAB X, et assembleur XC8. Ca change radicalement de l’assembleur, que je trouve nettement plus facile (j’ai appris sur du 6809 à l’époque, et je me suis régalé), mais il est quand même temps de se mettre à la page avec du C, et non plus de l’assembleur :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte