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

114 commentaires

Salut,

Je trouve cela un peu curieux (gcc 7.5.0). Quelqu’un pourrait-i-l vérifier de son côté ?

stéph

Je confirme avec GCC 8.3 et a priori c’est normal, le but est d’avertir qu’il « manque » des instructions break (dans le sens où c’est plus souvent un oubli qu’un souhait). ;)

+2 -0

Bonjour, premièrement merci beaucoup pour ce cours !

J’ai connais déjà les bases de la programmation (variables, if else, …) et j’ai appris il y a un bon moment le C avec le tuto de OC mais en l’absence de pratique j’ai quasiment tout oublié et je suis content de pouvoir réapprendre avec un cours de cette qualité.

J’en suis actuellement à la partie sur les boucles et j’ai un problème avec l’exercice sur les lapins : en lisant la correction je comprends l’algorithme mais je n’arrive pas à savoir comment on peut arriver à ce résultat à partir d’un simple énoncé. En gros ma question est comment on transforme une simple consigne/énoncé en algorithme ?

Bonjour, je t’invite à poser la question sur le forum directement. ^^

Section Programmation, ça sera bien plus pratique pour pouvoir te répondre.

Pour faciliter l’aide, tu peux copier l’énoncé de l’exercice où donner un lien directement vers l’énoncé.

+0 -0

Bonjour!

Tout d’abord, merci pour ce tutoriel (celui d’Open Classroom n’étant plus vraiment à jour aussi bien sur les bibliothèques que sur la norme du C enseignée)!

Ensuite, j’aimerais faire part d’une remarque au niveau du chapitre sur les chaînes de caractères. Au moment de la correction, la fonction donnée ne peut pas fonctionner puisque "c" est défini comme étant un int et non un char. Ensuite, je pense que ça aurait été utile de préciser que scanf() enregistre dans le buffer tout ce qui se trouve après un espace et rajoute un caractère de saut de ligne à la fin (si je ne me trompe pas). C’était un peu flou, et la fonction que j’ai écrit pour cet exercice fonctionnait mieux que ce à quoi je m’attendais pour cette raison ^^

Salut,

Tout d’abord, merci pour ce tutoriel (celui d’Open Classroom n’étant plus vraiment à jour aussi bien sur les bibliothèques que sur la norme du C enseignée)!

bryanetsesamis

Je suis heureux de lire que ce cours t’es utile. :)

Ensuite, j’aimerais faire part d’une remarque au niveau du chapitre sur les chaînes de caractères. Au moment de la correction, la fonction donnée ne peut pas fonctionner puisque "c" est défini comme étant un int et non un char.

bryanetsesamis

Est-ce que tu parles de la fonction strchr() ? Si oui, il n’y a pas d’erreur, c’est même le prototype donné par la norme (à quelques détails près). D’ailleurs, as-tu essayé le code avant de dire qu’il ne peut pas fonctionner ? ;)

Ceci étant dit, je réalise que ce point n’est pas abordé (emploi de int et non de char pour stocker un caractère). Je vais tâcher de voir où ajouter un mot à ce sujet, merci pour ce retour. :)

Ensuite, je pense que ça aurait été utile de préciser que scanf() enregistre dans le buffer tout ce qui se trouve après un espace et rajoute un caractère de saut de ligne à la fin (si je ne me trompe pas). C’était un peu flou, et la fonction que j’ai écrit pour cet exercice fonctionnait mieux que ce à quoi je m’attendais pour cette raison ^^

bryanetsesamis

Est-ce que tu peux détailler ce qui t’a posé problème ? Je ne comprends pas tout à fait à la lecture de ce passage.

+0 -0

Est-ce que tu parles de la fonction strchr() ? Si oui, il n’y a pas d’erreur, c’est même le prototype donné par la norme (à quelques détails près). D’ailleurs, as-tu essayé le code avant de dire qu’il ne peut pas fonctionner ? ;)

Ceci étant dit, je réalise que ce point n’est pas abordé (emploi de int et non de char pour stocker un caractère). Je vais tâcher de voir où ajouter un mot à ce sujet, merci pour ce retour. :)

C’est la fonction "lire_ligne" dont je parle, et je l’ai effectivement essayée: mon programme tournait dans le vide après l’entrée de la chaine jusqu’à ce que je remplace le "int" par "char".

Pour le problème du scanf(), c’est que j’ai cru comprendre que la fonction gardait en mémoire ce qui se trouvait après un espace dans le cas du %s ou un autre caractère dans le cas du %c, et qu’elle renvoyait ce qui se trouvait en mémoire à chaque nouvelle exécution de la fonction (vu que je peux rentrer plusieurs caractères en une seule fois et que la fonction lire_ligne effectue une boucle).

+0 -0
    for (i = 0; i < max - 1; ++i)
    {
        int c;

        if (scanf("%c", &c) != 1)
            return false;
        else if (c == '\n')
            break;

        chaine[i] = c;
    }

Parfois on utilise int pour récupérer des char pour stocker éventuellement une erreur. C’est le cas pas exemple de la fonction getchar().

Ici, on a c qui n’est pas initialisé, si c était initialisé ça fonctionnerait sans problème mais effectivement mettre char ici à plus de sens que mettre int car c’est scanf qui s’occupe de gérer les éventuelles erreurs.

Je me pose la question pourquoi ne pas avoir utiliser getchar() plutôt que scanf ?

En fait, il semble que @Taurre a dans un premier temps écrit un truc comme ça :

    for (i = 0; i < max - 1; ++i)
    {
        int c;

        if ( c = getchar(), c == EOF)
            return false;
        else if (c == '\n')
            break;

        chaine[i] = c;
    }

Puis a changé pour utiliser scanf. Je me demande pourquoi, mais il l’a certainement fait pour une bonne raison.

Par-contre, je ne comprend pas ta remarque sur scanf @bryanetsesamis. Il me semble que c’est exactement ce qu’indique le paragraphe chaînes de caractères avec des espaces du cours. Je ne t’accuse pas de ne pas lire, j’essaye de comprendre ce que tu n’as pas compris dans ce passage. Je ne suis pas sûr, mais je pense que ce que tu trouvais flou c’est le fait que « tout le monde\n » reste dans le buffer et est donc disponible pour la prochaine fois où on appelle scanf c’est ça ?

D’ailleurs, le caractère '\n' n’est pas vraiment rajouté par scanf, c’est toi qui le tape quand tu fais Entrée ;)

+0 -0

C’est la fonction "lire_ligne" dont je parle, et je l’ai effectivement essayée: mon programme tournait dans le vide après l’entrée de la chaine jusqu’à ce que je remplace le "int" par "char".

bryanetsesamis

Ah ! Oui, effectivement, là c’est une erreur, au temps pour moi. X/
Le format %c attend un char et non un int
Je vais corriger cela, merci de ton retour. :)

Je me pose la question pourquoi ne pas avoir utiliser getchar() plutôt que scanf ?

ache

C’est un choix « pédagogique » ici. Je préfère réserver getchar() et cie pour les chapitres sur les fichiers. Comme scanf() a déjà été présentée à ce stade, cela m’évite de parler de trop de choses. :)

Pour le problème du scanf(), c’est que j’ai cru comprendre que la fonction gardait en mémoire ce qui se trouvait après un espace dans le cas du %s ou un autre caractère dans le cas du %c, et qu’elle renvoyait ce qui se trouvait en mémoire à chaque nouvelle exécution de la fonction (vu que je peux rentrer plusieurs caractères en une seule fois et que la fonction lire_ligne effectue une boucle).

bryanetsesamis

Ah ! Ok, je comprends ce que tu veux dire.
Eh bien, c’est bien vu comme raisonnement et effectivement, les données que tu entres lors d’une saisie sont temporisées (et donc conservées dans un tampon). Lorsqu’il s’agit de données en provenance d’un périphérique interactif (comme un terminal), tout est stocké jursqu’à ce que tu entres un saut de ligne (ce saut de ligne étant également stocké). Ceci étant dit, ce mécanisme n’est pas propre à scanf(), mais est plus général que cela. Il est expliqué plus en détails plus tard, dans les chapitres sur les fichiers. ;)

+0 -0

Bonjour j’espère que vous allez bien . Je viens ici pour demander quelque explication sur les chaînes de caractères. En effet j’ai un projet en language C ou je dois faire des substitutions de lettre dans des chaînes de caractères. Pour ce faire je dois utiliser les fonctions comme malloc calloc etc…. Le problème c’est que je n’ai pas d’idée sur la marche à suivre pour créer la fonction qui va me permettre de faire des substitutions. Quelqu’un pourrait m’aider svp ?

+0 -0

Bonjour,

Je suis ici pour une suggestion d’amélioration sur un point du cours. J’espère que c’est bien ici que je suis censé poster ceci. Voici donc ma suggestion :

Dans la partie sur les structures, il y a des explications sur les contraintes d’alignement mémoire des différents types, il manque cependant une conclusion sur, finalement, comment savoir "à l’avance" la taille d’une structure donnée. On comprend bien comment sont alignées les données, mais on ne sait pas si le bloc mémoire de la structure s’arrête forcément à la fin d’un mot mémoire, ou bien à la fin du bloc de son dernier membre. Ce serait l’information manquante pour bien clôturer ce chapitre.

Bonne continuation et merci pour ce tutoriel exhaustif et de grande qualité pédagogique

Bonjour

Bonjour. :)

Je suis ici pour une suggestion d’amélioration sur un point du cours. J’espère que c’est bien ici que je suis censé poster ceci.

Tout à fait. ;)

Voici donc ma suggestion :

Dans la partie sur les structures, il y a des explications sur les contraintes d’alignement mémoire des différents types, il manque cependant une conclusion sur, finalement, comment savoir "à l’avance" la taille d’une structure donnée. On comprend bien comment sont alignées les données, mais on ne sait pas si le bloc mémoire de la structure s’arrête forcément à la fin d’un mot mémoire, ou bien à la fin du bloc de son dernier membre. Ce serait l’information manquante pour bien clôturer ce chapitre.

Je ne suis pas certains de comprendre le point. La taille finale d’une structure est donnée par l’opérateur sizeof. Concernant l’alignement, les contraintes sont appliquées pour chaque champ de la structure. De ce fait, la structure ne se termine pas forcément sur un mot mémoire. Si je reprends l’exemple du chapitre du cours, si le dernier champ de la structure est un int, il prendra 4 octets sur les huit que compte un mot mémoire. Il est correctement aligné, mais ne prend pas le mot complet.

+1 -0

Bonjour,

Nouvelle proposition,

[chapitre sur les chaines de caractères]

La définition de la fonction bool lireLigne(blabla) suppose que le lecteur connaisse la chose suivante :

lors du premier passage sur la ligne : scanf("%c", &c); l’utilisateur va pouvoir entrer une chaine qui sera stockée dans le buffer clavier et à chaque fois que scanf sera ré-appelée elle ira piocher un caractère dans le buffer pour s’en servir, ainsi l’utilisateur n’aura pas à ré-entrer de chaine tant que ce buffer clavier n’aura pas été entièrement vidé par les appels successifs de scanf.

Ce fonctionnement de scanf n’a me semble-t-il pas été présenté auparavant dans ce cours, ce qui rend la compréhension du code présenté assez fastidieuse il me semble.

Merci encore pour ce cours

Bonjour,

Dans le chapitre sur les fichier(2), dans le paragraphe sur l’explication de fseek, cas des flux de texte, je ne comprends pas d’où sort le deuxième point : pourquoi faire appel à ftell au préalable change quelque chose ? Le paramètre reste un long, non ?

Et pour le point juste au dessus, si j’ai bien compris, cela veut dire qu’on ne peut se placer que sur les repères en macro et pas ailleurs ?

Pourriez vous aussi préciser pourquoi on a de telles limitations ? Je ne trouve pas une description similaire à la votre sur internet (en français du moins)…

Bonjour,

Dans le chapitre sur les fichier(2), dans le paragraphe sur l’explication de fseek, cas des flux de texte, je ne comprends pas d’où sort le deuxième point : pourquoi faire appel à ftell au préalable change quelque chose ? Le paramètre reste un long, non ?

Il s’agit d’une contrainte imposée par la norme. Je ne sais pas spécifiquement pourquoi cette contrainte existe, les flux textes n’existent pas sous Linux et *BSD et ce sont ces systèmes que j’utilise. Cela étant, les flux textes ont une sémantique particulière, notamment certains caractères spécifiques sont interprétés et il n’est donc pas forcément bienvenue de sauter n’importe où lors de la lecture ou de l’écriture.

For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET.

ISO/IEC 9899:201x, doc. N1570, § 7.21.9.2 The fseek function, al. 4, p. 336

Et pour le point juste au dessus, si j’ai bien compris, cela veut dire qu’on ne peut se placer que sur les repères en macro et pas ailleurs ?

AScriabine

C’est plus restrictif que cela, comme décrit pour les fichiers textes et binaires.

Pourriez vous aussi préciser pourquoi on a de telles limitations ? Je ne trouve pas une description similaire à la votre sur internet (en français du moins)…

AScriabine

Pour les flux binaires, c’est parce qu’il est possible que le fichier contienne des bytes nuls à sa fin.

Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END) , has undefined behavior for a binary stream (because of possible trailing null characters) or for any stream with state-dependent encoding that does not assuredly end in the initial shift state.

ISO/IEC 9899:201x, doc. N1570, § 7.21.3 Files, note 268, p. 301
+1 -0

Bonjour,

Dans le chapitre sur les chaines de caractères, on présente l’initialisation suivante pour les chaines de caractères : char* chaine = "coucou"; et on précise que la chaine n’est pas modifiable ensuite, car la chaine "coucou" est une constante. Je me demande pourquoi cette syntaxe est acceptée, alors qu’on n’a pas précisé que chaine est un pointeur constant. Habituellement, quand on essaye d’affecter la valeur d’un pointeur à un autre, il faut s’assurer qu’on n’a pas une syntaxe du genre <pointeur simple> = <pointeur en lecture seule> (erreur de compilation). Or là cela ne provoque pas d’erreur. Quelqu’un aurait une idée ?

Merci d’avance :)

+0 -0

Il manque peut-être une précision dans les fichier(2) sur la fonction ungetc. A priori (rien n’est précisé) on imagine que ungetc va écrire sur le premier multiplet du tampon du flux et va donc écraser la valeur qui était présente. Mais après quelques tests (cela peut aussi être déduit d’une lecture particulièrement minutieuse du code proposé en illustration), il s’avère que le caractère est seulement "inséré" (tout le reste du tampon est décalé), si bien que le premier élément en attente dans le tampon n’est pas écrasé.

Après lecture de toutes les parties sur les fichiers, et de quelques tests personnels il apparaît que finalement on ne peut pas écrire au beau milieu d’un fichier mais seulement à la fin ? Cela est compréhensible car finalement, écrire au milieu d’un fichier reviendrait à tout décaler en mémoire, ce qui est une opération sans doute plus complexe. Y a-t-il des fonction en C dans la librairie standard permettant ce genre de choses ? Quelqu’un pourrait, en quelques mots, expliquer comment fonctionne un simple éditeur de texte ? Ou renvoyer vers des articles du net traitant de ce sujet, qui seraient abordables en ayant suivi ce cours ?

Dans le chapitre sur les chaines de caractères, on présente l’initialisation suivante pour les chaines de caractères : char* chaine = "coucou"; et on précise que la chaine n’est pas modifiable ensuite, car la chaine "coucou" est une constante. Je me demande pourquoi cette syntaxe est acceptée, alors qu’on n’a pas précisé que chaine est un pointeur constant. Habituellement, quand on essaye d’affecter la valeur d’un pointeur à un autre, il faut s’assurer qu’on n’a pas une syntaxe du genre <pointeur simple> = <pointeur en lecture seule> (erreur de compilation). Or là cela ne provoque pas d’erreur. Quelqu’un aurait une idée ?

Merci d’avance :)

AScriabine

Remarque tout à fait pertinente. :)
En fait, nous utilisons un raccourci ici qui tient au fait que modifier une chaîne de caractère littérales est un comportement indéfini.

It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

ISO/IEC 9899:201x, doc. N1570, § 6.4.5 String literals, al. 7, p. 71

Cela étant, une chaîne littérale reste un tableau de char sans qualificateur comme const.

Il manque peut-être une précision dans les fichier(2) sur la fonction ungetc. A priori (rien n’est précisé) on imagine que ungetc va écrire sur le premier multiplet du tampon du flux et va donc écraser la valeur qui était présente. Mais après quelques tests (cela peut aussi être déduit d’une lecture particulièrement minutieuse du code proposé en illustration), il s’avère que le caractère est seulement "inséré" (tout le reste du tampon est décalé), si bien que le premier élément en attente dans le tampon n’est pas écrasé.

AScriabine

Effectivement, je vais préciser que cette fonction ajoute un caractère, mais n’écrase pas ceux déjà présents.

Après lecture de toutes les parties sur les fichiers, et de quelques tests personnels il apparaît que finalement on ne peut pas écrire au beau milieu d’un fichier mais seulement à la fin ? Cela est compréhensible car finalement, écrire au milieu d’un fichier reviendrait à tout décaler en mémoire, ce qui est une opération sans doute plus complexe. Y a-t-il des fonctions en C dans la librairie standard permettant ce genre de choses ? Quelqu’un pourrait, en quelques mots, expliquer comment fonctionne un simple éditeur de texte ? Ou renvoyer vers des articles du net traitant de ce sujet, qui seraient abordables en ayant suivi ce cours ?

AScriabine

Il est possible d’écrire au milieu d’un fichier, cependant ce qui sera écrit écrasera le contenu qui occupait la même position. Un fichier peut-être vu comme une bande magnétique : si l’on revient en arrière et que l’on écrit, on écrit par-dessus les données précédentes.

En règle générale, les éditeurs de textes chargent le contenu en mémoire sous forme d’une liste chaînée (un nœud par ligne) et manipule cette liste.

+1 -0

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…")

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