Académique Documents
Professionnel Documents
Culture Documents
S'autoformer
C
24
heures
Tony Zhang
DEUXIÈME ÉDITION
Michel Stephens
Deuxième édition
RÉDACTEUR DES ACQUISITIONS
Tous les droits sont réservés. Aucune partie de ce livre ne doit être reproduite, stockée ÉDITEUR DE DÉVELOPPEMENT
dans un système de récupération ou transmise par quelque moyen que ce soit, électronique, Gus A Miklos
mécanique, photocopie, enregistrement ou autre, sans l'autorisation écrite de l'éditeur.
DIRECTEUR DE LA RÉDACTION
Aucune responsabilité de brevet n'est assumée en ce qui concerne l'utilisation des informations
Charlotte Clapp
contenues dans ce document. Bien que toutes les précautions aient été prises lors de la
préparation de ce livre, l'éditeur et l'auteur déclinent toute responsabilité en cas d'erreur ou ÉDITEUR DE PROJET
d'omission. De même, aucune responsabilité n'est assumée pour les dommages résultant de Andy Beaster
l'utilisation des informations contenues dans ce document.
ÉDITEUR DE COPIE
Numéro international normalisé du livre : 067231861x Kate Givens
Christine Nelsen
Imprimé aux ÉtatsUnis d'Amérique
Déborah Hittel
Première impression : février 2000
RELECTEUR
RÉDACTEUR TECHNIQUE
Marques de commerce Bill Mitchell
Tous les termes mentionnés dans ce livre qui sont connus pour être des marques commerciales ou COORDONNATEUR D' ÉQUIPE
des marques de service ont été correctement mis en majuscules. Sams Publishing ne peut attester de Pamalée Nelson
l'exactitude de ces informations. L'utilisation d'un terme dans ce livre ne doit pas être considérée comme
DESIGNER D' INTÉRIEUR
affectant la validité d'une marque commerciale ou d'une marque de service.
Gary Adair
Aren Howell
Tous les efforts ont été faits pour rendre ce livre aussi complet et aussi précis que
possible, mais aucune garantie ou adéquation n'est implicite. Les informations fournies COPYWRITER
sont sur une base "telle quelle". L'auteur et l'éditeur déclinent toute responsabilité visàvis Eric Borgert
de toute personne ou entité en cas de perte ou de dommage résultant des informations
ASSISTANTE ÉDITORIALE
contenues dans ce livre.
Angela Boley
PRODUCTION
Stacey De Rome
Marc Walchle
Machine Translated by Google
Contenu vii
Heure 9 Travailler avec des modificateurs de données et des fonctions mathématiques 141
Contenu ix
Contenu xii
Contenu xiii
Contenu xv
Heure 9, « Travailler avec des modificateurs de données et des fonctions mathématiques » ......455
Quiz ........ .................................................. .................................................. ....455
Des exercices ................................................. .................................................. .....456
Indice 503
Machine Translated by Google
A propos de l'auteur
TONY ZHANG a plus de 15 ans d'expérience dans la programmation informatique et la conception de
systèmes d'information à l'échelle de l'entreprise. Il travaille actuellement pour l'une des « 5 grandes »
sociétés de conseil spécialisées dans la conception, le développement et la mise en œuvre d'infrastructures
liées aux affaires électroniques.
Titulaire d'une maîtrise en physique, il a publié des dizaines d'articles de recherche sur les lasers et
la programmation informatique. Parmi ses grands intérêts figurent la peinture à l'huile et la
photographie, les deux choses que Tony aime le plus.
Vous pouvez contacter Tony via Sams Publishing ou en lui envoyant un email
à tyc24h@hotmail.com.
Dévouement
À ma femme, Ellen, et à mes parents, Zhiying et Bingrong, pour leur amour et leurs inspirations.
—Tony Zhang
Remerciements
Tout d'abord, je voudrais remercier les lecteurs de la première édition du livre pour leurs encouragements,
leur patience, leurs commentaires et surtout leurs critiques, qui ont rendu la deuxième édition plus
adaptée aux personnes qui souhaitent se lancer dans la programmation en C monde.
C'est pour moi un grand plaisir de travailler avec l'éditrice Sharon Cox pour la deuxième fois. Je
tiens à remercier les éditeurs Carol Ackerman et Gus Miklos, ainsi que l'auteur contributeur John
Southmayd pour leur excellent travail qui a rendu la deuxième édition du livre plus accessible et en
grande partie, sinon complètement, sans erreur. De plus, j'aimerais exprimer mon appréciation pour
l'excellent travail des autres membres de l'équipe de rédaction. Ensemble, ils ont rendu possible la deuxième édition.
J'apprécie grandement l'amour et le soutien de ma femme, Ellen, qui m'inspire à regarder le monde
de la technologie sous différents angles. C'est toujours une grande joie de discuter avec elle de
questions de philosophie et de littérature. Mes parents, que je ne remercierai jamais assez, m'ont donné
non seulement de l'amour et de l'affection, mais aussi l'opportunité de recevoir la meilleure éducation
que j'aie jamais pu avoir quand j'étais en Chine.
Machine Translated by Google
En tant qu'éditeur associé pour Sams, j'apprécie vos commentaires. Vous pouvez me faxer, m'envoyer un e
mail ou m'écrire directement pour me faire savoir ce que vous avez aimé ou non dans ce livre, ainsi que ce
que nous pouvons faire pour rendre nos livres plus solides.
Veuillez noter que je ne peux pas vous aider avec des problèmes techniques liés au sujet de ce livre, et
qu'en raison du volume élevé de courrier que je reçois, je ne pourrai peutêtre pas répondre à
chaque message.
Lorsque vous écrivez, assurezvous d'inclure le titre et l'auteur de ce livre ainsi que votre nom et votre
numéro de téléphone ou de télécopieur. Je vais examiner attentivement vos commentaires et les partager
avec l'auteur et les éditeurs qui ont travaillé sur le livre.
Fax: 3175814770
Courriel : michael.stephens@macmillanusa.com Courriel :
Michael Stephens Éditeur associé
Éditions Sams
201 103e rue Ouest
Introduction
Si l'on apprend des autres mais ne pense pas, on sera désorienté ; Si l'on pense mais
—Confucius
Sur la base du succès de la première édition du livre et des commentaires des lecteurs, nous avons réécrit ou modifié
chaque chapitre du livre pour rendre la deuxième édition plus adaptée aux débutants comme vous qui veulent
commencer avec le langage de programmation C le plus rapidement possible.
Bien sûr, il est tout à fait normal de passer plus de 24 heures pour vraiment comprendre les concepts et les
compétences de programmation introduits dans le livre. Cependant, la bonne nouvelle est que ce livre propose de
nombreux exemples de programmes et d'exercices avec des explications et des réponses claires, ce qui facilite la
compréhension des concepts du langage C.
En fait, Teach Yourself C in 24 Hours vous fournit un bon point de départ pour la programmation en C. Il couvre
des sujets importants en programmation C et établit une base solide pour un débutant sérieux comme vous. Après
avoir lu ce livre, vous serez capable d'écrire des bases en C pro
grammes par vousmême.
Vous tirerez profit de la lecture de ce livre lorsque vous commencerez à appliquer des programmes C à des
problèmes réels ou que vous passerez à l'apprentissage d'autres langages de programmation, tels que Perl, C++ et Java.
Particularités de ce livre
Ce livre contient les éléments spéciaux suivants qui vous permettent d'assimiler plus simplement et plus clairement
les fonctionnalités et concepts rudimentaires du C au fur et à mesure qu'ils sont introduits :
• Boîtes de syntaxe
• Remarques
• Précautions
• Conseils
Machine Translated by Google
Les encadrés de syntaxe expliquent certaines des fonctionnalités les plus compliquées du C, telles que les
structures de contrôle. Chaque boîte de syntaxe consiste en une définition formelle de la caractéristique suivie
d'une explication. Voici un exemple de boîte de syntaxe :
Ici, la taille spécifie le nombre d'octets de stockage à allouer. Le fichier d'entête, stdlib.h, doit être
inclus avant que la fonction malloc() puisse être appelée. Étant donné que la fonction malloc() renvoie un
pointeur vide , son type est automatiquement converti en type de pointeur sur le côté gauche d'un opérateur
, d'affectation.
(Vous en apprendrez plus sur la fonction malloc() plus loin dans le livre.)
Les notes sont des explications des propriétés intéressantes d'une fonctionnalité particulière du programme
C. Examinons l'exemple de note suivant :
Dans une sortie justifiée à gauche, la valeur affichée apparaît à l'extrémité gauche du champ de valeur.
Dans une sortie justifiée à droite, la valeur affichée apparaît à l'extrémité droite du champ de valeur.
Les avertissements vous avertissent des pièges de programmation que vous devez éviter. Voici un avertissement typique :
N'utilisez jamais les mots clés réservés en C, ni les noms des fonctions de la bibliothèque C comme
noms de variables dans votre programme.
Les astuces sont des conseils pour mieux écrire vos programmes C. Voici un exemple de conseil :
Exemples de programmation
Comme mentionné précédemment, ce livre contient de nombreux exemples de programmation utiles avec des
explications. Ces exemples sont destinés à vous montrer comment utiliser différents types de données et
fonctions fournis en C.
Machine Translated by Google
Introduction 3
Chaque exemple a une liste du programme C; la sortie générée à partir de cette liste suivra. L'exemple
propose également une analyse du fonctionnement du programme. Des icônes spéciales sont utilisées
pour souligner chaque partie de l'exemple : Type, Entrée/Sortie et Analyse.
Dans l'exemple présenté dans le Listing IN.1, il existe des conventions typographiques spéciales.
L'entrée que vous entrez est affichée en caractères gras à espacement fixe, et la sortie générée par le
programme exécutable du Listing IN.1 est affichée en caractères à espacement fixe.
int ch ;
12 : }
À la ligne 2 du Listing IN.1, le fichier d'entête stdio.h est inclus pour les fonctions getc() et
UNE ANALYSE
printf() utilisées dans le programme. Les lignes 4 à 12 donnent le nom et le corps
de la fonction main() .
À la ligne 6, une variable entière ch est déclarée, qui est affectée à la valeur de retour de la fonction
getc() plus loin à la ligne 9. La ligne 8 imprime un message demandant à l'utilisateur d'entrer un caractère
au clavier. La fonction printf() de la ligne 8 utilise la sortie standard par défaut stdout pour afficher les
messages à l'écran.
À la ligne 9, l'entrée standard stdin est transmise à la fonction getc() , qui indique que le flux de fichiers
provient du clavier. Une fois que l'utilisateur a saisi un caractère, la fonction getc() renvoie la valeur
numérique (c'estàdire un entier) du caractère. Notez qu'à la ligne 9, la valeur numérique est affectée à la
variable entière ch.
Machine Translated by Google
Questionsréponses et atelier
Chaque heure (c'estàdire chaque chapitre) se termine par une section Q&A qui contient des réponses aux questions
courantes relatives à la leçon du chapitre. Après la section Q&A, il y a un atelier qui consiste en des questions de quiz et
des exercices de programmation. Les réponses à ces questions de quiz et des exemples de solutions pour les exercices
sont présentés à l'annexe D, « Réponses au quiz et aux exercices ».
Pour vous aider à consolider votre compréhension de chaque leçon, nous vous encourageons à essayer de
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier.
• Le code C réel est composé dans une police spéciale à espacement fixe . Vous verrez cette police utilisée dans
des listes, des exemples d'entrée/sortie et des extraits de code. Dans l'explication des fonctionnalités C, les
commandes, les noms de fichiers, les instructions, les variables et tout texte que vous voyez à l'écran sont
également composés dans cette police. • L'entrée de commande et tout ce que vous êtes censé entrer apparaît
en gras
police monospace . Vous le verrez principalement dans les sections Entrée/Sortie des exemples. • Les
espaces réservés dans les descriptions de syntaxe apparaissent dans une police italique à espacement fixe .
Remplacez l'espace réservé par le nom de fichier réel, le paramètre ou tout autre élément qu'il représente
envoie.
• Les italiques mettent en évidence les termes techniques lorsqu'ils apparaissent pour la première fois dans le texte et
sont parfois utilisés pour souligner des points importants.
L'heure 1, "Faire le premier pas", vous présente le langage C, la norme ANSI et les exigences logicielles et
matérielles de base pour la programmation en C.
L' heure 2, "Votre premier programme C", montre toute la procédure d'écriture, de compilation, de liaison et
d'exécution d'un programme C.
Machine Translated by Google
Introduction 5
L'heure 3, "Apprendre la structure d'un programme C", vous apprend plusieurs concepts importants, tels que les
constantes, les variables, les expressions et les instructions. L'anatomie d'une fonction est également introduite
dans cette heure.
L'heure 4, « Comprendre les types de données et les mots clés », répertorie tous les mots clés C réservés.
Quatre types de données, char, int, float et double, sont présentés en détail. De plus, les règles pour
nommer une variable sont expliquées.
L'heure 5, "Gestion des entrées et sorties standard", vous apprend à recevoir des entrées du clavier et
à imprimer des sorties à l'écran à l'aide d'un ensemble de fonctions C, telles que getc(), getchar(),
putc(), putchar() et printf().
La partie II, « Opérateurs et instructions de flux de contrôle », met l'accent sur les opérateurs et les instructions de flux
de contrôle en C. Voici un résumé de ce que vous apprendrez :
L'heure 6, « Manipulation des données », vous apprend à utiliser les opérateurs d'affectation arithmétique,
l'opérateur moins unaire, les opérateurs d'incrémentation/décrémentation, les opérateurs relationnels et l'opérateur
de transtypage.
L'heure 7, "Travailler avec des boucles", présente la boucle (c'estàdire l'itération) avec les instructions for, while
ou dowhile .
L'heure 8, "Utilisation des opérateurs conditionnels", vous en dit plus sur les opérateurs, tels que les opérateurs
logiques, les opérateurs au niveau du bit, l' opérateur sizeof et l'opérateur ? , qui sont fréquemment utilisés en C.
L'heure 9, "Travailler avec les modificateurs de données et les fonctions mathématiques", décrit comment utiliser
les modificateurs de données pour activer ou désactiver le bit de signe ou modifier la taille d'un type de données.
En outre, plusieurs fonctions mathématiques fournies par C sont introduites.
L'heure 10, "Contrôle du flux de programme", présente toutes les instructions de flux de contrôle
utilisées en C. Il s'agit des instructions if, ifelse, switch, break, continue et goto .
Les pointeurs et les tableaux sont abordés dans la partie III, « Pointeurs et tableaux ». Voici un résumé de ce que
vous apprendrez :
L'heure 11, "Comprendre les pointeurs", vous apprend à référencer des variables avec des pointeurs. Des
concepts tels que la valeur de gauche et la valeur de droite sont également introduits.
L'heure 12, « Comprendre les tableaux », explique comment déclarer et initialiser des tableaux.
La relation entre le tableau et le pointeur en C est également discutée.
L'heure 13, "Manipulation de chaînes" se concentre sur la lecture et l'écriture de chaînes. Plusieurs
fonctions de la bibliothèque C, telles que strlen(), strcpy(), gets(), puts() et scanf(), sont introduites
pour manipuler les chaînes.
L'heure 14, « Comprendre la portée et les classes de stockage », présente la portée du bloc, la portée
de la fonction, la portée du programme et la portée du fichier. En outre, les spécificateurs ou
modificateurs de classe de stockage, tels que auto, static, register, extern, const et volatile sont expliqués.
Machine Translated by Google
La partie IV, « Fonctions et allocation dynamique de mémoire », se concentre sur les fonctions et les
allocations dynamiques de mémoire en C. Voici un résumé de ce que vous apprendrez :
L'heure 15, « Travailler avec les fonctions », décrit la déclaration et la définition de la fonction en C. Le
prototypage de la fonction est expliqué, ainsi que la spécification du type de retour de la fonction.
L'heure 16, « Appliquer des pointeurs » , vous apprend à effectuer des opérations arithmétiques sur les
pointeurs, à accéder aux éléments de tableaux avec des pointeurs et à passer des pointeurs à des fonctions.
L'heure 17, « Allocation de mémoire », explique le concept d'allocation dynamique de mémoire. Les
fonctions C, telles que malloc(), calloc(), realloc() et free(), sont introduites en ce qui concerne l'allocation
de mémoire dynamique.
L'heure 18, "Utilisation de types de données et de fonctions spéciales", présente le type de données enum
et l'utilisation de typedef. La récursivité des fonctions et les arguments de ligne de commande de la fonction
main() sont également enseignés dans l'heure 18.
La partie V, « Structure, union, E/S de fichiers, etc. », traite des structures, des unions et des E/S de fichiers de
disque en C. Voici un résumé de ce que vous apprendrez :
L'heure 19, « Comprendre les structures », présente le type de données de structure . Vous apprenez
à accéder aux membres de la structure et à passer des structures aux fonctions à l'aide de pointeurs. Les
structures imbriquées et de référencement vers l'avant sont également abordées au cours de cette heure.
L' heure 20, « Comprendre les syndicats », décrit le type de données du syndicat et la différence entre le
syndicat et la structure. Les applications des unions sont démontrées dans plusieurs exemples.
L'heure 21, "Lecture et écriture avec des fichiers", explique les concepts de fichier et de
flux en C. Les bases de l'entrée et de la sortie de fichiers sur disque sont introduites dans
cette première partie. Les fonctions C suivantes, ainsi que plusieurs exemples, sont
introduites dans cette heure : fopen(), fclose(), fgetc(), fputc(), fgets(), fputs(), fread(),
fwrite() et feof ().
L'heure 22, "Utilisation des fonctions de fichiers spéciales", est la deuxième partie des E/S de fichiers
sur disque, dans laquelle fseek(), ftell() et rewind() sont introduits pour montrer comment ils peuvent
vous aider à obtenir un accès aléatoire au disque des dossiers. De plus, les fonctions fscanf(), fprintf()
et freopen() sont enseignées et appelées dans des exemples de programmes.
Introduction 7
L'heure 24, "Où allezvous à partir d'ici ?", résume les concepts et fonctionnalités importants introduits
dans ce livre. De plus, le style de programmation, la programmation modulaire et le débogage sont
expliqués brièvement. Une liste de livres C recommandés est fournie pour vos lectures ultérieures.
Maintenant, vous êtes prêt à commencer le voyage d'apprentissage du langage C, alors que le monde
est entré dans un nouveau millénaire. Amusezvous à lire ce livre et amusezvous à programmer en C !
Tony Zhang
Centreville, Pennsylvanie
janvier 2000
Machine Translated by Google
Machine Translated by Google
PARTIE I
Les bases du C
Heure
1 Faire le premier pas
HEURE 1
Faire le premier pas
Un voyage de mille miles commence par le premier pas.
Proverbe chinois
—Aristophane
Bienvenue à Teach Yourself C en 24 heures. Dans cette première leçon, vous apprendrez ce qui
suit :
• Qu'estce que C ?
• La norme ANSI
12 Heure 1
Qu'estce que C?
C est un langage de programmation. Le langage C a été développé pour la première fois en 1972 par
Dennis Ritchie chez AT&T Bell Labs. Ritchie a appelé son nouveau langage C simplement parce qu'il
existait déjà un langage de programmation B. (En fait, la langue B a conduit au développement de C.)
C est un langage de programmation de haut niveau. En fait, C est l'un des langages de programmation
à usage général les plus populaires.
Dans le monde informatique, plus un langage de programmation est éloigné de l'architecture informatique,
plus le niveau du langage est élevé. Vous pouvez imaginer que les langages de plus bas niveau sont des
langages machine que les ordinateurs comprennent et exécutent directement. Les langages de
programmation de haut niveau, en revanche, sont plus proches de nos langages humains (voir Figure 1.1).
FIGURE 1.1
Haute
La spécification de langue Si la ligne n'est
Si (ligne ! = occupé)
connexion (Internet) ;
Le langage de programmation de haut sinon attendez (5)...
niveau (par exemple, C)
Bas
Les langages de programmation de haut niveau, dont le C, présentent les avantages suivants :
Portabilité : les programmes sont faciles à transférer sur différentes platesformes informatiques.
Machine Translated by Google
La lisibilité et la maintenabilité du langage C bénéficient directement de sa relative proximité avec les langages
humains, en particulier l'anglais.
1
Chaque langage de haut niveau a besoin d'un compilateur ou d'un interpréteur pour traduire les instructions
écrites dans le langage de programmation de haut niveau en un langage machine qu'un ordinateur peut
comprendre et exécuter. Différentes machines peuvent nécessiter différents compilateurs ou interpréteurs pour
le même langage de programmation. Par exemple, j'utilise le compilateur C de Microsoft pour compiler les
programmes C de ce livre pour mon ordinateur personnel (PC). Si j'ai besoin d'exécuter les programmes C sur un
poste de travail basé sur UNIX, je dois utiliser un autre type de compilateur C pour compiler ces programmes. Par
conséquent, la portabilité des programmes écrits en C est réalisée en recompilant les programmes avec différents
compilateurs pour différentes machines (voir Figure 1.2).
FIGURE 1.2
Le C
Portage de programmes Programme
14 Heure 1
Cependant, un programme informatique écrit dans un langage de haut niveau, tel que C, Java ou Perl,
n'est qu'un fichier texte, composé de caractères et de mots de type anglais. Vous devez utiliser des
programmes spéciaux, appelés compilateurs ou interpréteurs, pour traduire un tel programme en un code
lisible par machine. C'estàdire que le format texte de toutes les instructions écrites dans un langage de
haut niveau doit être converti en format binaire. Le code obtenu après la traduction est appelé code binaire.
Avant la traduction, un programme au format texte est appelé code source.
La plus petite unité de code binaire est appelée un bit (de chiffre binaire), qui peut avoir une valeur de 0 ou
1. Généralement, huit bits constituent un octet et un demioctet (quatre bits) est un quartet.
De plus, le langage C présente d'autres avantages. Les programmes écrits en C peuvent être réutilisés.
Vous pouvez enregistrer des parties de vos programmes C dans un fichier de bibliothèque et les invoquer dans
votre prochain projet de programmation simplement en incluant le fichier de bibliothèque. De nombreuses tâches
de programmation courantes et utiles sont déjà implémentées dans les bibliothèques fournies avec les compilateurs.
De plus, les bibliothèques vous permettent de libérer facilement la puissance et les fonctionnalités du système
d'exploitation que vous utilisez. Plus de détails sur l'utilisation des fonctions de la bibliothèque C sont couverts
dans le reste de ce livre.
C est un langage de programmation relativement petit, ce qui vous facilite la vie. Vous n'avez pas besoin de vous
rappeler de nombreux motsclés ou commandes C avant de commencer à écrire des programmes en C pour
résoudre des problèmes dans le monde réel.
Pour ceux qui recherchent la rapidité tout en gardant la commodité et l'élégance d'un langage de haut niveau,
le langage C est probablement le meilleur choix. En fait, C vous permet de prendre le contrôle du matériel
informatique et des périphériques. C'est pourquoi le langage C est parfois appelé le langage de programmation
de haut niveau le plus bas.
De nombreux autres langages de haut niveau ont été développés sur la base de C. Par exemple, Perl est un
langage de programmation populaire dans la conception du World Wide Web (WWW) sur Internet.
Perl emprunte en fait beaucoup de fonctionnalités au C. Si vous comprenez le C, apprendre Perl est un jeu
d'enfant. Un autre exemple est le langage C++, qui est simplement une version étendue de C, bien que C++
facilite la programmation orientée objet. De plus, apprendre Java devient beaucoup plus facile si vous connaissez
déjà C.
1
le code peut être enregistré dans un fichier d'application. Vous pouvez continuer à exécuter le
fichier d'application sans le compilateur, sauf si le programme (code source) est mis à jour et que vous
devez le recompiler. Le code binaire ou fichier d'application est également appelé code exécutable (ou
fichier exécutable).
D'un autre côté, un programme écrit dans un langage interprété peut être exécuté immédiatement
après que vous ayez fini de l'écrire — ou d'ailleurs, pendant que vous l'écrivez ! Mais un tel
programme a toujours besoin d'un interpréteur pour traduire les instructions de haut niveau en
instructions compréhensibles par la machine (code binaire) au moment de l'exécution. Vous ne
pouvez pas exécuter le programme sur une machine à moins que le bon interprète ne soit disponible.
Vous pouvez considérer le langage C comme un langage compilé car la plupart des fournisseurs
de langage C ne fabriquent que des compilateurs C, par opposition aux interpréteurs, pour prendre
en charge les programmes écrits en C.
La norme ANSI C
Pendant de nombreuses années, la norme de facto pour le langage de programmation C était le livre
The C Programming Language, écrit par Brian Kernighan et Dennis Ritchie en 1978. Ce livre est
communément connu dans la communauté de la programmation sous le simple nom de K&R (faisant
référence aux initiales du auteurs) et trouve une place sur les étagères de nombreux programmeurs à
ce jour. Cependant, le livre a été écrit comme un didacticiel d'introduction au C, et non comme une
norme complète ou officielle pour le langage. Au fur et à mesure que différents fournisseurs proposaient
diverses implémentations du langage C, des différences entre ces implémentations ont commencé à apparaître.
La norme ANSI pour C améliore la norme K&R d'origine et définit un groupe de fonctions C
couramment utilisées connues sous le nom de bibliothèque standard ANSI C. Dans la plupart des cas,
les compilateurs C incluent la bibliothèque standard, ainsi que d'autres bibliothèques pour fournir
d'autres fonctions spécifiques au compilateur.
Machine Translated by Google
16 Heure 1
Ce livre se concentre sur les fonctions C définies dans la norme ANSI, qui est prise en charge par tous les
fournisseurs de compilateurs. Tous les programmes de ce livre peuvent être compilés par n'importe quel
compilateur conforme à la norme ANSI. Si vous êtes intéressé par un compilateur spécifique, vous pouvez
apprendre les fonctions spécifiques au compilateur à partir du manuel de référence du compilateur.
Après avoir terminé ce livre, après avoir fait tous les exercices en cours de route, vous devriez être compétent
et à l'aise avec la syntaxe et les fonctionnalités du langage C. De plus, vous aurez déjà une certaine expérience
de la plupart des tâches rencontrées en programmation C. Lorsque vous serez prêt à entreprendre vos propres
projets de programmation, vous pourrez utiliser le C comme outil pour écrire les programmes puissants et utiles
que vous souhaitez créer. Au fur et à mesure de votre progression, vous constaterez qu'il y a toujours plus à
apprendre, non seulement sur le C et sur la manière d'exploiter sa puissance, mais aussi sur les nouvelles
technologies et les idées de programmation en général. Avec un travail acharné et beaucoup de pratique, vous
pouvez rapidement développer les compétences et les technologies que vous apprenez.
Matériel
Tout type d'ordinateur qui a ou peut accéder à un compilateur C convient. Le compilateur C doit être conforme
à la norme ANSI C. Très probablement, vous avez un PC sur votre bureau. Un PC 286 avec un disque dur de
50 Mo et 1 Mo de mémoire (RAM) est probablement le minimum requis pour exécuter un compilateur C basé
sur DOS. Pour un compilateur C basé sur Windows, votre ordinateur doit avoir un disque dur plus gros et plus
de mémoire. Vérifiez votre fournisseur de compilateur pour plus de détails sur les exigences matérielles.
Logiciel
Si vous utilisez un poste de travail basé sur UNIX, vous avez peutêtre déjà un compilateur C chargé sur
votre machine, ou du moins vous pouvez accéder à un compilateur C sur une machine serveur. Consultez
votre administrateur système pour savoir comment accéder à un ANSI C
Machine Translated by Google
compilateur conforme. Sur une machine basée sur UNIX, vous devez savoir comment utiliser un éditeur de texte
tel que vi ou emacs pour écrire des programmes en C.
1
Si vous avez un PC exécutant un système d'exploitation Microsoft Windows (tel que Windows 95), vous devez
installer un compilateur C et un éditeur de texte sur votre PC. Cependant, la plupart des compilateurs C sont
livrés avec un éditeur intégré. Vous pouvez également utiliser n'importe quel éditeur de texte déjà installé sur
votre machine.
Turbo C de Borland International et Quick C de Microsoft étaient autrefois très populaires sur le marché des
compilateurs C. De nos jours, un compilateur C conforme à ANSI fait généralement partie de tout package de
développement C++ disponible dans le commerce, tel que Microsoft Visual C++. De plus, les packages de
développement sont livrés avec un environnement de développement intégré (IDE), que vous pouvez utiliser
pour éditer, compiler, exécuter et déboguer vos programmes C à partir de la même fenêtre.
Vous pouvez choisir n'importe quel compilateur C de votre choix pour compiler l'exemple de code donné dans le
livre, tant que le compilateur est conforme à la norme ANSI C. Vous ne devriez pas rencontrer de problèmes pour
installer un compilateur C sur votre ordinateur si vous lisez les manuels fournis avec le compilateur et suivez
correctement les instructions d'installation. La plupart des compilateurs C et/ou C++ fournissent un didacticiel
rapide qui vous montre comment installer le compilateur et configurer un environnement de développement
fonctionnel sur votre ordinateur.
De nos jours, le système d'exploitation Linux devient de plus en plus populaire parmi les utilisateurs de PC. Dans
la plupart des cas, le package Linux que vous obtenez contient un compilateur C. Le compilateur C peut être
installé sur votre PC lorsque vous installez le système d'exploitation Linux, ou peut être ajouté ultérieurement
après avoir terminé l'installation de Linux.
Dans ce livre, tous les programmes C sont développés avec Microsoft Visual C++ version 5.0. Les raisons pour
lesquelles j'ai choisi Visual C++ sont simples : tous les programmes C de ce livre sont écrits en ANSI C et
peuvent être compilés dans des applications en mode console (c'estàdire des programmes textuels exécutés
dans une fenêtre DOS) ; le package Visual C++ 5.0 inclut un bon compilateur C conforme à la norme ANSI C.
J'ai configuré mon environnement de développement de manière à ce que tous les programmes C de ce livre
puissent être compilés et transformés en applications console. De plus, je teste et exécute les applications créées
à partir des programmes C à une invite DOS fournie par Windows 95.
Dans les deux sections suivantes, je vais vous montrer brièvement comment utiliser les compilateurs C de
Microsoft et de Boralnd.
Machine Translated by Google
18 Heure 1
Maintenant, je suppose que vous avez installé une copie de Visual C++ 5.0 sur votre ordinateur. Pour
démarrer le compilateur, vous pouvez cliquer sur le bouton Démarrer de votre Windows 95 (ou 98 ou
NT), et choisir : Programmes, Microsoft Visual C++ 5.0, Microsoft Visual C++ 5.0. Ou, vous pouvez
simplement exécuter le fichier d'application MSDEV.EXE directement à partir du répertoire (dossier) où
vous avez installé le package Visual C++. La figure 1.3 montre un exemple de l'environnement de
développement intégré (IDE) de Visual C++ 5.0.
FIGURE 1.3
Un exemple de l'IDE de
Visual C++ version 5.0.
Ensuite, vous pouvez ouvrir un nouveau fichier dans l'IDE en cliquant sur le bouton Nouveau fichier à
l'extrême gauche de la barre d'outils et saisir le texte suivant dans l'espace du nouveau fichier :
#include <stdio.h>
principale()
{
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;
}
Machine Translated by Google
La figure 1.4 montre l'EDI avec le texte que vous venez de saisir. Ne vous souciez pas de la signification du texte.
Dans le chapitre suivant, "Votre premier programme C", vous l'expliquera.
1
FIGURE 1.4
Écriture de code dans
l'IDE Visual C++ 5.0.
Ensuite, vous devez enregistrer le texte dans un fichier. Appelons le fichier MyFirstProgram.c. C'est aussi une bonne
idée de créer un nouveau répertoire sur votre disque dur pour stocker vos projets de programmation et d'y enregistrer
le nouveau fichier. Tout d'abord, cliquez sur le bouton Enregistrer dans la barre d'outils. Dans la boîte de dialogue
Enregistrer sous, cliquez sur le bouton Nouveau dossier et saisissez un nom pour votre dossier de programmation.
Doublecliquez ensuite sur ce dossier pour l'ouvrir, saisissez MyFirstProgram.c dans la zone Nom de fichier, puis
cliquez sur Enregistrer. Notez que l'extension .c est utilisée pour indiquer que le fichier que vous venez d'enregistrer
est un fichier de programme C.
Maintenant, vous devez cliquer sur le menu Construire et choisir l'option Compiler MyFirstProgram.c. Ce
faisant, vous demandez au compilateur de compiler le texte que vous venez de saisir et d'enregistrer (voir Figure 1.5).
À ce stade, Visual C++ peut vous inviter à créer un nouvel espace de travail ; cliquez simplement sur Oui et cela se
fera automatiquement. Il ne devrait pas y avoir d'erreurs ou d'avertissements dans la fenêtre de sortie après l'exécution
du compilateur.
Ensuite, cliquez à nouveau sur le menu Construire, et cette fois, choisissez l'option Construire MyFirstProgram.exe
qui finira par produire un fichier exécutable appelé MyFirstProgram.exe.
La figure 1.6 montre qu'il n'y a pas d'erreurs ou d'avertissements après la génération de MyFirstProgram.exe .
Machine Translated by Google
20 Heure 1
FIGURE 1.5
Compilation d'un
programme C à l'aide de l'IDE.
FIGURE 1.6
Vous êtes maintenant prêt à exécuter le fichier exécutable, MyFirstProgram.exe, que vous venez de
compiler. Vous pouvez l'exécuter à partir du chemin du menu : Build, Execute MyFirstProgram.exe. Étant
donné que le fichier exécutable est une application en mode console, une fenêtre d'invite DOS s'affiche
lorsque le fichier exécutable est en cours d'exécution (voir Figure 1.7).
Machine Translated by Google
FIGURE 1.7
Vous pouvez voir que la première ligne de la fenêtre d'invite DOS illustrée à la figure 1.7 est la ligne
exacte que vous venez de taper : « Howdy neighbor ! C'est mon premier programme en C. C'est en
effet votre première sortie de programme C ! (Notez que la deuxième ligne affichée dans l'invite DOS
n'est qu'un rappel intégré de la fenêtre d'invite DOS.)
D'accord. Je viens de montrer comment utiliser le compilateur Visual C++ pour écrire et compiler un
programme C, et comment rendre le programme exécutable. Pour plus de détails, vous devez lire des
livres tels que Teach Yourself Visual C++ 5 in 21 Days qui se concentrent sur l'apprentissage de l'utilisation
du compilateur Visual C++.
Je suppose que vous avez installé une copie de Borland C++ 5.02 sur votre ordinateur. Pour démarrer le
compilateur, vous pouvez cliquer sur le bouton Démarrer de la barre des tâches de Windows 95 (ou
Windows 98 ou NT) et choisir Programmes, Borland C++ 5.02, Borland C++. Ou, vous pouvez simplement
exécuter le fichier d'application bcw.exe directement à partir du répertoire (dossier) où vous avez installé
le package Borland C++. La figure 1.8 montre un exemple de l'environnement de développement intégré
(IDE) de Borland C++ 5.02.
Ensuite, vous pouvez ouvrir un nouveau fichier dans l'IDE et saisir le texte suivant dans l'espace du fichier
nouvellement ouvert :
#include <stdio.h>
principale()
{
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" ); renvoie 0 ;
}
Machine Translated by Google
22 Heure 1
FIGURE 1.8
SE REND.
La figure 1.9 montre l'IDE avec le texte que vous venez de taper. Ne vous souciez pas du sens
du texte. La prochaine heure vous l'expliquera.
FIGURE 1.9
Enregistrement du texte du
programme C avec l'IDE de Borland.
Machine Translated by Google
Vous devez maintenant enregistrer le texte dans un fichier. Appelons le fichier MyFirstProgram.c. Notez que
l'extension .c est utilisée pour indiquer que le fichier que vous venez d'enregistrer est un fichier de programme C.
1
Maintenant, vous devez cliquer sur le menu Projet et choisir l'option Compiler. Ce faisant, vous demandez au
compilateur de commencer à compiler le texte que vous venez de taper et d'enregistrer. La figure 1.10 montre
qu'il n'y a pas d'erreurs ou d'avertissements après la compilation de MyFirstProgram.c et la création de
MyFirstProgram.exe .
FIGURE 1.10
Compilation d'un
programme C à l'aide de
l'IDE de Borland.
Vous êtes maintenant prêt à exécuter le fichier exécutable, MyFirstProgram.exe, que vous venez de compiler.
Vous pouvez l'exécuter en cliquant sur le bouton Exécuter de la barre d'outils. Ou, vous pouvez exécuter
MyFirstProgram.exe directement à partir du répertoire dans lequel vous l'avez créé. Parce que le fichier exécutable
est en fait une application DOS, une fenêtre d'invite DOS apparaîtra lorsque le fichier exécutable est en cours
d'exécution (voir Figure 1.11).
FIGURE 1.11
24 Heure 1
La figure 1.11 affiche la sortie exactement telle que vous venez de la saisir : « Howdy neighbor ! C'est mon
premier programme en C. C'est en effet votre première sortie de programme C !
Si vous souhaitez en savoir plus sur l'utilisation de Borland C++, lisez un livre tel que Teach Yourself Borland
C++ 5 in 21 Days.
Voici une brève note sur le code binaire et les fichiers exécutables. Vous apprendrez
plus de détails plus tard dans ce livre. Fondamentalement, avant de pouvoir exécuter un
programme C sur votre ordinateur, vous devez utiliser un compilateur C pour traduire le
programme C en code compréhensible par la machine (c'estàdire en code binaire). Une
fois la traduction terminée, le code binaire peut être enregistré dans un fichier d'application.
Le code binaire ou fichier d'application est appelé code exécutable, ou fichier exécutable,
car il peut être exécuté directement sur votre ordinateur.
Résumé
Dans cette première leçon, vous avez appris les éléments de base suivants sur le langage C :
• C est un petit langage que vous pouvez facilement apprendre en relativement peu de
temps. • Les programmes écrits en C peuvent être réutilisés. • Les programmes écrits en C
doivent être compilés et traduits en code lisible par machine avant que l'ordinateur puisse les exécuter. •
De nombreux autres langages de programmation, tels que Perl, C++ et Java, ont adopté
concepts de base et fonctionnalités utiles du langage C. Une fois que vous avez appris le C, apprendre
ces autres langages est beaucoup plus facile. • La norme ANSI pour C est la norme prise en charge par
• Vous pouvez utiliser n'importe quel compilateur compatible ANSI C pour compiler tous les programmes C dans
ce livre.
Questions et réponses
R La lisibilité, la maintenabilité et la portabilité sont les principaux avantages des langages de programmation
de haut niveau.
A C est un langage de programmation à usage général. C'est un langage de haut niveau qui présente des
avantages tels que la lisibilité, la maintenabilité et la portabilité. De plus, C vous permet de descendre au
niveau matériel pour augmenter la vitesse de performance si nécessaire. Le compilateur AC est nécessaire
pour traduire les programmes écrits en C en code compréhensible par la machine. La portabilité de C est
réalisée en recompilant les programmes C avec différents compilateurs C destinés à différents types
d'ordinateurs.
R Oui. C est un petit langage de programmation. Il n'y a pas beaucoup de motsclés C ou com
mandes à retenir. De plus, il est très facile de lire et d'écrire des programmes C car C est un langage de
programmation de haut niveau proche des langages humains, en particulier l'anglais. Vous pouvez apprendre
le C en relativement peu de temps.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz fournies dans l'atelier avant de passer à la leçon suivante. Les réponses et les conseils aux
questions sont donnés dans l'annexe D, « Réponses aux questions et exercices du quiz ».
Questionnaire
1. Quels sont les langages de niveau le plus bas et de niveau le plus élevé mentionnés dans ce livre ?
2. Un ordinateur peutil comprendre directement un programme écrit en C ? De quoi avezvous besoin pour
traduire un programme écrit en C en code compréhensible par la machine (c'estàdire en code binaire) ?
HEURE 2
Écrire votre premier C
Programme
Coupez votre propre bois et il vous réchauffera deux fois.
Proverbe chinois
Au cours de la première heure, "Faire le premier pas", vous avez appris que le C est un
langage de programmation de haut niveau et que vous avez besoin d'un compilateur C pour
traduire vos programmes C en code binaire que votre ordinateur peut comprendre et exécuter.
Dans cette leçon, vous allez écrire votre premier programme C et apprendre les bases d'un
programme C, telles que
• La directive #include
• Fichiers d'entête
• Commentaires
• La fonction main()
• La déclaration de retour
• La fonction exit()
Machine Translated by Google
28 Heure 2
Débogage
Un programme en C simple
Jetons un coup d'œil à votre premier programme C, illustré dans le Listing 2.1. Plus tard dans cette leçon,
vous allez écrire votre propre programme C pour la première fois.
8:}
Il s'agit d'un programme C très simple, qui est enregistré dans un fichier appelé 02L01.c. Notez que le nom
d'un fichier de programme C doit avoir une extension .c. Si vous avez installé un compilateur C et configuré
l'environnement de développement approprié, vous devriez pouvoir compiler ce programme C et en faire un
fichier exécutable. J'expliquerai comment créer un fichier exécutable plus loin dans ce chapitre.
Au cours de l'heure précédente, vous avez appris à entrer un programme dans votre éditeur de texte et à
l'enregistrer en tant que fichier de programme C. Ici, vous remarquerez peutêtre que contrairement à
l'exemple du dernier chapitre, chaque ligne est numérotée. Ceci n'est fait ici qu'à titre de référence lorsque je
discute de ce que fait chaque ligne d'un programme. Contrairement à d'autres langages tels que BASIC, le
langage C n'a pas du tout de numéros de ligne. En fait, si vous entrez les numéros de ligne dans la liste, votre
programme ne fonctionnera pas ! Ainsi, lorsque vous entrez dans ces programmes, n'oubliez pas de ne pas
entrer les numéros de ligne indiqués dans le livre.
Deux choses que vous remarquerez peutêtre en jetant un coup d'œil au Listing 2.1 sont les
pointsvirgules et l'indentation sur les lignes 6 et 7. Contrairement à d'autres langages, comme le
BASIC, la fin d'une ligne n'a pas de signification particulière en C. C'est parfaitement légal (et dans
de nombreux cas , conseillé) pour diviser une déclaration en plusieurs lignes pour plus de clarté.
En règle générale, une instruction C individuelle se termine par un pointvirgule, mais nous en
dirons plus à ce sujet plus loin dans le livre. L'indentation sert à identifier les différents niveaux
Machine Translated by Google
els d'un programme dans une sorte de format de plan. La fonction main() est, eh bien, le
niveau principal du programme, donc elle va à l'extrême gauche. Les lignes 6 et 7 font
partie de main() donc elles sont en retrait d'un niveau vers la droite. Habituellement, vous
utilisez votre touche Tab pour indenter un niveau avant de commencer à taper. Il convient
de noter que l'indentation, comme les numéros de ligne, n'est pas appliquée ni même
remarquée ! — par le compilateur. Le programmeur est libre d'utiliser des sauts de ligne et
des indentations, communément appelés espaces, pour rendre le programme lisible. C'est
généralement une question de style, mais c'est une bonne idée de suivre les conventions 2
généralement acceptées afin que les autres programmeurs puissent comprendre vos
programmes et viceversa. Jetez un coup d'œil à l'utilisation des espaces blancs dans les
programmes de ce livre et n'hésitez pas à développer votre propre style au fur et à mesure.
J'ai configuré mon environnement de développement de manière à ce que tous les programmes C de ce livre
puissent être compilés et transformés en applications console. Par exemple, 02L01.exe est le nom de l'application
console créée à partir de 02L01.c. Notez que .exe est inclus comme extension du nom d'un programme d'application
DOS ou Windows (c'estàdire un fichier exécutable).
De plus, sur ma machine, j'enregistre tous les fichiers exécutables créés à partir des programmes C de ce livre
dans un répertoire dédié appelé C:\app. Par conséquent, si je tape 02L01 à partir d'une invite DOS et que j'appuie
sur la touche Entrée, je peux exécuter le fichier exécutable 02L01.exe et afficher le message Salut, voisin ! C'est
mon premier programme en C. sur l'écran. La sortie suivante est une copie de l'écran :
commentaires
Examinons maintenant de près le programme C du Listing 2.1.
Vous remarquez que cette ligne commence par une combinaison de barre oblique et d'astérisque, /*, et se termine
par */. En C, /* est appelé la marque de commentaire d'ouverture et */ est la marque de commentaire de fermeture.
Le compilateur C ignore tout ce qui se trouve entre la marque de commentaire d'ouverture et la marque de
commentaire de fermeture. Cela signifie que le commentaire dans la première ligne du Listing 2.1, 02L01.C : Ceci
est mon premier programme C, est complètement ignoré par le compilateur.
Le seul but d'inclure des commentaires dans votre programme C est de vous aider à documenter ce que font
le programme ou certaines sections spécifiques des programmes. N'oubliez pas que les commentaires sont écrits
pour vousmême et pour les autres programmeurs. Par exemple, lorsque vous lisez quelqu'un d'autre
Machine Translated by Google
30 Heure 2
code, les commentaires dans le code vous aident à comprendre ce que fait le code, ou du moins ce que le code
a l'intention de faire. Au fur et à mesure que vos programmes deviennent plus volumineux et plus compliqués, vous
pouvez utiliser des commentaires pour vous écrire des notes sur ce que vous essayez de faire et pourquoi.
Vous n'avez pas à vous soucier de la taille ou de la vitesse de performance de votre programme C si
vous y ajoutez de nombreux commentaires. L'ajout de commentaires dans un programme C
n'augmente pas la taille du code binaire du programme (c'estàdire le fichier exécutable), bien que la
taille du programme luimême (c'estàdire le code source) puisse augmenter. La vitesse de
performance du fichier exécutable créé à partir de votre programme C n'est en aucun cas affectée par
les commentaires à l'intérieur de votre programme C.
Le langage C vous permet d'écrire un commentaire qui traverse plus d'une ligne. Par exemple,
vous pouvez écrire un commentaire en C comme ceci :
/*
Ce commentaire n'augmente pas la taille du fichier
exécutable (code binaire), ni n'affecte la vitesse de
performance.
*/
De nos jours, il existe une autre façon de mettre des commentaires dans un programme C. C+
+ a commencé à utiliser deux barres obliques (//) pour marquer le début d'une ligne de
commentaire ; de nombreux compilateurs C utilisent désormais également cette convention. Le
commentaire se termine à la fin de la ligne. Par exemple, si j'écris un programme C en Borland C+
+ ou Visual C++, les deux commentaires suivants sont identiques :
/*
Ce commentaire n'augmente pas la taille de
le fichier exécutable (code binaire), ni n'affecte la
vitesse de performance.
Notez que ce nouveau style d'utilisation de // comme marque de début d'un commentaire n'a
pas été approuvé par l'ANSI. Assurezvous que votre compilateur C prend en charge // avant
de l'utiliser.
Machine Translated by Google
Une chose qui doit être soulignée est que la norme ANSI ne prend pas en charge les commentaires
imbriqués, c'estàdire les commentaires dans les commentaires. Par exemple, ce qui suit n'est pas
autorisé par la norme ANSI :
2
Vous pouvez utiliser la marque de commentaire d'ouverture, /*, et la marque de commentaire de fermeture,
*/, pour vous aider à tester et à corriger les erreurs trouvées dans votre programme C. Ceci est
communément appelé commenter un bloc de code. Vous pouvez commenter une ou plusieurs instructions
C dans votre programme C avec /* et */ lorsque vous devez vous concentrer sur d'autres instructions et
surveiller de près leurs comportements. Le compilateur C ignorera les instructions que vous commentez.
Plus tard, vous pouvez toujours restaurer les instructions précédemment commentées simplement en
supprimant les marques de commentaire d'ouverture et de fermeture. De cette façon, vous n'avez pas
besoin d'effacer ou de réécrire les instructions pendant les tests et le débogage.
Cependant, comme vous ne pouvez pas imbriquer les commentaires faits avec /* et */, si vous
essayez de commenter du code qui contient déjà ces commentaires, votre programme ne se compilera
pas. L'une des raisons pour lesquelles les commentaires de type // sont si utiles est que vous pouvez les
imbriquer, et donc les commenter légalement avec /* et */.
Si votre éditeur de texte prend en charge la coloration syntaxique des couleurs, vous pouvez l'utiliser pour
savoir en un coup d'œil si des sections de code sont réellement commentées comme vous le souhaitiez.
La directive #include
Passons maintenant à la ligne 2 du programme C du Listing 2.1 :
#include <stdio.h>
Vous voyez que cette ligne commence par un signe dièse, #, suivi de include. En C, #include forme
une directive de préprocesseur qui indique au préprocesseur C de rechercher un fichier et de placer
le contenu de ce fichier à l'emplacement indiqué par la directive #include .
Le préprocesseur est un programme qui effectue certaines préparations pour le compilateur C avant
que votre code ne soit compilé. Plus de détails sur le préprocesseur C sont abordés dans l'Heure 23, «
Compilation de programmes : le préprocesseur C ».
Toujours dans cette ligne, vous voyez que <stdio.h> suit #include. Vous pouvez deviner que le fichier
demandé par la directive #include s'appelle stdio.h. Vous avez tout à fait raison ! Ici, la directive #include
demande au préprocesseur C de rechercher et de placer stdio.h à l'emplacement de la directive dans le
programme C.
Machine Translated by Google
32 Heure 2
Le nom du fichier stdio.h signifie fichier d'entête d'entréesortie standard . Le fichier stdio.h contient de nombreux
prototypes et macros pour effectuer des entrées ou des sorties (E/S) pour les programmes C. Vous verrez plus d'E/S de
programme dans l'heure 5, « Gestion des entrées et sorties standard ».
Certains systèmes d'exploitation font la distinction entre les majuscules et les minuscules,
tandis que d'autres ne le font pas. Par exemple, stdio.h et STDIO.H sont des noms de fichiers
identiques sur un PC, alors qu'ils sont différents sous UNIX.
Fichiers d'entête
Les fichiers inclus par la directive #include , comme stdio.h, sont appelés fichiers d'entête car les directives #include
sont presque toujours placées au début ou à la tête des programmes C. En fait, le nom d'extension de .h signifie "en
tête" et ceuxci sont parfois appelés dans la conversation des fichiers pointh.
Outre stdio.h, il existe d'autres fichiers d'entête, tels que stdlib.h, string.h, math.h, etc. L'annexe A, "Fichiers d'entête
standard ANSI", donne une liste de tous les fichiers d'entête standard ANSI. Les fichiers d'entête spécifiques que
vous devez inclure dépendent des fonctions de bibliothèque spécifiques que vous avez l'intention d'appeler. La
documentation des fonctions de la bibliothèque vous indiquera quel fichier d'entête est requis.
Par exemple, le répertoire courant contenant le fichier 02L01.C s'appelle C:\code sur mon ordinateur. Par conséquent,
les crochets angulaires autour de <stdio.h> indiquent au préprocesseur C de rechercher stdio.h dans un répertoire autre
que C:\code.
Si vous voulez laisser le préprocesseur C chercher d'abord dans le répertoire courant un fichier d'entête avant qu'il ne
commence à chercher ailleurs, vous pouvez utiliser des guillemets doubles pour entourer le nom du fichier d'entête. Par
exemple, lorsque le préprocesseur C voit "stdio.h", il regarde dans le répertoire courant, qui est C:\code sur ma machine,
avant de chercher ailleurs le fichier d'entête stdio.h .
Normalement, les fichiers d'entête sont enregistrés dans un sousrépertoire appelé include. Par exemple, j'installe
un compilateur Microsoft C dans le répertoire MSVC sur mon disque dur, qui est étiqueté comme le lecteur C. Ensuite,
le chemin d'accès aux fichiers d'entête devient C:\MSVC\include.
Machine Translated by Google
Le chemin où sont conservés les fichiers d'entête est généralement déterminé par votre compilateur
lorsque vous l'installez. Ceci est communément appelé le répertoire d'inclusion ou le chemin d'inclusion de
votre environnement. Normalement, vous n'avez jamais à vous soucier du répertoire d'inclusion tant que
vous n'avez pas créé vos propres fichiers d'entête. Pour l'instant, il vous suffit de spécifier le nom du fichier
d'entête que vous souhaitez inclure.
La fonction principale() 2
À la ligne 4 du Listing 2.1, vous voyez cette fonction :
principale ()
C'est une fonction très spéciale en C. Chaque programme C doit avoir une fonction main() , et chaque
programme C ne peut avoir qu'une seule fonction main() . Des discussions plus génériques sur les fonctions
sont données dans l'heure 3, "Apprentissage de la structure d'un programme C".
Vous pouvez mettre la fonction main() où vous voulez dans votre programme C. Cependant, l'exécution
de votre programme commence toujours par la fonction main() . Si vous créez d'autres fonctions dans
votre programme, main() s'exécutera toujours en premier, même si elle se trouve en bas de votre fichier
programme.
Dans le Listing 2.1, le corps de la fonction main() commence à la ligne 4 et se termine à la ligne 8. Comme il
s'agit d'un programme très simple, la fonction main() est la seule fonction définie dans le programme.
Dans le corps de la fonction main() , une fonction de la bibliothèque C, printf(), est appelée afin d'imprimer un
message d'accueil (voir ligne 6). Plus de détails sur printf() sont couverts dans l'heure 5.
Une autre chose importante à propos de main() est que l'exécution de chaque programme C se termine
par main(). Un programme se termine lorsque toutes les instructions de la fonction main() ont été exécutées.
Dans un environnement UNIX, \n va de luimême à une nouvelle ligne mais laisse le curseur à la position où il
se trouvait sur la ligne précédente. Dans ce cas, il est nécessaire d'imprimer \r\n plutôt que \n uniquement. Le
caractère \r est le caractère de retour chariot . Lorsque vous exécutez les exemples de programmes de ce
livre, vous serez en mesure de dire immédiatement si le curseur revient au début de la nouvelle ligne ; si ce
n'est pas le cas, utilisez simplement \r\n partout où vous voyez \n dans les listes de programmes.
L'exercice 3 de cette leçon vous permet d'utiliser le caractère de saut de ligne pour diviser un message
d'une ligne en deux lignes.
Machine Translated by Google
34 Heure 2
La déclaration de retour
Toutes les fonctions en C peuvent renvoyer des valeurs. Par exemple, lorsque vous créez une fonction pour
additionner deux nombres, vous pouvez créer une telle fonction qui vous renvoie la valeur de l'addition.
La fonction main() renvoie ellemême une valeur entière. En C, les nombres entiers sont des nombres
décimaux sans fractions.
Par conséquent, à la ligne 7 du Listing 2.1, il y a une instruction, return 0;, qui indique que 0 est renvoyé par
la fonction main() et que le programme se termine normalement. Dans certains cas, vous devez terminer
votre programme en raison d'une condition d'erreur. Lorsque cela se produit, vous pouvez renvoyer des
valeurs autres que 0 pour indiquer au système d'exploitation (ou au programme qui a exécuté votre
programme) qu'il y a eu une erreur.
une fonction de la bibliothèque C, exit(), qui peut être utilisée pour terminer un programme. Étant donné
que la fonction exit() est définie dans un fichier d'entête, stdlib.h, vous devez inclure le fichier d'entête au
début de votre programme afin d'utiliser la fonction. La fonction exit() ellemême ne renvoie pas de valeur à
votre programme.
Notez que return et exit() peuvent également être utilisés dans d'autres fonctions. Vous verrez d'autres
exemples du motclé return dans le reste du livre.
Compilation et liaison
Vous êtes peutêtre déjà anxieux de savoir comment un fichier exécutable est créé. Voyons comment
un programme C est compilé et traduit en un fichier exécutable. Comme le montre la figure 2.1, il y a au
moins trois étapes nécessaires pour créer un fichier exécutable.
Tout d'abord, un fichier de programme écrit en C, appelé code source, est créé. Le nom du fichier de
code source se termine par l'extension .c.
Ensuite, le fichier de code source est compilé par un compilateur C, qui crée un nouveau fichier. Le
nouveau fichier est un fichier objet. Dans le système d'exploitation UNIX, le nom d'un fichier objet se termine
par l'extension .o ; Dans les systèmes d'exploitation DOS et Windows, l'extension est .obj.
Vous ne pouvez pas exécuter le fichier objet car il manque du code de fonction. Vous devez terminer l'étape
suivante : la liaison. La liaison est effectuée en appelant un programme spécial appelé éditeur de liens, qui
est normalement fourni avec le package du compilateur.
Un éditeur de liens est utilisé pour lier ensemble le fichier objet, la bibliothèque C standard ANSI et d'autres
bibliothèques générées par l'utilisateur pour produire un fichier exécutable, le code binaire. Dans cette
étape, le code binaire des fonctions de la bibliothèque qui sont appelées dans le code source est combiné
Machine Translated by Google
avec le fichier objet ; le résultat est enregistré dans un nouveau fichier, un fichier exécutable.
Comme vous l'avez appris dans le premier chapitre du livre, le nom d'un fichier exécutable se termine
généralement par l'extension .exe sous DOS et Windows. (.com est une autre extension utilisée pour un
nom de fichier exécutable DOS.) Sous UNIX, il n'est pas nécessaire d'inclure une telle extension à un
nom de fichier exécutable.
Faire un exécutable
stdio.h 2
fichier par le compilateur et stdlib.h /* 02L01.C */
l'éditeur de liens. .....
Fichiers de bibliothèque
Le compilateur C et
L'éditeur de liens
Le fichier exécutable
10011111001
0111000011
110001100
Plus tard, vous apprendrez que dans de nombreux cas, il peut y avoir plusieurs fichiers objets qui
doivent être liés ensemble afin de créer un programme exécutable.
Notez que le fichier objet et le fichier exécutable dépendent tous deux de la machine. Vous ne pouvez
pas simplement déplacer un fichier exécutable de la plateforme informatique actuelle vers une autre
qui est exploitée par un système d'exploitation différent, bien que le code source du fichier exécutable,
vraisemblablement écrit en ANSI C, puisse être indépendant de la machine (c'estàdire portable) .
Machine Translated by Google
36 Heure 2
La portabilité est un concept important en C, car c'était l'un des objectifs de conception
originaux du langage. La portabilité du code C est ce qui a alimenté sa large utilisation et
sa popularité. À l'époque où les applications et les systèmes d'exploitation étaient adaptés à
un système informatique spécifique, les logiciels devaient être écrits à partir de zéro chaque
fois qu'un nouvel ordinateur arrivait. L'avènement du langage C a séparé le logiciel du
matériel et, dans un sens très réel, a contribué à donner naissance à l'industrie du logiciel
telle que nous la connaissons aujourd'hui.
La portabilité, par essence, fait référence au processus de portage d'un programme sur un
autre ordinateur et/ou système d'exploitation. Le développement de logiciels est un
processus long et coûteux, et la réécriture d'un programme existant pour qu'il fonctionne sur
un nouvel ordinateur est souvent une tâche ardue qu'il vaut mieux éviter. En supposant que
chaque combinaison de système d'exploitation et de compilateur est adaptée à l'ordinateur
spécifique sur lequel il est destiné à s'exécuter, un programme C devrait être facilement
portable avec seulement des modifications minimes du code. La portabilité est mentionnée
tout au long de ce livre, car il est important que les programmes C ne fassent pas
d'hypothèses sur le système informatique spécifique sur lequel ils s'exécutent.
Heureusement, la norme ANSI C fournit de nombreuses caractéristiques et fonctions qui
permettent à votre programme de s'adapter essentiellement à son environnement, au lieu
d'agir sur des hypothèses faites par vous, le programmeur. Si vous prenez l'habitude de
maintenir la portabilité dès le début, alors que vous progressez avec C, l'idée deviendra
une seconde nature.
Habituellement, votre compilateur peut vous aider à vérifier la grammaire c'estàdire la syntaxe de votre programme
C et à vous assurer que vous avez correctement suivi les règles de programmation C. Par exemple, si vous oubliez de
mettre l'accolade de fin sur la fonction main() à la ligne 8 du Listing 2.1, vous obtiendrez un message d'erreur du genre :
erreur de syntaxe : fin de fichier trouvée.
En outre, l'éditeur de liens émettra un message d'erreur s'il ne trouve pas le code manquant pour une fonction
nécessaire dans les bibliothèques. Par exemple, si vous orthographiez mal printf() comme pprintf() dans le programme
du Listing 2.1, vous verrez un message d'erreur : '_pprintf' : unresolved external (ou quelque chose de similaire).
Toutes les erreurs trouvées par le compilateur et l'éditeur de liens doivent être corrigées avant qu'un fichier
exécutable (code binaire) puisse être créé.
Machine Translated by Google
compilateur C et votre éditeur de liens ne trouvent aucune erreur dans votre programme, mais le résultat obtenu en
exécutant le fichier exécutable du programme n'est pas celui que vous attendiez. Afin de trouver ces erreurs "cachées" dans
Normalement, votre compilateur C inclut déjà un logiciel de débogage. Le débogueur peut exécuter votre programme une
ligne à la fois afin que vous puissiez surveiller de près ce qui se passe avec le code dans chaque ligne, ou pour que vous 2
puissiez demander au débogueur d'arrêter l'exécution de votre programme sur n'importe quelle ligne. Pour plus de détails sur
Plus loin dans ce livre, vous apprendrez que le débogage est une étape très nécessaire et importante dans l'écriture de
programmes logiciels. (Ce sujet est traité dans l'heure 24, "Où allezvous à partir d'ici".)
Résumé
Dans cette leçon, vous avez appris les concepts et énoncés suivants concernant le langage C :
• Les fichiers d'entête, tels que stdio.h et stdlib.h, contiennent les déclarations des fonctions utilisées dans votre
• Les commentaires dans vos programmes C sont nécessaires pour vous aider à documenter vos programmes.
• En ANSI C, un commentaire commence par la marque de commentaire d'ouverture, /*, et se termine par
• Chaque programme C doit avoir une mais une seule fonction main() . Le programme exe
cution commence et se termine avec la fonction main() .
• L' instruction return peut être utilisée pour renvoyer une valeur pour indiquer au système d'exploitation si une erreur
s'est produite. La fonction exit() termine un programme ; l'argument de la fonction indique également l'état de l'erreur.
• La compilation et la liaison sont des étapes consécutives qui doivent être terminées avant qu'un fichier exécutable ne
soit produit.
• Tout le monde, y compris vous et moi, fait des erreurs de programmation. Le débogage est
Dans la prochaine leçon, vous en apprendrez plus sur les bases des programmes C.
Machine Translated by Google
38 Heure 2
Questions et réponses
A Les commentaires vous aident à documenter ce que fait un programme. Surtout quand un programme devient
très complexe, vous devez écrire des commentaires pour expliquer les différentes parties du programme.
A L'exécution d'un programme C commence et se termine par la fonction main() . Sans pour autant
la fonction main() , l'ordinateur ne sait pas par où commencer pour exécuter un programme.
A La directive #include est utilisée pour inclure les fichiers d'entête contenant les déclarations
aux fonctions utilisées dans votre programme C. En d'autres termes, la directive #include indique au
préprocesseur C d'examiner le chemin d'inclusion pour trouver le fichier d'entête spécifié.
A Après la compilation, il se peut qu'il manque encore du code de fonction dans le fichier objet d'un
programme. Un éditeur de liens doit ensuite être utilisé pour lier le fichier objet à la bibliothèque standard C ou
à d'autres bibliothèques générées par l'utilisateur et inclure le code de fonction manquant afin qu'un fichier
exécutable puisse être créé.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et exercices du
quiz ».
Questionnaire
Des exercices
1. #include <stdio.h> est il identique à #include "stdio.h" ?
2. Il est temps pour vous d'écrire un programme par vousmême. Se référant au programme de
Listing 2.1, écrivez un programme C capable d'afficher un message : C'est amusant d'écrire mon
propre programme en C.
3. Mettez à jour le programme du Listing 2.1 en ajoutant un caractère de retour à la ligne supplémentaire
dans le message imprimé par la fonction printf() . Vous devriez voir deux lignes du message à l'écran 2
après avoir exécuté le fichier exécutable mis à jour : Howdy, neighbor !
5. Quels messages d'erreur obtiendrezvous pour le programme suivant lorsque vous essayez de
le compiler ?
void main() {
}
Machine Translated by Google
Machine Translated by Google
HEURE 3
Euclide
Au cours de l'heure 2, "Écrire votre premier programme C", vous avez vu et écrit quelques
programmes C simples. Vous avez également appris la structure de base d'un programme C.
Vous savez qu'un programme écrit en C doit être compilé avant de pouvoir être exécuté. Dans
cette leçon, vous apprendrez plus d'éléments essentiels dans un programme C, tels que
• Constantes et variables
• Expressions
• Déclarations
• Blocs d'instructions
d'une fonction
• Appels de fonction
Machine Translated by Google
42 Heure 3
Constantes et variables
Comme son nom l'indique, une constante est une valeur qui ne change jamais. Une variable, en revanche,
peut être utilisée pour présenter différentes valeurs.
Vous pouvez considérer une constante comme un CDROM musical ; la musique enregistrée sur le CDROM
n'est jamais modifiée. Une variable ressemble plus à une cassette audio : vous pouvez toujours mettre à jour le
contenu de la cassette en écrasant simplement les anciennes chansons avec les nouvelles.
Vous pouvez voir de nombreux exemples dans lesquels des constantes et des variables sont dans la même instruction.
Par exemple, considérez ce qui suit :
je = 1 ;
où le symbole 1 est une constante car il a toujours la même valeur (1), et le symbole i est affecté de la constante
1. En d'autres termes, i contient la valeur de 1 après l'exécution de l'instruction. Plus tard, s'il y a une autre
déclaration,
je = 10 ;
après son exécution, i reçoit la valeur 10. Comme i peut contenir différentes valeurs, on l'appelle une variable en
langage C.
Expressions Une
expression est une combinaison de constantes, de variables et d'opérateurs utilisés pour dénoter des calculs.
(2 + 3) * 10
est une expression qui additionne d'abord 2 et 3, puis multiplie le résultat de l'addition par 10. (Le résultat final
de l'expression est 50.)
Expression Description
6 Expression d'une constante.
je
Expression d'une variable.
Opérateurs
Comme vous l'avez vu, une expression peut contenir des symboles tels que +, * et /. En langage
C, ces symboles sont appelés opérateurs arithmétiques. Le tableau 3.1 liste tous les opérateurs
arithmétiques et leurs significations.
Soustraction
* Multiplication
/ Division
% Reste (ou module)
Vous connaissez peutêtre déjà tous les opérateurs arithmétiques, à l'exception de l'opérateur reste
(%) . % est utilisé pour obtenir le reste du premier opérande divisé par le deuxième opérande. Par
exemple, l'expression
6%4
Parmi les opérateurs arithmétiques, les opérateurs de multiplication, de division et de reste ont une
priorité plus élevée que les opérateurs d'addition et de soustraction. Par exemple, l'expression
2 + 3 * 10
donne 32, et non 50, en raison de la priorité plus élevée de l'opérateur de multiplication. 3 * 10
est calculé en premier, puis 2 est ajouté au résultat de la multiplication.
Machine Translated by Google
44 Heure 3
Comme vous le savez peutêtre, vous pouvez mettre des parenthèses autour d'une addition (ou d'une
soustraction) pour forcer l'addition (ou la soustraction) à être effectuée avant une multiplication, une
division ou un calcul de module. Par exemple, l'expression
(2 + 3) * 10
D'autres opérateurs, qui sont utilisés pour la syntaxe, incluent la virgule et le pointvirgule. Le point
virgule est généralement utilisé pour indiquer la fin d'une instruction, comme vous le verrez plus tard. La
virgule est utilisée dans certains cas où une instruction est composée d'une liste d'expressions ou de
déclarations.
Vous en apprendrez plus sur les opérateurs du langage C dans les heures 6, "Manipulation des données" et 8, "Utilisation
des opérateurs conditionnels".
Identifiants
Outre les nombres (tels que la constante 7) et les opérateurs (tels que le symbole +), les expressions
peuvent également contenir des mots appelés identificateurs. Les noms de fonctions (comme exit) et
les noms de variables (comme i), ainsi que les mots clés réservés, sont tous des identifiants en C.
Voici le jeu de caractères que vous pouvez utiliser pour créer un identifiant valide. Tous les caractères
ou symboles qui ne suivent pas ces règles sont illégaux à utiliser dans un identifiant.
• Caractères A à Z et a à z. • Caractères
numériques de 0 à 9 (mais ceuxci ne peuvent pas être utilisés comme premier caractère d'un
identifiant).
Par exemple, stop_sign, Loop3 et _pause sont tous des identifiants valides.
Les caractères suivants sont illégaux ; c'estàdire qu'ils ne respectent pas l'ensemble de règles cidessus pour
les identifiants :
Certains identifiants non valides, par exemple, sont 4flags, sumresult, method*4
et what_size?.
Machine Translated by Google
N'utilisez jamais les motsclés réservés ou les noms des fonctions de la bibliothèque C
standard pour les noms de variables ou les noms de fonctions que vous créez dans vos
propres programmes C.
Vous avez déjà vu le motclé return dans l'heure précédente. L'heure 4, « Comprendre les types de données et les
mots clés », répertorie tous les mots clés réservés.
Déclarations
En langage C, une instruction est une instruction complète, se terminant par un pointvirgule. Dans de nombreux
cas, vous pouvez transformer une expression en instruction en ajoutant simplement un pointvirgule à la fin de
l'expression.
est une déclaration. Vous avez peutêtre déjà compris que l'instruction se compose d'une expression de i = 1
et d'un pointvirgule (;).
je = (2 + 3) * 10 ; je =
2 + 3 * 10 ; j = 6 % 4;
k = je + j ;
De plus, dans la première leçon de ce livre, vous avez appris des déclarations telles que
renvoie 0 ;
sortie(0);
printf ("Bonjour, voisin ! C'est mon premier programme C.\n" );
Blocs d'instructions
Un groupe d'instructions peut former un bloc d'instructions commençant par une accolade ouvrante ({) et se
terminant par une accolade fermante (}). Un bloc d'instructions est traité comme une seule instruction par le
compilateur C.
pour(. . .) { s3
= s1 + s2; mul =
s3 * c; reste =
somme % c;
}
Machine Translated by Google
46 Heure 3
est un bloc d'instructions qui commence par { et se termine par }. Ici, for est un motclé en C qui détermine le bloc
d'instructions. Le motclé for est abordé dans l'heure 7, "Travailler avec des boucles".
Un bloc d'instructions permet de regrouper une ou plusieurs instructions en une seule instruction. De nombreux mots
clés C ne peuvent contrôler qu'une seule instruction. Si vous souhaitez placer plusieurs instructions sous le contrôle
d'un motclé C, vous pouvez ajouter ces instructions dans un bloc d'instructions afin que le bloc soit considéré comme une
seule instruction par le motclé C.
Comme le montre la figure 3.1, une fonction se compose de six parties : le type de fonction, le nom de la fonction, les
arguments de la fonction, l'accolade ouvrante, le corps de la fonction et l'accolade fermante.
fonction en langage C.
{ Début de fonction
résultat entier ;
résultat = x + y ; Fonction Corps
retourner le résultat ;
Corps et fonction de fin de
} fonction
Les six parties d'une fonction sont expliquées dans les sections suivantes.
En C, int est utilisé comme mot clé pour le type de données entier. Au cours de la prochaine heure, vous en apprendrez
plus sur les types de données.
Machine Translated by Google
Outre le type int , un type de fonction peut être l'un des autres types, tels que le type caractère (motclé : char),
le type flottant (float), etc. Vous en apprendrez plus sur ces types plus tard dans ce livre.
Lorsque vous appelez une fonction C qui renvoie un type de données, la valeur qu'elle renvoie (valeur de retour)
peut alors être utilisée dans une expression. Vous pouvez l'affecter à une variable, telle que
int a = fonction();
a = fonction() + 7 ;
De plus, vous ne pouvez pas utiliser les noms des fonctions C standard telles que printf() ou exit() pour
nommer vos propres fonctions. Ils sont déjà définis et il est illégal d'utiliser le même nom de fonction pour définir
plusieurs fonctions.
Par exemple, dans le Listing 2.1 de l'Heure 2, une chaîne de caractères, « Bonjour, voisin ! C'est mon premier
programme C.\n", est passé à la fonction printf() , puis printf() imprime la chaîne à l'écran. Le but de printf() est
d'imprimer une chaîne à l'écran, mais chaque fois que vous l'appelez, vous transmettez la chaîne spécifique que
vous souhaitez qu'elle imprime cette foisci.
Les informations transmises aux fonctions sont appelées arguments. Comme vous l'avez vu, l'argument d'une
fonction est placé entre les parenthèses qui suivent immédiatement le nom de la fonction.
Le nombre d'arguments d'une fonction est déterminé par la déclaration de la fonction, qui à son tour est
déterminée par la tâche que la fonction va effectuer. Si une fonction a besoin de plus d'un argument, les
arguments passés à la fonction doivent être séparés par des virgules ; ces arguments sont considérés comme
une liste d'arguments.
Machine Translated by Google
48 Heure 3
Si aucune information ne doit être transmise à une fonction, il vous suffit de laisser vide le
champ argument entre parenthèses. Par exemple, la fonction main() du Listing 2.1 de l'Heure 2 n'a
pas d'argument, donc le champ entre parenthèses après le nom de la fonction est vide. Voir la copie
de la liste 3.1 cidessous :
8:}
Comme mentionné précédemment, les accolades sont également utilisées pour marquer le début et la fin d'un bloc
d'instructions. Vous pouvez le considérer comme une extension naturelle pour utiliser des accolades avec des fonctions
car une fonction se compose d'une ou plusieurs instructions.
Le corps de la fonction
Le corps de la fonction dans une fonction est l'endroit qui contient les déclarations de variables et
d'autres instructions C. La tâche d'une fonction est accomplie en exécutant les instructions à
l'intérieur du corps de la fonction une par une.
Il est important de se rappeler que toute déclaration de variable doit être placée au début du
corps de la fonction. Il est illégal de placer des déclarations de variables ailleurs qu'au tout début
d'un bloc d'instructions.
Si le corps de votre fonction contient des déclarations de variables, elles doivent toutes être
placées en premier, avant toute autre instruction.
Le Listing 3.2 illustre une fonction qui additionne deux entiers spécifiés par ses arguments et renvoie
le résultat de l'addition.
Machine Translated by Google
1 : /* 03L01.c : cette fonction additionne deux entiers et renvoie le résultat */ 2 : int integer_add( int x, int y )
3:{
4: résultat entier ;
résultat = x + y ;
retourner le résultat ;
5:6:7:}
Comme vous l'avez appris à l'heure 2, la ligne 1 du Listing 3.1 est un commentaire qui décrit ce que la
UNE ANALYSE
fonction peut faire.
À la ligne 2, vous voyez que le type de données int est préfixé avant le nom de la fonction. Ici, int est utilisé
comme type de fonction, ce qui signifie qu'un entier est renvoyé par la fonction.
Le nom de la fonction affiché à la ligne 2 est integer_add. La liste d'arguments contient deux arguments, int x et
3
int y, à la ligne 2, où le type de données int spécifie que les deux arguments sont tous deux des entiers.
Le corps de la fonction se trouve aux lignes 4 à 6 du Listing 3.1. La ligne 4 donne la déclaration de variable du
résultat et est spécifiée par le type de données int sous la forme d'un entier. L'instruction de la ligne 5 additionne
les deux nombres entiers représentés par x et y et affecte le résultat du calcul à la variable de résultat . L'
instruction return de la ligne 6 renvoie ensuite le résultat du calcul représenté par result.
Enfin, mais non des moindres, l'accolade fermante (}) à la ligne 7 est utilisée pour fermer la fonction.
Lorsque vous créez une fonction dans votre programme C, n'attribuez pas trop de
travail à la fonction. Si une fonction a trop à faire, elle sera très difficile à écrire et à
déboguer. Si vous avez un projet de programmation complexe, divisezle en plus petits
morceaux. Faites de votre mieux pour vous assurer que chaque fonction n'a qu'une
seule tâche à accomplir.
50 Heure 3
LISTE 3.3 Programme AC qui calcule une addition et imprime le résultat à l' écran
résultat entier ;
résultat = x + y ;
retourner le résultat ;
7:8:
9:}
10 : 11 : int main()
12 : { 13 : 14 : 15 :
16 : 17 : 18
int :somme
} ;
Le programme du Listing 3.2 est enregistré en tant que fichier source appelé 03L02.c. Une fois ce
programme compilé et lié, un fichier exécutable pour 03L02.c est créé. Sur ma machine, le fichier exe
cutable s'appelle 03L02.exe. Voici la sortie imprimée à l'écran après avoir lancé l'exécutable sur ma
machine :
La ligne 1 du Listing 3.2 est un commentaire sur le programme. Comme vous l'avez appris à
UNE ANALYSE
l'heure 2, la directive include de la ligne 2 inclut le fichier d'entête stdio.h en raison de la
fonction printf() dans le programme.
Les lignes 3 à 9 représentent la fonction integer_add() qui additionne deux entiers, comme indiqué
dans la section précédente.
La fonction main() , précédée du type de données int , commence à la ligne 11. Les lignes 12 et 18
contiennent respectivement l'accolade ouvrante et l'accolade fermante de la fonction main() . Une
variable entière, somme, est déclarée à la ligne 13.
L'instruction de la ligne 15 appelle la fonction integer_add() que vous avez examinée dans la section
précédente. Notez que deux constantes entières, 5 et 12, sont transmises à la fonction integer_add() et
que la variable sum reçoit le résultat renvoyé par la fonction integer_add() .
Machine Translated by Google
Vous avez vu pour la première fois la fonction printf() de la bibliothèque standard C à l'heure 2. Si vous
pensiez avoir trouvé quelque chose de nouveau ajouté à la fonction à la ligne 16, vous avez raison. Cette
fois, deux arguments sont passés à la fonction printf() . Il s'agit de la chaîne "L'addition de 5 et 12 est %d.\n"
et de la variable somme.
Notez qu'un nouveau symbole, %d, est ajouté au premier argument. Le deuxième argument est la somme de la
variable entière . Étant donné que la valeur de sum va être imprimée à l'écran, vous pourriez penser que %d a
quelque chose à voir avec la variable entière sum. Vous avez encore raison. %d indique à l'ordinateur le format
dans lequel la somme doit être affichée à l'écran.
Plus de détails sur %d sont couverts dans l'heure 4. La relation entre %d et la somme est discutée dans
l'heure 5, "Gestion des entrées et sorties standard".
Plus important encore, vous devez vous concentrer sur le programme du Listing 3.2 et faire attention à la
façon d'appeler soit une fonction générée par l'utilisateur, soit une fonction standard de la bibliothèque C à 3
partir de la fonction main() .
Résumé
Dans cette leçon, vous avez appris les concepts et opérateurs importants suivants :
• Une constante dans C est une valeur qui ne change jamais. Une variable, en revanche, peut présenter
différentes valeurs.
• Une combinaison de constantes, de variables et d'opérateurs est appelée une expression dans la
Langage C. Une expression est utilisée pour désigner différents calculs.
C traite un bloc d'instructions comme une instruction unique, bien que le bloc d'instructions puisse
contenir plusieurs instructions.
• Un argument contient des informations que vous souhaitez transmettre à une fonction. Une liste
d'arguments contient deux ou plusieurs arguments séparés par des virgules.
• L'accolade ouvrante ({) et l'accolade fermante (}) sont utilisées pour marquer le début et la fin d'un
Fonction C.
Dans la leçon suivante, vous en apprendrez plus sur les types de données en langage C.
Machine Translated by Google
52 Heure 3
Questions et réponses
A La principale différence est que la valeur d'une constante ne peut pas être modifiée, alors que la valeur d'une
variable le peut. Vous pouvez affecter différentes valeurs à une variable chaque fois que cela est nécessaire
dans votre programme C.
R De nombreux motsclés C ne peuvent contrôler qu'une seule instruction. Un bloc d'instructions fournit une
manière de regrouper plusieurs instructions et de placer le bloc d'instructions sous le contrôle d'un motclé
C. Ensuite, le bloc d'instructions est traité comme une seule instruction.
A Parmi les cinq opérateurs arithmétiques, les opérateurs de multiplication, de division et de reste ont une
priorité plus élevée que les opérateurs d'addition et de soustraction.
R Une fonction comporte normalement six parties : le type de fonction, le nom de la fonction, les arguments,
l'accolade ouvrante, le corps de la fonction et l'accolade fermante.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».
Questionnaire
2méthodes
m2_algorithme
*start_function
Taille de la chambre
.End_Exe
_turbo_add
Des exercices
int somme ;
somme = x + y + z ;
somme de retour ;
}
int somme ; 3
somme = x + y + z
retour somme ;
}
4. Écrivez une fonction C qui peut effectuer une multiplication de deux entiers et renvoyer la
résultat calculé.
5. Écrivez un programme C qui appelle la fonction C que vous venez d'écrire dans l'exercice 4 pour
calculer la multiplication de 3 fois 5, puis imprimez la valeur de retour de la fonction à l'écran.
Machine Translated by Google
Machine Translated by Google
HEURE 4
Comprendre les données
Types et motsclés
Qu'estce qu'il y a dans un nom? Ce qu'on appelle une rose
—W. Shakespeare
Vous avez appris à créer un nom valide pour une fonction C à l'heure 3, "Apprentissage
de la structure d'un programme C". Maintenant, vous allez en savoir plus sur le nommage d'une
variable et les motsclés C réservés par le compilateur C pendant cette heure.
Au cours de cette heure également, vous découvrirez en détail les quatre types de données du
langage C :
56 Heure 4
Motsclés C
Le langage C réserve certains mots qui ont des significations particulières pour le langage. Ces mots
réservés sont parfois appelés motsclés C. Vous ne devez pas utiliser les mots clés C pour vos
propres noms de variables, constantes ou fonctions dans vos programmes. Le tableau 4.1 répertorie
les 32 mots clés C réservés.
Déclaration
Pause
Déclaration
Cas
Déclaration
Continuez
défaut Étiquette
Déclaration
faire
Déclaration
autre
Déclaration
pour
Déclaration
aller à
si Déclaration
Déclaration
revenir
taille de Opérateur
Déclaration
changer
Machine Translated by Google
Motclé La description
typedef
Déclaration
Ne vous inquiétez pas si vous ne vous souvenez pas de tous les motsclés C la première fois. Dans le reste
du livre, vous vous familiariserez avec eux et commencerez à utiliser de nombreux mots clés à travers des
exemples et des exercices.
Notez que tous les motsclés C sont écrits en lettres minuscules. Comme je l'ai mentionné, C est un langage
sensible à la casse. Par conséquent, int, comme indiqué dans la liste ici, est considéré comme un mot clé C,
mais INT ne l'est pas.
Cependant, un ordinateur ne peut stocker que du code numérique. Par conséquent, les caractères tels que
A, a, B, b, etc. ont tous un code numérique unique utilisé par les ordinateurs pour représenter les caractères.
Habituellement, un caractère prend 8 bits (c'estàdire 1 octet) pour stocker son code numérique.
Pour de nombreux ordinateurs, les codes ASCII sont les codes standard de facto pour représenter un
jeu de caractères. (ASCII, juste pour votre information, signifie American Standard Code for Information
Interchange.) Le jeu de caractères ASCII d'origine n'a que 128 caractères car il utilise les 7 bits inférieurs qui
peuvent représenter 27 (c'estàdire 128) caractères.
Sur les PC compatibles IBM, cependant, le jeu de caractères est étendu pour contenir un total de 256 (c'està
dire 28 ) caractères.
Une chose que je voudrais mentionner ici est que la norme ANSI C spécifie uniquement
la valeur du caractère nul, qui est toujours zéro (c'estàdire un octet avec tous les bits
définis sur 0.) Les valeurs numériques des autres caractères sont déterminées par les
types d'ordinateurs, de systèmes d'exploitation et de compilateurs C. Nous vous
encourageons à explorer le jeu de caractères de l'ordinateur que vous utilisez. Cela peut
être fait avec le programme du Listing 4.1.
Machine Translated by Google
58 Heure 4
Dans le monde informatique, un bit est la plus petite unité de stockage de données et il ne peut
avoir qu'une des deux valeurs suivantes : 0 ou 1. Ces valeurs représentent deux états des
commutateurs électroniques utilisés dans la mémoire et le processeur de l'ordinateur. Un octet
est une unité plus grande qu'un bit. En fait, huit bits sont égaux à un octet.
Variables de caractère
Une variable qui peut représenter différents caractères est appelée une variable de caractère.
Vous pouvez définir le type de données d'une variable sur char en utilisant le format de déclaration suivant :
où variablename est le nom que vous fournissez dans lequel stocker les valeurs de ce type.
Si vous avez plusieurs variables à déclarer, vous pouvez soit utiliser le format suivant :
ou celuici :
De même, les instructions suivantes déclarent x, y et z en tant que variables de type caractère, puis
leur attribuent des valeurs :
caractère x, y,
z ; x = 'A' ; y =
'f'; z = '7';
Notez que la dernière affectation, z = '7', définit z pour qu'il soit égal à la valeur numérique représentant
le caractère '7' dans le jeu de caractères et non au nombre réel 7.
Vous en apprendrez plus sur la variable caractère et sur son utilisation dans vos programmes C plus loin
dans ce livre.
Constantes de caractères
Un caractère entouré de guillemets simples (') est appelé une constante de caractère. Par exemple,
'A', 'a', 'B' et 'b' sont toutes des constantes de caractères qui ont leurs valeurs numériques uniques
Machine Translated by Google
dans un jeu de caractères donné. Par exemple, vous pouvez voir les valeurs numériques uniques du jeu de caractères
ASCII.
Il est important de se rappeler que les constantes de caractères sont toujours entourées de guillemets simples (')
alors qu'une chaîne de plusieurs caractères utilise les guillemets doubles (").
Si cela semble déroutant, rappelezvous simplement que les guillemets simples vont avec des caractères simples. Vous
avez vu un exemple de guillemets doubles et de chaînes de caractères avec les appels de fonction printf() au cours de
l'heure précédente.
À partir du jeu de caractères ASCII, vous constaterez que les valeurs numériques (décimales) uniques de 'A', 'a', 'B' et 'b'
sont respectivement 65, 97, 66 et 98 . Par conséquent, étant donné x comme variable de caractère et étant donné le jeu
de caractères ASCII, par exemple, les deux instructions d'affectation suivantes sont équivalentes :
x = 'A' ;
x = 65 ;
x = 'un' ;
x = 97 ;
Plus tard dans cette heure, vous verrez un programme, présenté dans le Listing 4.2, qui reconvertit les valeurs
4
numériques en caractères correspondants.
Ne confondez pas x = 'a'; avec x = a;. La première instruction affecte la valeur numérique
du caractère a à la variable x, c'estàdire que x contiendra la valeur 97 (la valeur ASCII de la lettre
'a') après l'affectation. Énoncé x = a ; affecte cependant la valeur contenue dans la variable a à la
variable x.
Vous en apprendrez plus sur la différence plus loin dans ce livre.
Par exemple, lorsque l'ordinateur voit \ dans le caractère de retour à la ligne \n, il sait que le caractère suivant, n,
provoque une séquence de retour chariot et de saut de ligne.
Machine Translated by Google
60 Heure 4
Outre le caractère de nouvelle ligne, certains des autres caractères spéciaux du langage C sont les
suivants :
Personnage Description
Caractères d'impression
Vous savez déjà que la fonction printf() , définie dans le fichier d'entête C stdio.h, peut être utilisée
pour imprimer des messages à l'écran. (Réf. Listing 2.1 de l'heure 2.) Dans cette section, vous allez
apprendre à utiliser le spécificateur de format de caractère, %c, qui indique à la fonction printf() que
l'argument à afficher est un caractère. (Vous en apprendrez plus sur le spécificateur de format dans
l'heure 5, "Gestion des entrées et sorties standard". Ici, vous venez de vous mouiller les pieds.) La
chose importante à savoir pour l'instant est que chaque spécificateur de format dans la chaîne que vous
passez à printf() correspondra à l'une des variables que vous transmettez à la fonction. Voyons d'abord
le programme du Listing 4.1, qui imprime les caractères à l'écran.
caractère c1 ;
caractère c2 ;
c1 = 'A' ; c2
= 'un' ;
8 : 9 : 10 : 11printf("Convertir
: la valeur de c1 en caractère : %c.\n", c1); printf("Convertir la
12 : valeur de c2 en caractère : %c.\n", c2); renvoie 0 ;
13 :
14 : }
Une fois le fichier exécutable de 04L01.c du Listing 4.1 créé, vous pouvez l'exécuter pour voir ce qui
sera imprimé à l'écran. Sur ma machine, le fichier exécutable est nommé 04L01.exe. Voici la sortie
imprimée sur l'écran de mon ordinateur après avoir lancé l'exécutable :
Machine Translated by Google
Comme vous le savez, la ligne 2 inclut le fichier d'entête, stdio.h, pour la fonction printf() .
UNE ANALYSE
Les lignes 5 à 15 constituent le corps de la fonction main() .
Les lignes 6 et 7 déclarent deux variables de caractère, c1 et c2, tandis que les lignes 9 et 10 affectent c1 et
c2 avec les constantes de caractère 'A' et 'a', respectivement.
Notez que le spécificateur de format %c est utilisé dans la fonction printf() aux lignes 11 et 12, qui indique
à l'ordinateur que le contenu contenu par c1 et c2 doit être imprimé sous forme de caractères. Lorsque les
deux instructions des lignes 11 et 12 sont exécutées, deux caractères sont formatés et affichés à l'écran, en
fonction des valeurs numériques contenues respectivement par c1 et c2 .
Maintenant, regardez le programme montré dans le Listing 4.2. Cette fois, %c est utilisé pour reconvertir
les valeurs numériques en caractères correspondants.
caractère c1 ;
caractère c2 ;
c1 =65 ;
c2 = 97 ;
printf("Le caractère qui a la valeur numérique de 65 est : %c.\n", c1); printf("Le caractère qui a la valeur numérique
de 97 est : %c.\n", c2); renvoie 0 ;
Voici la sortie imprimée sur l'écran de mon ordinateur après avoir exécuté le fichier exe cutable, 04L02.exe.
(Vous pouvez recevoir une sortie différente de votre ordinateur ; cela dépend de l'implémentation. C'està
dire que cela dépend du type de votre ordinateur, du système d'exploitation et de l'ordinateur C que vous
utilisez) :
Le programme de l'extrait 4.2 est similaire à celui de l'extrait 4.1, à l'exception des deux instructions
UNE ANALYSE
des lignes 9 et 10. Notez qu'aux lignes 9 et 10 de l'extrait 4.2, les variables de caractère c1 et c2
reçoivent respectivement 65 et 97 .
Machine Translated by Google
62 Heure 4
Comme vous le savez, 65 est la valeur numérique (décimal) du caractère A dans le jeu de caractères ASCII ; 97
est la valeur numérique de a. Aux lignes 11 et 12, le spécificateur de format %c convertit les valeurs numériques,
65 et 97, en A et a, respectivement. Les caractères A et a sont alors imprimés à l'écran.
Selon le système d'exploitation et le compilateur C que vous utilisez, la longueur d'un entier varie. Sur la
plupart des stations de travail UNIX, par exemple, un entier a une longueur de 32 bits, ce qui signifie que la
plage d'un entier va de 2147483647 (c'estàdire 231–1) à 2147483648. La plage d'un entier 16 bits va de
32767 (c'estàdire 215–1) à 32768.
Encore une fois, cela peut varier d'un système à l'autre, vous pouvez donc vérifier les documents de référence
de votre compilateur pour en être sûr.
Certains compilateurs C, tels que Visual C++ 1.5, fournissent uniquement l'entier 16 bits, tandis que d'autres
compilateurs C 32 bits, tels que Visual C++ 5.0, prennent en charge l'entier 32 bits.
Semblable à la déclaration de caractères, si vous avez plus d'une variable à déclarer, vous pouvez soit utiliser
le format comme ceci :
ou comme ceci :
Ici variablename1, variablename2 et variablename3 indiquent les endroits où vous mettez les noms des variables
int .
Par exemple, l'instruction suivante déclare MyInteger en tant que variable entière et lui attribue une valeur :
entier A, a, B, b ;
A = 37 ;
un = –37 ;
B = 2418 ; b =
12 ;
Vous en apprendrez plus sur le type de données entier plus tard dans le livre.
Dans cette section, vous allez étudier un programme, présenté dans le Listing 4.3, qui peut imprimer les
valeurs numériques des caractères en utilisant le spécificateur de format entier %d avec printf().
caractère c1 ;
caractère c2 ;
c1 = 'A' ; c2
= 'un' ;
8 : 9 : 10 : 11printf("La
: valeur numérique de A est : %d.\n", c1); printf("La valeur
12 : numérique de a est : %d.\n", c2); renvoie 0 ;
13 :
14 : }
J'obtiens la sortie suivante sur l'écran de mon ordinateur après avoir exécuté le fichier exécutable, 04L03.exe.
(Vous pouvez obtenir une sortie différente si votre machine n'utilise pas le jeu de caractères ASCII.)
UNE ANALYSE
Vous constaterez peutêtre que le programme du Listing 4.3 est assez similaire à celui du Listing 4.1.
En fait, j'ai simplement copié le code source du Listing 4.1 vers le Listing 4.3 et apporté des
modifications aux lignes 11 et 12. Le changement majeur que j'ai apporté a été de remplacer le spécificateur
de format de caractère (%c) par le spécificateur de format entier (% ré).
Machine Translated by Google
64 Heure 4
Les deux spécificateurs de format font fondamentalement la même chose insérez des données dans la chaîne
que vous transmettez à printf() mais la différence réside dans la façon dont printf() affiche ces données. Le
spécificateur %c imprime toujours un caractère ; le spécificateur %d imprime toujours un nombre. Même
lorsqu'ils font référence aux mêmes données, elles seront imprimées comme vous l'indiquez dans le
spécificateur de format, quel que soit le type de données réel.
Les deux instructions des lignes 11 et 12 formatent les deux variables de caractères (c1 et c2) en utilisant le
spécificateur de format entier %d, puis impriment deux messages indiquant les valeurs numériques 65 et 97
qui représentent, respectivement, les caractères A et a dans le jeu de caractères ASCII.
Un nombre à virgule flottante est spécifié par le motclé float dans le langage C. Les constantes de pointeur
flottant peuvent être suffixées avec f ou F pour spécifier float. Un nombre à virgule flottante sans suffixe est
double par défaut. Le type de données double est présenté plus loin dans cette leçon.
Comme un nombre entier, un nombre à virgule flottante a une plage limitée. La norme ANSI exige que la
plage soit au moins plus ou moins 1,0 × 1037. Dans la plupart des cas, un nombre à virgule flottante est
représenté en prenant 32 bits. Par conséquent, un nombre à virgule flottante en C a une précision d'au moins
six chiffres. Autrement dit, pour un nombre à virgule flottante, il y a au moins six chiffres (ou décimales) à droite
de la virgule décimale.
Contrairement à une division entière dont le résultat est tronqué et la fraction est supprimée, une
division à virgule flottante produit un autre nombre à virgule flottante. Une division à virgule flottante est
effectuée si le diviseur et le dividende, ou l'un d'eux, sont des nombres à virgule flottante.
Par exemple, 571.2 / 10.0 produit un autre nombre à virgule flottante, 57.12. Il en va de même pour 571.2/10
et 5712/10.0.
Semblable à la déclaration de caractères ou d'entiers, si vous avez plus d'une variable à déclarer,
vous pouvez soit utiliser le format comme ceci :
ou comme celuici :
Par exemple, l'instruction suivante déclare myFloat en tant que variable flottante et lui attribue une valeur :
flottant a, b, c ; a
= 10,38 ; b = –
32,7 ; c = 12,0f ;
TAPER LISTE 4.4 Impression des résultats de la division entière et virgule flottante
8:
9: int_num1 = 32 / 10 ; /* Le diviseur et le dividende sont tous deux
entiers */ flt_num1 = 32 /
10: 10 ; int_num2 = 32,0 /
11: 10 ; /* Le diviseur est un entier */ flt_num2 = 32.0 / 10; int_num3 = 32 /
12 : 10.0 ; /* Le dividende est un entier */ flt_num3 = 32 / 10.0;
13:
14:
continue
Machine Translated by Google
66 Heure 4
17: printf("La division en virgule flottante de 32/10 est : %f\n", flt_num1); printf("La
division entière de 32.0/10 est : %d\n", int_num2); printf("La division en virgule
flottante de 32.0/10 est : %f\n", flt_num2); printf("La division entière de 32/10.0 est :
%d\n", int_num3); printf("La division en virgule flottante de 32/10.0 est : %f\n",
18h19h20h21h
flt_num3); renvoie 0 ;
22:
23 : }
UNE ANALYSE
Dans la fonction main() , les deux instructions des lignes 6 et 7 déclarent trois variables
entières, int_num1 , int_num2 et int_num3, et trois variables à virgule flottante.
ables, flt_num1 , flt_num2 et flt_num3.
Ensuite, les lignes 16 à 21 impriment les valeurs contenues par les trois variables int et les trois
variables à virgule flottante. Notez que %d est utilisé pour les variables entières et que le
spécificateur à virgule flottante (%f) est utilisé pour formater les variables à virgule flottante dans la
fonction printf() .
Étant donné que la troncature se produit dans la division entière de 32/10, flt_num1 contient
3,000000, et non 3,200000, ce que vous pouvez voir sur la deuxième ligne de la sortie. Cependant,
flt_num2 et flt_num3 se voient attribuer 3,200000 car 32,0/10 et 32/10,0 sont considérés comme la
division à virgule flottante.
Machine Translated by Google
Mais int_num2 et int_num3, en tant que variables entières, rejettent respectivement les parties fractionnaires
des divisions à virgule flottante de 32.0/10 et 32/10.0. Par conséquent, vous ne voyez que l'entier 3 dans les
troisième et cinquième lignes de la sortie.
La différence entre un type de données double et un type de données flottant est que le premier utilise deux
fois plus de bits que le second. Par conséquent, un nombre à virgule flottante double a une précision d'au moins
10 chiffres, bien que la norme ANSI ne le spécifie pas pour le type de données double .
Dans l'heure 8, "Utilisation des opérateurs conditionnels", vous apprendrez à utiliser l' opérateur
sizeof pour obtenir la longueur en octets d'un type de données, tel que char, int, float ou double,
spécifié sur votre système informatique.
4
Utiliser la notation scientifique
Le langage C utilise la notation scientifique pour vous aider à écrire de longs nombres à virgule flottante.
En notation scientifique, un nombre peut être représenté par la combinaison de la mantisse et de l' exposant.
Le format de la notation est que la mantisse est suivie de l'exposant, qui est préfixé par e ou E. Voici deux
exemples :
exponentielle la mantisse
et
exposant de la mantisse
Veuillez noter que la mantisse et l'exposant cidessus sont tous deux des espaces réservés et que vous
devez les remplacer par des valeurs numériques.
Par exemple, 5000 peut être représenté par 5e3 en notation scientifique. De même, 300 peut être représenté
par 3e2 et 0,0025 par 2,5e3.
De même, le spécificateur de format, %e ou %E, est utilisé pour formater un nombre à virgule flottante en
notation scientifique. L'utilisation de %e ou %E dans la fonction printf() est la même
comme %f.
Machine Translated by Google
68 Heure 4
Tout comme les noms de fonction doivent idéalement refléter la tâche que la fonction exécute, les noms de variable
doivent décrire la valeur stockée dans la variable et à quoi elle sert dans votre programme ou votre fonction. Jusqu'à
présent, la plupart des exemples de code ont utilisé des noms de variables à une seule lettre tels que i, mais à mesure
que vous écrivez des programmes plus volumineux et des fonctions plus compliquées, il devient de plus en plus
important de donner à vos variables des noms significatifs.
N'utilisez jamais les mots clés C réservés dans le langage C, ou les noms des fonctions de
la bibliothèque C standard, comme noms de variables dans votre programme C.
Résumé
Dans cette leçon, vous avez découvert les motsclés C et les types de données importants suivants :
flottante peuvent être suffixés avec f ou F pour spécifier float. Un nombre à virgule flottante sans suffixe est
double par défaut. • Les plages possibles des types de données char, int et float • Le type de données
double • La notation scientifique et les spécificateurs de format %e et %E • Les règles que vous devez suivre
Dans la prochaine leçon, vous en apprendrez plus sur la fonction printf() et d'autres fonctions pour gérer les entrées
et les sorties.
Questions et réponses
A Les caractères sont stockés dans les ordinateurs sous forme de bits. Les combinaisons de bits
peut être utilisé pour représenter différentes valeurs numériques. Un personnage doit avoir un caractère unique
Machine Translated by Google
valeur numérique afin de se distinguer. De nombreux systèmes informatiques prennent en charge le jeu
de caractères ASCII, qui contient un ensemble de valeurs numériques uniques pouvant contenir jusqu'à
256 caractères.
Veuillez noter que votre ordinateur peut utiliser un jeu de caractères différent du jeu de caractères ASCII.
Ensuite, tous les caractères utilisés par le langage C, à l'exception du caractère nul, peuvent avoir des
valeurs numériques différentes des valeurs représentées par le caractère ASCII
ensemble d'acteurs.
A Tout d'abord, un entier ne contient aucune partie fractionnaire, mais un nombre à virgule flottante
Estce que. Un nombre à virgule flottante doit avoir une virgule décimale. En C, le type de données float
prend plus de bits que le type de données int . En d'autres termes, le type de données float a une plus grande
plage de valeurs numériques que le type de données int .
De plus, la division entière tronque la partie fractionnaire. Par exemple, la division entière de 16/10 produit
un résultat de 1, et non de 1,6.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe C, « Réponses aux questions et exercices du
quiz ».
Questionnaire
2. Le résultat de 3000 + 1,0 estil un nombre à virgule flottante ? Que diriez vous de 3000/1.0 ?
Machine Translated by Google
70 Heure 4
• 0,0035
• –0,0035
• 7ème_calcul
• Méthode_de Tom
• _index
• Libellé_1
Des exercices
1. Écrivez un programme qui imprime les valeurs numériques des caractères Z et z.
2. Étant donné deux valeurs numériques, 72 et 104, écrivez un programme pour imprimer le corre
répondant à deux caractères.
3. Pour une variable entière 16 bits, pouvezvous attribuer à la variable une valeur entière de
72368 ?
4. Étant donné la déclaration double dbl_num = 123.456;, écrivez un programme qui imprime la valeur
de dbl_num dans les deux formats de notation à virgule flottante et scientifique.
5. Écrivez un programme capable d'imprimer la valeur numérique du caractère de saut de ligne (\n).
(Astuce : affectez '\n' à une variable de type caractère.)
Machine Translated by Google
HEURE 5
Dans la dernière leçon, vous avez appris à afficher des caractères, des entiers et des nombres à
virgule flottante à l'écran en appelant la fonction printf() . Dans cette leçon, vous allez en savoir
plus sur printf(), ainsi que sur les fonctions suivantes, qui sont nécessaires pour recevoir l'entrée
de l'utilisateur ou pour afficher la sortie à l'écran :
• La fonction getc() • La
Avant de nous lancer dans ces nouvelles fonctions, commençons par nous faire une idée des
entrées et sorties (E/S) standard en C.
Machine Translated by Google
72 Heure 5
représenté en bits sur les ordinateurs, et un octet est une série de bits, le langage C traite un fichier
comme une série d'octets. Une série d'octets est également appelée flux. En fait, le langage C traite tous
les flux de fichiers de la même manière, bien que certains des flux de fichiers puissent provenir d'un lecteur
de disque ou de bande, d'un terminal ou même d'une imprimante.
De plus, en C, trois flux de fichiers sont préouverts pour vous, c'estàdire qu'ils sont toujours disponibles
pour être utilisés dans vos programmes :
Habituellement, le flux de fichiers d'entrée standard (stdin) est lié à votre clavier, tandis que les flux de
fichiers de sortie standard (stdout) et d'erreur standard (stderr) pointent vers l'écran de votre terminal. En
outre, de nombreux systèmes d'exploitation permettent à l'utilisateur de rediriger ces flux de fichiers.
En fait, vous avez déjà utilisé stdout. Lorsque vous avez appelé la fonction printf() dans la dernière leçon,
vous envoyiez en fait la sortie au flux de fichiers par défaut, stdout, qui pointe vers votre écran.
Vous en apprendrez plus sur stdin et stdout dans les sections suivantes.
Entrée de syntaxe
SYNTAXE La syntaxe de la fonction getc() est #include
<stdio.h> int getc(FILE *stream);
Ici, FILE *stream déclare un flux de fichier (c'estàdire une variable). La fonction renvoie
la valeur numérique du caractère lu. En cas de fin de fichier ou d'erreur, la fonction renvoie
EOF.
Pour l'instant, ne vous souciez pas de la structure FILE . Plus de détails à ce sujet sont présentés dans
les heures 21, « Lecture et écriture avec des fichiers », et 22, « Utilisation des fonctions de fichiers
spéciales ». Dans cette section, le flux d'entrée standard stdin est utilisé comme flux de fichier spécifié par
FICHIER *flux.
Défini dans le fichier d'entête stdio.h, EOF est une constante. EOF signifie fin de fichier.
Habituellement, la valeur de EOF est 1. Mais continuez à utiliser EOF, au lieu de 1, pour indiquer
la fin de fichier dans vos programmes. De cette façon, si vous utilisez ultérieurement une compilation
ou un système d'exploitation qui utilise une valeur différente, votre programme fonctionnera toujours.
Le Listing 5.1 montre un exemple qui lit un caractère saisi par l'utilisateur à partir du
clavier, puis affiche le caractère à l'écran.
int ch ;
12 : }
Voici la sortie affichée sur l'écran de mon ordinateur après avoir exécuté le fichier
exécutable, 05L01.exe, saisi le caractère H et appuyé sur la touche Entrée :
Veuillez saisir un caractère :
SORTIR
H
Le caractère que vous venez d'entrer est : H
Machine Translated by Google
74 Heure 5
UNE ANALYSE Vous voyez à la ligne 2 du Listing 5.1 que le fichier d'entête stdio.h est inclus pour les
fonctions getc() et printf() utilisées dans le programme. Les lignes 4 à 12 donnent le
nom et corps de la fonction main() .
A la ligne 6, une variable entière, ch, est déclarée ; la valeur de retour de la fonction getc() lui
est affectée plus tard à la ligne 9. La ligne 8 imprime un message demandant à l'utilisateur d'entrer
un caractère au clavier. Comme je l'ai mentionné plus tôt dans cette leçon, l' appel de la fonction
printf() à la ligne 8 utilise la sortie standard par défaut stdout pour afficher les messages à l'écran.
À la ligne 9, le flux d'entrée standard stdin est passé à la fonction getc() , qui indique que le flux
de fichier provient du clavier. Une fois que l'utilisateur a saisi un caractère, la fonction getc()
renvoie la valeur numérique (c'estàdire un entier) du caractère. Vous voyez qu'à la ligne 9, la
valeur numérique est affectée à la variable entière ch.
Ensuite, à la ligne 10, le caractère saisi par l'utilisateur est affiché à l'écran à l'aide de printf(). Notez
que le spécificateur de format de caractère (%c) est utilisé dans l' appel de la fonction printf() à la
ligne 10. (L'exercice 1 de cette leçon vous demande d'utiliser %d dans un programme pour imprimer
la valeur numérique d'un caractère entré par le utilisateur.)
Entrée de syntaxe
La syntaxe de la fonction getchar() est #include
<stdio.h> int getchar(void);
SYNTAXE
Ici, void indique qu'aucun argument n'est nécessaire pour appeler la fonction. La fonction
renvoie la valeur numérique du caractère lu. Si une fin de fichier ou une erreur se produit, la fonction
renvoie EOF.
Le programme du Listing 5.2 montre comment utiliser la fonction getchar() pour lire l'entrée de
l'utilisateur.
TAPER
LISTE 5.2 Lire un caractère en appelant getchar()
8: printf("Veuillez saisir deux caractères ensemble :\n"); ch1 = getc( stdin ); ch2 =
9: getchar( ); printf("Le premier caractère que vous venez d'entrer est : %c\n", ch1);
10 : printf("Le deuxième caractère que vous venez d'entrer est : %c\n", ch2); renvoie 0 ;
11 :
12 :
13 :
14 : }
Après avoir exécuté le fichier exécutable, 05L02.exe, et saisi deux caractères (H et i) ensemble
sans espaces, j'appuie sur la touche Entrée et le résultat suivant s'affiche sur l'écran de mon ordinateur :
Le programme du Listing 5.2 est assez similaire à celui du Listing 5.1, sauf que celuici se
UNE ANALYSE
lit en deux caractères.
L'instruction de la ligne 6 déclare deux entiers, ch1 et ch2. La ligne 8 affiche un message
demandant à l'utilisateur d'entrer deux caractères ensemble.
Ensuite, les fonctions getc() et getchar() sont appelées aux lignes 9 et 10, respectivement, pour lire
deux caractères saisis par l'utilisateur. Notez qu'à la ligne 10, rien n'est passé à la fonction
getchar() . En effet, comme mentionné précédemment, getchar() utilise le flux de fichier d'entrée
par défaut, stdin. Vous pouvez remplacer la fonction getchar() à la ligne 10 par getc(stdin) car
getc(stdin) est équivalent à getchar().
Les lignes 11 et 12 envoient deux caractères (conservés respectivement par ch1 et ch2 ) à l'écran.
5
76 Heure 5
Entrée de syntaxe
SYNTAXE La syntaxe de la fonction putc() est #include <stdio.h> int
putc(int c, FILE *stream);
Ici, le premier argument, int c, indique que la sortie est un caractère enregistré dans une variable
entière c ; le deuxième argument, FILE *stream, spécifie un flux de fichier. En cas de succès, putc()
renvoie le caractère écrit ; sinon, il renvoie EOF.
Dans cette leçon, la sortie standard stdout est spécifiée comme flux de fichier de sortie dans putc().
La fonction putc() est utilisée dans le Listing 5.3 pour placer le caractère A à l'écran.
int ch ;
ch = 65 ; /* la valeur numérique de A */
printf("Le caractère qui a la valeur numérique de 65 est :\n"); putc(ch, stdout); renvoie 0 ;
8 : 9 : 10 : 11 :
12 : }
La ligne 9 affiche un message pour rappeler à l'utilisateur la valeur numérique du caractère qui va
être mis à l'écran. Ensuite, la fonction putc() de la ligne 10 place le caractère A à l'écran. Notez que
le premier argument de la fonction putc() est la variable entière (ch) qui contient 65, et le second
argument est le flux de fichier de sortie standard, stdout.
Machine Translated by Google
Entrée de syntaxe La
SYNTAXE
syntaxe de la fonction putchar() est #include <stdio.h> int
putchar(int c);
Ici int c est l'argument qui contient la valeur numérique d'un caractère. La fonction renvoie EOF si une
erreur se produit ; sinon, il renvoie le caractère qui a été écrit.
TAPER
LISTE 5.4 Sortie de caractères avec putchar().
putchar(65);
7: putchar(10);
8: putchar(66);
9: putchar(10);
10 :
5
putchar(67); putchar(10);
11 : renvoie 0 ;
12 :
13 : }
La manière d'écrire le programme du Listing 5.4 est un peu différente. Il n'y a pas de variable
UNE ANALYSE
déclarée dans le programme. Au lieu de cela, les entiers sont passés directement à putchar() ,
comme indiqué aux lignes 6 à 11.
Comme vous l'avez peutêtre compris, 65, 66 et 67 sont respectivement les valeurs numériques des
caractères A, B et C dans le jeu de caractères ASCII. À partir de l'exercice 5 de l'heure 4, « Comprendre
les types de données et les mots clés », vous pouvez découvrir que 10 est la valeur numérique du caractère
de retour à la ligne (\n).
Machine Translated by Google
78 Heure 5
Ainsi, respectivement, les lignes 6 et 7 placent le caractère A sur l'écran et font démarrer l'ordinateur
au début de la ligne suivante. De même, la ligne 8 met B à l'écran et la ligne 9 commence une nouvelle
ligne. Ensuite, la ligne 10 place C à l'écran et la ligne 11 commence une autre nouvelle ligne. En
conséquence, A, B et C sont placés au début de trois lignes consécutives, comme indiqué dans la section
de sortie.
Entrée de syntaxe
SYNTAXE
La syntaxe de la fonction printf() est #include
<stdio.h> int printf(const char *formatstring, .
. .);
Ici const char *formatstring est le premier argument qui contient le(s) spécificateur(s) de format ; ...
indique la section d'expression qui contient la ou les expressions à formater selon les spécificateurs de
format. Le nombre d'expressions est déterminé par le nombre de spécificateurs de format à l'intérieur
du premier argument. La fonction renvoie le nombre d'expressions formatées si elle réussit. Il renvoie
une valeur négative en cas d'erreur.
const char * est expliqué plus loin dans ce livre. Pour le moment, considérez le premier argument de la
fonction printf() comme une chaîne (une série de caractères entourés de guillemets doubles) avec
quelques spécificateurs de format à l'intérieur. Par exemple, vous pouvez passer "La somme de deux
entiers %d + %d est : %d.\n" à la fonction comme premier argument.
La figure 5.1 montre la relation entre la chaîne de format et les expressions. Notez que les spécificateurs
de format et les expressions correspondent dans l'ordre de gauche à droite.
FIGURE 5.1
Format chaîne Expressions
La relation entre
la chaîne de format et les
expressions dans printf().
N'oubliez pas que vous devez utiliser exactement le même nombre d'expressions que le nombre de spécificateurs de
Voici tous les spécificateurs de format qui peuvent être utilisés dans printf() :
%dans
Le spécificateur de format d'entier non signé.
Parmi les spécificateurs de format de cette liste, %c, %d, %f, %e et %E ont été introduits jusqu'à présent. Plusieurs autres sont expliqués plus loin
dans ce livre. La section suivante vous montre comment convertir des nombres décimaux en nombres hexadécimaux en utilisant %x ou %X.
uns), toutes les données avec lesquelles nous travaillons ou que nous imprimons ne sont en réalité qu'une sorte de
représentation lisible par l'homme des données binaires. En tant que programmeur, il est souvent nécessaire de traiter
directement des données binaires, mais il est extrêmement long de déchiffrer une chaîne de zéros et de uns et d'essayer de
80 Heure 5
La solution à ce problème est la notation hexadécimale (ou hexadécimal), qui est une sorte de raccourci pour
représenter les nombres binaires. Hex est un compromis entre le système de numération en base 2 (ou binaire)
lisible par ordinateur et notre système plus familier en base 10 (ou décimal).
Convertir des nombres de l'hexadécimal au décimal (ou du binaire à l'hexadécimal) et inversement est
beaucoup plus facile (pour ne pas dire plus rapide) que de convertir directement du binaire au décimal ou viceversa.
décimal est un système de numération en base 16. Un nombre hexadécimal peut être représenté par quatre
bits. (24 ] est égal à 16, ce qui signifie que quatre bits peuvent produire 16 nombres uniques.)
Les nombres hexadécimaux 0 à 9 utilisent les mêmes symboles numériques trouvés dans les nombres
décimaux 0 à 9. A, B, C, D, E et F sont utilisés pour représenter, respectivement, les nombres 10 à 15 en
majuscules. (De même, en minuscules, a, b, c, d, e et f sont utilisés pour représenter ces nombres hexadécimaux.
Les hexagones majuscules et minuscules sont interchangeables et ne sont qu'une question de style.)
Le Listing 5.5 fournit un exemple de conversion de nombres décimaux en nombres hexadécimaux en utilisant
%x ou %X dans la fonction printf() .
24 : }
Machine Translated by Google
La sortie suivante est obtenue en exécutant le fichier exécutable, 05L05.exe, sur mon ordinateur :
1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
UN 10
B un B 11
C 12
ré CD 13
ET si 14
F 15
UNE ANALYSE
Ne paniquez pas lorsque vous voyez autant d' appels de fonction printf() utilisés dans le Listing
5.5. En fait, le programme du Listing 5.5 est très simple. Le programme n'a qu'un seul corps de
fonction des lignes 5 à 23.
Ensuite, les lignes 7 à 22 impriment les nombres hexadécimaux et décimaux de 0 à 15. Seize
appels printf() sont effectués pour accomplir le travail. Chacun des appels printf() a une chaîne de format
comme premier argument suivi de trois entiers comme trois expressions. Notez que les spécificateurs de 5
format hexadécimal %X et %x sont utilisés dans la chaîne de format dans chacun des appels printf() pour
convertir les expressions correspondantes au format hexadécimal (majuscules et minuscules).
En réalité, personne n'écrirait un programme comme celui du Listing 5.5. Au lieu de cela, une boucle peut
être utilisée pour appeler la fonction printf() à plusieurs reprises. La boucle (ou itération) est introduite dans
l'heure 7, "Travailler avec les boucles".
82 Heure 5
L'exemple du Listing 5.6 montre comment utiliser le spécificateur de largeur de champ minimum.
nombre1 =
12 ; num2 =
12345 ; printf("%d\n", num1);
8 : 9 : 10 : 11printf("%d\n",
: num2);
12 : printf("%5d\n", num1);
13: printf("%05d\n", num1);
14: printf("%2d\n", num2); renvoie
15 : 0;
16 : }
12
SORTIR
12345
12
00012
12345
UNE ANALYSE Dans le Listing 5.6, deux variables entières, num1 et num2, sont déclarées à la ligne 6 et
affectées respectivement de 12 et 12345 aux lignes 8 et 9.
Sans utiliser de spécificateurs de largeur de champ minimum, les lignes 10 et 11 affichent les deux entiers
en appelant la fonction printf() . Vous pouvez voir dans la section de sortie que la sortie de l'instruction de la
ligne 10 est 12, ce qui prend deux espaces de caractères, tandis que la sortie 12345 de la ligne 11 prend
cinq espaces de caractères.
À la ligne 12, une largeur de champ minimale, 5, est spécifiée par %5d. La sortie de la ligne 12 prend donc
cinq espaces de caractères, avec trois espaces blancs plus deux espaces de caractères de 12.
(Voir la troisième ligne de sortie dans la section de sortie.)
Le %05d dans printf(), affiché à la ligne 13, indique que la largeur de champ minimale est de 5, et le 0 indique
que des zéros sont utilisés pour remplir, ou "compléter", les espaces. Par conséquent, vous voyez que la
sortie effectuée par l'exécution de l'instruction de la ligne 13 est 00012.
Machine Translated by Google
Le %2d à la ligne 14 définit la largeur de champ minimale sur 2, mais vous voyez toujours la sortie pleine grandeur
de 12345 à partir de la ligne 14. Cela signifie que lorsque la largeur de champ minimale est plus courte que la
largeur de la sortie, celleci est prise et la sortie est toujours imprimée dans son intégralité.
Alignement de la sortie
Comme vous l'avez peutêtre remarqué dans la section précédente, toutes les sorties sont justifiées à droite.
En d'autres termes, par défaut, toutes les sorties sont placées sur le bord droit du champ, tant que la largeur du
champ est supérieure à la largeur de la sortie.
Vous pouvez modifier cela et forcer la sortie à être justifiée à gauche. Pour ce faire, vous devez préfixer le
spécificateur de champ minimum avec le signe moins (). Par exemple, %12d spécifie la largeur de champ
minimale à 12 et justifie la sortie à partir du bord gauche du champ.
Le Listing 5.7 donne un exemple d'alignement de la sortie par justification à gauche ou à droite.
nombre1 =
1 ; nombre2
= 12 ; nombre3
8 : 9 : 10 : 11=: 123 ; nombre4
12 :
5
= 1234 ; num5 =
13: 12345 ; printf("%8d %8d\n", num1, num1);
14: printf("%8d %8d\n", num2, num2); printf("%8d
%8d\n", num3, num3); printf("%8d %8d\n",
num4, num4); printf("%8d %8d\n", num5,
15 : 16 : 17 num5);
: renvoie 0 ;
18 :
19 : }
J'obtiens la sortie suivante affichée sur l'écran de mon ordinateur après avoir exécuté l'exe cutable 05L07.exe :
1 1
SORTIR
12 12
123 123
1234 1234
12345 12345
Machine Translated by Google
84 Heure 5
UNE ANALYSE
Dans le Listing 5.7, il y a cinq variables entières, num1, num2, num3, num4 et num5, qui
sont déclarées à la ligne 6 et qui reçoivent des valeurs aux lignes 8 à 12.
Ces valeurs représentées par les cinq variables entières sont ensuite imprimées par les fonctions printf()
aux lignes 13–17. Notez que tous les appels printf() ont le même premier argument : "%8d %8d\n". Ici, le
premier spécificateur de format, %8d, aligne la sortie sur le bord droit du champ, et le deuxième spécificateur,
%8d, aligne la sortie sur le bord gauche du champ.
Après l'exécution des instructions des lignes 13 à 17, l'alignement est accompli et la sortie est affichée à l'écran
comme ceci :
1 1
12 12
123 123
1234 1234
12345 12345
Par exemple, avec %10.3f, la longueur minimale de la largeur de champ est spécifiée sur 10 caractères et le
nombre de décimales est défini sur 3. (N'oubliez pas que le nombre de décimales par défaut est 6.) Pour les
nombres entiers, %3.8d indique que la largeur de champ minimale est de 3 et que la largeur de champ maximale
est de 8.
entier
entier_num ; double flt_num ;
int_num = 123 ;
flt_num = 123,456789 ;
8 : 9 : 10 : 11printf("Format
: entier par défaut : %d\n", int_num);
Machine Translated by Google
Après avoir exécuté le fichier exécutable 05L08.exe sur mon ordinateur, j'obtiens le résultat suivant à
l'écran :
Le programme du Listing 5.8 déclare une variable entière, int_num, à la ligne 6, et un nombre à
UNE ANALYSE
virgule flottante, flt_num, à la ligne 7. Les lignes 9 et 10 attribuent 123 et 123,456789 à int_num
et flt_num, respectivement.
À la ligne 11, le format entier par défaut est spécifié pour la variable entière, int_num, tandis que
l'instruction de la ligne 12 spécifie le format entier avec un spécificateur de précision qui indique que la
largeur maximale du champ est de huit caractères. Par conséquent, vous voyez que cinq zéros sont
remplis avant l'entier 123 dans la deuxième ligne de la sortie.
Pour la variable à virgule flottante, flt_num, la ligne 13 imprime la valeur à virgule flottante dans le format
par défaut, et la ligne 14 réduit les décimales à deux en plaçant le spécificateur de précision .2 dans le
spécificateur de format %10.2f. Notez ici que la justification à gauche est également spécifiée par le
signe moins () dans le spécificateur de format à virgule flottante.
Le nombre à virgule flottante 123,46 dans la quatrième ligne de la sortie est produit par l'instruction 5
de la ligne 14 avec le spécificateur de précision pour deux décimales. Par conséquent, 123,456789
arrondi à deux décimales devient 123,46.
Résumé
Dans cette leçon, vous avez appris les concepts, spécificateurs et fonctions importants suivants :
stdin, stdout et stderr sont trois flux de fichiers qui sont préouverts et que vous pouvez toujours
utiliser.
• Les fonctions de la bibliothèque C getc() et getchar() peuvent être utilisées pour lire un caractère à
partir de l'entrée standard.
• Les fonctions de la bibliothèque C putc() et putchar() peuvent être utilisées pour écrire un caractère
à la sortie standard.
Machine Translated by Google
86 Heure 5
• %x ou %X peuvent être utilisés pour convertir des nombres décimaux en nombres hexadécimaux.
• Une largeur de champ minimale peut être spécifiée et garantie en ajoutant un entier dans un
spécificateur de format.
• Une sortie peut être alignée sur le bord gauche ou droit du champ de sortie. • Un spécificateur
de précision peut être utilisé pour spécifier le nombre de décimales pour flottant
nombres de points ou la largeur de champ maximale pour les entiers ou les chaînes.
Questions et réponses
Un hexadécimal, ou hexadécimal en abrégé, est un système numérique de base 16. Par conséquent, 32
(hex) est égal à 3*161 +2*160 , ou 50 en décimal.
R Étant donné que la fonction getchar() lit à partir du flux de fichiers stdin par défaut, getc(stdin) et
getchar() sont équivalents dans ce cas.
Q Dans la fonction printf("L'entier %d est identique à l'hex %x", 12, 12), quelle est la relation entre les
spécificateurs de format et les expressions ?
A Les deux spécificateurs de format, %d et %x, spécifient les formats des valeurs numériques contenues
dans la section expression. Ici, la première valeur numérique de 12 va être imprimée au format entier,
tandis que la seconde 12 (dans la section expression) sera affichée au format hexadécimal. D'une
manière générale, le nombre de spécificateurs de format dans la section format doit correspondre au
nombre d'expressions dans la section expression.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».
Machine Translated by Google
Questionnaire
1. Pouvezvous aligner votre sortie sur le bord gauche, plutôt que sur le bord droit, de la sortie
domaine?
4. Dans %10.3f, quelle partie est le spécificateur de largeur de champ minimum et lequel est le spécificateur de
précision ?
Des exercices
2. Affichez les deux nombres 123 et 123.456 et alignezles sur le bord gauche du
domaine.
3. Étant donné trois nombres entiers, 15, 150 et 1500, écrivez un programme qui imprime les nombres entiers sur
l'écran au format hexadécimal.
4. Écrivez un programme qui utilise getchar() et putchar() pour lire un caractère saisi
par l'utilisateur et écrivez le caractère à l'écran.
principale()
{
int ch ;
ch = getchar();
putchar(ch); 5
renvoie 0 ;
}
Machine Translated by Google
Machine Translated by Google
PARTIE II
Opérateurs et instructions
de flux de contrôle
Heure
6 Manipulation des données
HEURE 6
—L. Carroll
Vous pouvez considérer les opérateurs comme des verbes en C qui vous permettent de
manipuler des données (qui sont comme des noms). En fait, vous avez appris certains
opérateurs, tels que + (addition), (soustraction), * (multiplication), / (division) et % (reste), à
l'heure 3, "Apprendre la structure d'un programme C .” Le langage C possède un riche ensemble
d'opérateurs. Au cours de cette heure, vous découvrirez d'autres opérateurs, tels que
d'incrémentation et de décrémentation •
distribution
Machine Translated by Google
92 Heure 6
Ici, l'instruction provoque l' affectation (ou l'écriture) de la valeur de l' opérande de droite à
l'emplacement mémoire de l' opérande de gauche. Ainsi, après l'affectation, l'opérande gauche
sera égal à la valeur de l'opérande droit. De plus, l'ensemble de l'expression d'affectation est évalué
à la même valeur que celle qui est affectée à l' opérande de gauche.
Par exemple, l'énoncé a = 5 ; écrit la valeur de l'opérande de droite (5) dans l'emplacement mémoire
de la variable entière a (qui est l'opérande de gauche dans ce cas).
Il est important de se rappeler que l'opérande de gauche de l'opérateur d'affectation doit être une
expression dans laquelle vous pouvez légalement écrire des données. Une expression telle que 6
= a, bien qu'elle puisse sembler correcte en un coup d'œil, est en fait inversée et ne fonctionnera
pas. L' opérateur = fonctionne toujours de droite à gauche ; par conséquent, la valeur de gauche
doit être une forme de variable pouvant recevoir les données de l'expression de droite.
En utilisant l'opérateur d'affectation (=) et l'opérateur d'addition (+), vous obtenez ce qui suit
déclaration:
z=x+y;
Comme vous pouvez le voir, c'est assez simple. Maintenant, considérons à nouveau le même exemple.
Cette fois, au lieu d'affecter le résultat à la troisième variable, z, réécrivons le résultat de l'addition dans la
variable entière, x :
x=x+y;
N'oubliez pas que l' opérateur = fonctionne toujours de droite à gauche, donc le côté droit sera évalué en
premier. Ici, sur le côté droit de l'opérateur d'affectation (=), l'addition de x et y est exécutée ; du côté gauche
de =, la valeur précédente de x est remplacée par le résultat de l'addition du côté droit.
Le langage C vous donne un nouvel opérateur, +=, pour faire l'addition et l'affectation ensemble. Par
conséquent, vous pouvez réécrire l'énoncé x = x + y ; comme
x += y ;
Les combinaisons de l'opérateur d'affectation (=) avec les opérateurs arithmétiques, +, , *, / et %, vous
donnent un autre type d' opérateurs, les opérateurs d'affectation arithmétique :
Opérateur La description
+= Opérateur d'affectation d'addition
=
Opérateur d'affectation de soustraction
*=
Opérateur d'affectation de multiplication
x += y ; est équivalent à x = x + y ;
6
x= y ; est équivalent à x = x y ;
x *= *
y; est équivalent à x = x Y;
x /= y ; est équivalent à x = x / y ;
x %= y ; est équivalent à x = x % y ;
94 Heure 6
z=z *
x+y ;
z*=x+y;
car
z *= x + y
multiplie z par tout le côté droit de l'instruction, de sorte que le résultat serait le
pareil que
z=z *(x+y);
Le Listing 6.1 donne un exemple d'utilisation de certains des opérateurs d'affectation arithmétiques.
entier x, y, z ;
x = 1 ; /* initialiser x */ y = 3; /* initialise y
*/ z = 10; /* initialiser
donné xz =*/ %d,
printf("Étant
y = %d, et
z = %d,\n", x, y, z);
x=x+y;
printf("x = x + y affecte %d à x ;\n", x);
x = 1 ; /* réinitialiser x */ x += y;
printf("x += y assigne %d à x ;
\n", x);
x = 1 ; /* réinitialiser x */ x + y;
z=z *
printf("z = z
*
x + y affecte %d à z ;\n", z );
z = 10 ; /* réinitialiser z */ * (x +
z=z y); printf(“z = z * (x + y)
assigne %d à z;\n”, z);
z = 10 ; /* réinitialiser z */ z *= x
+ y; printf("z *= x + y affecte %d
à z.\n", z);
renvoie 0 ;
Machine Translated by Google
Une fois ce programme compilé et lié, un fichier exécutable est créé. Sur ma machine, ce fichier exécutable
est nommé 06L01.exe. Voici la sortie affichée après avoir lancé l'exécutable :
z=z *
x + y attribue 13 à z ; * (x + y)
z=z attribue 40 à z ; z *= x + y attribue 40
à z.
UNE ANALYSE
La ligne 2 du Listing 6.1 inclut le fichier d'entête stdio.h en utilisant la directive include . Le
fichier d'entête stdio.h est nécessaire pour la fonction printf() utilisée dans les lignes 4–33.
Les lignes 8 à 10 initialisent trois variables entières, x, y et z, qui sont déclarées à la ligne 6.
La ligne 11 imprime ensuite les valeurs initiales affectées à x, y et z.
L'instruction de la ligne 13 utilise un opérateur d'addition et un opérateur d'affectation pour additionner les
valeurs contenues par x et y, puis affecte le résultat à x. La ligne 14 affiche le résultat à l'écran.
De même, les lignes 17 et 18 font la même addition et affichent à nouveau le résultat, après que la
variable x est réinitialisée à la valeur 1 à la ligne 16. Cette fois, l'opérateur d'affectation arithmétique, +=, est
utilisé.
La valeur de x est à nouveau réinitialisée à la ligne 20. La ligne 21 effectue une multiplication et une addition
et enregistre le résultat dans la variable entière z ; c'estàdire z = zx + y;.*L' le
appel
résultat,
printf()
13,ààlal'écran.
ligne 22
Encore
affiche
une fois, le x = 1 ; L'instruction à la ligne 20 réinitialise la variable entière, x.
Les lignes 24 à 30 affichent deux résultats de deux calculs. Les deux résultats sont en fait les mêmes (c'est
àdire 40) car les deux calculs des lignes 25 et 29 sont équivalents. La seule différence entre les deux
instructions aux lignes 25 et 29 est que l'opérateur d'affectation arithmétique, *=, est utilisé à la ligne 29.
6
Obtenir des négations de valeurs numériques
Si vous souhaitez modifier le signe d'un nombre, vous pouvez placer l'opérateur moins () juste avant
le nombre. Par exemple, étant donné un entier de 7, vous pouvez obtenir sa valeur négative en changeant
le signe de l'entier comme ceci : 7. Ici, est l'opérateur moins.
Le symbole utilisé de cette manière est appelé l' opérateur moins unaire. En effet, l'opérateur ne prend
qu'un seul opérande : l'expression immédiatement à sa droite. Le type de données de l'opérande peut être
n'importe quel entier ou nombre à virgule flottante.
Machine Translated by Google
96 Heure 6
Vous pouvez également appliquer l'opérateur moins unaire à un nombre entier ou à une variable à virgule flottante.
Par exemple, étant donné x = 1,234, x est égal à 1,234. Ou, étant donné x = 1,234, x est égal à 1,234
puisque la négation d'une valeur négative donne un nombre positif.
z = x y ;
est en fait la même que cette déclaration:
z = x (y);
ou celuici :
z=x+y;
Ici, dans les deux déclarations, le premier symbole est utilisé comme opérateur de
soustraction, tandis que le second symbole est l'opérateur moins unaire.
Incrémenter ou décrémenter de un
Les opérateurs d'incrémentation et de décrémentation sont très pratiques à utiliser lorsque vous souhaitez ajouter
ou soustraire 1 à une variable. Le symbole de l'opérateur d'incrémentation est ++. L'opérateur de décrémentation
est .
Par exemple, vous pouvez réécrire la déclaration x = x + 1 ; comme ++x;, ou vous pouvez remplacer x = x 1;
avec x;.
En fait, il existe deux versions des opérateurs d'incrémentation et de décrémentation. Dans le ++x ; , où ++
apparaît avant son opérande, l'opérateur d'incrémentation est appelé opérateur de préincrémentation. Cela fait
référence à l'ordre dans lequel les choses se produisent : l'opérateur ajoute d'abord 1 à x, puis donne la nouvelle
valeur de x. De même, dans l'instruction x;, l' opérateur de prédécrémentation soustrait d'abord 1 de x , puis
donne la nouvelle valeur de x.
Si vous avez une expression comme x++, où ++ apparaît après son opérande, vous utilisez l' opérateur de post
incrémentation. De même, dans x, l'opérateur de décrémentation est appelé opérateur de postdécrémentation.
Par exemple, dans l'instruction y = x++;, y reçoit d'abord la valeur d'origine de x , puis x est augmenté de 1.
int w, x, y, z, résultat ;
7:
8: w = x = y = z = 1 ; /* initialiser x et y */ printf("Étant donné w = %d, x
9: = %d, y = %d, et z = %d,\n", w, x, y, z);
10 :
11 : résultat = ++w ;
12 : printf("++w est évalué à %d et w est maintenant %d\n", résultat, w); résultat = x++ ;
13 : printf("x++ est évalué à %d et x est maintenant %d\n", résultat, x); résultat = y ; printf("
14 : y est évalué à %d et y est maintenant %d\n", résultat, y); résultat = z ; printf("z est
15 : évalué à %d et z est maintenant %d\n", résultat, z); renvoie 0 ;
16 :
17 :
18 :
19 :
20 : }
Dans la fonction main() , la ligne 8 du Listing 6.2 affecte 1 à chacune des variables entières, w, x,
UNE ANALYSE
y et z. L' appel printf() à la ligne 9 affiche les valeurs contenues par les quatre variables entières.
98 Heure 6
À la ligne 17, cependant, l'opérateur de postdécrémentation n'a aucun effet sur l'affectation car la valeur
d'origine de z est donnée à la variable entière résultat avant que z ne soit diminué de 1.
La postdécrémentation agit comme si la ligne 17 était simplement résultat = z, z étant ensuite décrémenté
de 1 après l'exécution de l'instruction. La ligne 18 imprime donc le résultat 1, qui est bien sûr la valeur
originale de z, ainsi que 0, la valeur de z après la postdécrémentation.
Supérieur ou inférieur à ?
Il existe six types de relations entre deux expressions : égal à, différent de, supérieur à, inférieur à, supérieur
ou égal à et inférieur ou égal à. Ainsi, le langage C fournit ces six opérateurs relationnels :
Opérateur La description
== Égal à
!= Pas égal à
Tous les opérateurs relationnels ont une priorité inférieure aux opérateurs arithmétiques.
Par conséquent, toutes les opérations arithmétiques de part et d'autre d'un opérateur relationnel sont
effectuées avant toute comparaison. Vous devez utiliser des parenthèses pour délimiter les opérations des
opérateurs qui doivent être effectuées en premier.
Parmi les six opérateurs relationnels, les opérateurs >, <, >= et <= ont une priorité plus élevée que les
opérateurs == et != .
(x * y) < (z + 3)
Un autre point important est que toutes les expressions relationnelles produisent un résultat de 0 ou 1.
En d'autres termes, une expression relationnelle est évaluée à 1 si la relation spécifiée est vérifiée.
Sinon, 0 est renvoyé.
L' opérateur * a une priorité plus élevée que les opérateurs + et . Par conséquent, y sera
X * évalué en premier et son résultat devient l'opérande de droite de l' opérateur + . Le
résultat est ensuite donné à l' opérateur comme opérande de gauche.
Si vous souhaitez remplacer la priorité des opérateurs par défaut, vous pouvez
utiliser des parenthèses pour regrouper les opérandes dans une expression. Si, par
exemple, vous vouliez réellement multiplier z + x par y 3, vous pourriez réécrire
l'expression cidessus sous la forme (z + x) * (y 3)
De plus, vous pouvez toujours utiliser les parenthèses lorsque vous n'êtes pas tout à fait
sûr des effets de la priorité des opérateurs ou que vous souhaitez simplement faciliter la
lecture de votre code.
int x, y ;
double z ;
x=7;y
= 25 ; z = 6
24,46 ;
printf("Étant donné x = %d, y = %d, et z = %.2f,\n", x, y, z); printf(“x >= y produit :
%d\n”, x >= y); printf("x == y produit : %d\n", x == y); printf("x < z produit : %d\n", x <
z); printf("y > z produit : %d\n", y > z); printf(“x != y 18 produit : %d\n”, x != y 18);
printf(“x + y != z produit : %d\n”, x + y != z); renvoie 0 ;
Machine Translated by Google
100 Heure 6
Une fois l'exécutable 06L03.exe exécuté, la sortie suivante s'affiche sur l'écran de mon
ordinateur :
Étant donné x = 7, y = 25 et z = 24,46, x >= y produit :
SORTIR 0 x == y produit : 0 x < z produit : 1 y > z produit : 1
x != y 18 produit : 0 x + y != z donne : 1
UNE ANALYSE Il y a deux variables entières, x et y, et une variable à virgule flottante z, déclarées
respectivement aux lignes 6 et 7.
Les lignes 9 à 11 initialisent les trois variables. La ligne 12 imprime les valeurs affectées aux
variables.
Comme la valeur de x est 7 et la valeur de y est 25, y est supérieur à x. Par conséquent, la ligne 13
imprime 0, qui est le résultat obtenu par l'expression relationnelle x >= y.
Les lignes 15 et 16 impriment le résultat de 1, qui est obtenu par les évaluations de x < z et y
> z.
Soyez prudent lorsque vous comparez deux valeurs pour l'égalité. En raison de la
troncature ou de l'arrondi, certaines expressions relationnelles, qui sont algébriquement
vraies, peuvent donner 0 au lieu de 1. Par exemple, regardez l'expression relationnelle suivante :
1 / 2 + 1 / 2 == 1
Ceci est algébriquement vrai et on s'attendrait à ce qu'il soit évalué à 1.
L'expression, cependant, donne 0, ce qui signifie que la relation d'égal à ne tient pas.
En effet, la troncature de la division entière, c'estàdire 1/2 , produit un entier : 0, et
non 0,5.
Un autre exemple est 1.0 / 3.0, qui produit 0.33333... C'est un nombre avec un nombre
infini de décimales. Mais l'ordinateur ne peut contenir qu'un nombre limité de décimales.
Par conséquent, l'expression
(type de données) x
Ici datatype spécifie le nouveau type de données que vous voulez. x est une variable (ou constante ou
expression) d'un type de données différent. Vous devez inclure les parenthèses ( et ) autour du nouveau
type de données pour créer un opérateur de conversion.
int x, y ;
7:
8: x=7;y
9: =5;
10 : printf("Étant donné x = %d, y = %d\n", x, y); printf("x / y
11 : produit : %d\n", x / y); printf("(float)x / y produit : %f\n",
12 : (float)x / y); renvoie 0 ;
13 :
14 : }
6
La sortie suivante est obtenue en exécutant l'exécutable 06L04.exe sur mon ordinateur :
Étant donné x = 7, y = 5 x /
SORTIR
y produit : 1 (float)x / y
produit : 1,400000
Dans le Listing 6.4, il y a deux variables entières, x et y, déclarées à la ligne 6, et initialisées aux
UNE ANALYSE
lignes 8 et 9, respectivement. La ligne 10 affiche alors les valeurs contenues par les variables
entières x et y.
Machine Translated by Google
102 Heure 6
L'instruction de la ligne 11 imprime la division entière de x/y. Comme la partie fractionnaire est tronquée, le
résultat de la division entière est 1.
Cependant, à la ligne 12, l'opérateur cast (float) convertit la valeur de x en une valeur à virgule flottante. Par
conséquent, l' expression (float)x/y devient une division à virgule flottante qui renvoie un nombre à virgule
flottante. C'est pourquoi vous voyez le nombre à virgule flottante 1,400000 affiché à l'écran après l'exécution
de l'instruction de la ligne 12.
Résumé
Dans cette leçon, vous avez découvert les opérateurs importants suivants :
• L'opérateur d'affectation =, qui a deux opérandes (un de chaque côté). La valeur de l'opérande de
droite est affectée à l'opérande de gauche. L'opérande sur le côté gauche doit être une forme de
variable qui peut accepter la nouvelle valeur.
• Les opérateurs d'affectation arithmétique +=, =, *=, /= et %=, qui sont combinés
des opérateurs arithmétiques avec l'opérateur d'affectation.
• L'opérateur moins unaire (), qui correspond à la négation d'une valeur numérique. • Les deux
versions de l'opérateur d'incrémentation, ++. Vous savez que dans ++x, l' opérateur ++ est appelé
opérateur de préincrémentation ; et dans x++, ++ est l'opérateur de postincrémentation.
• Les deux versions de l'opérateur de décrémentation, . Vous avez appris que, par exemple, dans x,
l' opérateur est l'opérateur de prédécrémentation, et dans x, est appelé l'opérateur de post
décrémentation.
• Les six opérateurs relationnels en C : == (égal à), != (différent de), > (supérieur à), < (inférieur à), >=
(supérieur ou égal à) et <= (moins supérieur ou égal à). • Comment changer le type de données
Questions et réponses
Q L'opérateur moins unaire () est il le même que l'opérateur de soustraction () ?
R Non, ce ne sont pas les mêmes, bien que les deux opérateurs partagent le même symbole. La
signification du symbole est déterminée par le contexte dans lequel il apparaît. L'opérateur moins
unaire est utilisé pour changer le signe d'une valeur numérique. En d'autres termes, l'opérateur
moins unaire donne la négation de la valeur. L'opérateur de soustraction est un opérateur arithmétique
qui effectue une soustraction entre ses deux opérandes.
A Un opérateur arithmétique a une priorité plus élevée qu'un opérateur relationnel. Pour y + z > x
exemple, dans l'expression x du * + y, la priorité des opérateurs de
plus haut au plus bas va de * à + et enfin >. L'expression entière est donc interprétée comme ((x *
y) + z) > (x + y).
A Une expression relationnelle est évaluée à 0 ou 1. Si la relation indiquée par un opérateur relationnel
dans une expression est vraie, l'expression est évaluée à 1 ; sinon, l'expression est évaluée à 0.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe C, « Réponses
aux questions et exercices du quiz ».
Questionnaire
Des exercices
104 Heure 6
est exécuté?
3. Écrivez un programme qui initialise la variable entière x avec 1 et génère les résultats avec les
deux instructions suivantes : printf(“x++ produit : %d\n”, x++); printf("Maintenant x contient :
%d\n", x);
4. Réécrivez le programme que vous avez écrit dans l'exercice 3. Cette fois, incluez les deux
déclarations :
printf("x = x++ produit : %d\n", x = x++);
printf("Maintenant x contient : %d\n", x);
principale()
int x, y ;
x=y=0;
printf("Le résultat de la comparaison est : %d\n", x = y); renvoie
0;
}
Machine Translated by Google
HEURE 7
Travailler avec des boucles
Le ciel et la terre:
Sutra inouï chant répété…
—Proverbe zen
Dans les leçons précédentes, vous avez appris les bases du programme C, plusieurs
fonctions C importantes, les E/S standard et quelques opérateurs utiles. Dans cette
leçon, vous apprendrez une fonctionnalité très importante du langage C : le bouclage.
La boucle, également appelée itération, est utilisée en programmation pour exécuter le même
ensemble d'instructions encore et encore jusqu'à ce que certaines conditions spécifiées soient remplies.
106 Heure 7
La boucle while
Le but du motclé while est d'exécuter une instruction de manière répétée tant qu'une condition
donnée est vraie. Lorsque la condition de la boucle while n'est plus logiquement vraie, la boucle se
termine et l'exécution du programme reprend à l'instruction suivante suivant la boucle.
instruction while
(expression);
Ici , expression est la condition de l' instruction while . Cette expression est évaluée en premier. Si
l'expression est évaluée à une valeur différente de zéro , alors l' instruction est exécutée. Après cela,
l'expression est évaluée une fois de plus. L'instruction est ensuite exécutée une fois de plus si
l'expression est toujours évaluée à une valeur différente de zéro. Ce processus est répété encore et
encore jusqu'à ce que l' expression soit évaluée à zéro ou fausse logique.
L'idée est que le code à l'intérieur de la boucle (instruction; cidessus) finira par rendre l'
expression logiquement fausse la prochaine fois qu'elle sera évaluée, mettant ainsi fin à la boucle.
Bien sûr, vous souhaitez souvent utiliser un motclé while pour contrôler la boucle sur plusieurs
instructions. Lorsque c'est le cas, utilisez un bloc d'instructions entouré d'accolades { et }. Chaque fois
que l' expression while est évaluée, le bloc d'instructions entier sera exécuté si l'expression est évaluée
comme vraie.
Maintenant, regardons un exemple d'utilisation de l' instruction while . Le programme du listing 7.1
utilise une boucle while pour lire continuellement, puis afficher, l'entrée de caractères tant que l'entrée
de caractères n'est pas égale à 'x'.
entier c ;
7:
8: c = ' ';
9: printf("Entrez un caractère :\n(entrez x pour quitter)\n"); tandis
10 : que (c != 'x') { c = getc(stdin); putchar(c);
11 :
12 :
13 :
14 : } printf("\nSortie de la boucle while. Au revoir !\n");
15 : renvoie 0 ;
16 : }
Machine Translated by Google
Ce qui suit est une copie de la sortie de l'écran de mon ordinateur. (Notez que les caractères que j'ai
saisis sont en gras.)
je
X
X
7
Hors de la boucle while. Au revoir!
Comme vous pouvez le voir dans la sortie, le programme réimprime chaque caractère
UNE ANALYSE
saisi, puis s'arrête après x.
La ligne 8 met la variable c à la valeur ' ' (un espace). C'est ce qu'on appelle l' initialisation de
la variable, et nous avons juste besoin de l'initialiser à autre chose que 'x'.
La ligne 10 est l' instruction while . La condition entre parenthèses, c != 'x', signifie que la boucle
continuera à s'exécuter encore et encore jusqu'à ce que c soit réellement égal à 'x'. Comme nous
' , la
venions d'initialiser c pour être égal à ' Après larelation c != xfermante
parenthèse est bien se
sûrtrouve
vraie. une accolade ouvrante,
la boucle s'exécutera jusqu'à ce qu'une accolade fermante soit rencontrée.
La boucle dowhile
Dans l' instruction while que nous avons vue, l'expression conditionnelle est définie tout en haut de la
boucle. Cependant, dans cette section, vous allez voir une autre instruction utilisée pour la boucle,
dowhile, qui place l'expression au bas de la boucle. De cette manière, les instructions de la boucle
sont garanties d'être exécutées au moins une fois avant que l'expression ne soit testée. Notez que les
instructions d'une boucle while ne sont pas du tout exécutées si l'expression conditionnelle est évaluée
à zéro la première fois.
Machine Translated by Google
108 Heure 7
faire
{ instruction1 ;
instruction2 ;
.
.
.
} tandis que (expression);
Ici, les instructions à l'intérieur du bloc d'instructions sont exécutées une fois, puis l' expression est
évaluée afin de déterminer si la boucle doit continuer. Si l'expression donne une valeur différente de
zéro, la boucle do while continue ; sinon, la boucle s'arrête et l'exécution passe à l'instruction suivante
suivant la boucle.
Notez que l' instruction dowhile se termine par un pointvirgule, ce qui constitue une distinction
importante par rapport aux instructions if et while .
Le programme du Listing 7.2 affiche les caractères A à G en utilisant une boucle do while pour répéter
l'impression et l'ajout.
int je ;
je = 65 ;
do
{ printf("La valeur numérique de %c est %d.\n", i, i); je++ ; } tandis que (i<72);
8 : 9 : 10 : 11 : renvoie 0 ;
12 :
13 :
14 : }
Après avoir exécuté l'exécutable 07L02.exe du Listing 7.6, j'ai les caractères A à G, ainsi que leurs
valeurs numériques, affichés à l'écran comme suit :
La valeur numérique de A est 65.
SORTIR
La valeur numérique de B est 66.
La valeur numérique de C est 67.
La valeur numérique de D est 68.
La valeur numérique de E est 69.
La valeur numérique de F est 70.
La valeur numérique de G est 71.
Machine Translated by Google
UNE ANALYSE
L'instruction de la ligne 8 du Listing 7.6 initialise la variable entière i avec 65.
La variable entière a été déclarée à la ligne 6.
Les lignes 9 à 12 contiennent la boucle do while. L'expression i<72 se trouve au bas de la boucle de
la ligne 12. Lorsque la boucle démarre pour la première fois, les deux instructions des lignes 10 et 11
sont exécutées avant que l'expression ne soit évaluée. Comme la variable entière i contient la valeur
initiale de 65, la fonction printf() de la ligne 10 affiche la valeur numérique ainsi que le caractère A
correspondant à l'écran.
7
Après que la variable entière i est augmentée de 1 à la ligne 11, le contrôle du programme atteint le
bas de la boucle do while. Ensuite, l'expression i<72 est évaluée. Si la relation dans l'expression est
toujours valable, le contrôle du programme saute au sommet de la boucle do while, puis le processus
est répété. Lorsque l'expression est évaluée à 0 après que i est augmenté à 72 (i est alors égal à 72
et n'est donc pas inférieur à 72), la boucle do while se termine immédiatement.
.
.
.
}
Vous voyez dans cet exemple que l' instruction for utilise trois expressions (expression1, expression2
et expression3) séparées par des pointsvirgules.
Une boucle for peut contrôler une seule instruction comme dans le premier exemple, ou plusieurs
instructions, telles que instruction1 et instruction2, placées entre accolades ({ et }).
La première fois que l' instruction for est exécutée, elle évalue d'abord expression1, qui est généralement
utilisée pour initialiser une ou plusieurs variables.
110 Heure 7
pour déclaration. Si expression2 donne une valeur différente de zéro (vrai logique), les instructions
entre accolades sont exécutées. Sinon, la boucle est arrêtée et l'exécution reprend à l'instruction
suivante après la boucle.
La troisième expression de l' instruction for , expression3, n'est pas évaluée lorsque l' instruction
for est rencontrée pour la première fois. Cependant, expression3 est évaluée après chaque boucle et
avant que l'instruction ne revienne tester à nouveau expression2 .
Dans l'Heure 5, « Gestion des entrées et sorties standard », vous avez vu un exemple (Liste 5.5) qui
convertit les nombres décimaux de 0 à 15 en nombres hexadécimaux. À l'époque, les conversions
devaient être écrites dans des déclarations séparées. Maintenant, avec l' instruction for , vous pouvez
réécrire le programme du Listing 5.5 de manière très efficace. Le Listing 7.3 montre la version réécrite
du programme.
int je ;
Après avoir créé le fichier exécutable 07L03.exe, j'obtiens la sortie suivante en exécutant
07L03.exe. (La sortie est en fait la même que celle de 05L05.exe à l'heure 5.)
1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
UN 10
B un B 11
Machine Translated by Google
C 12
ré CD 13
ET 14
F par f 15
UNE ANALYSE Maintenant, regardons le code de l'extrait 7.3. Comme vous le savez, la ligne 2 inclut le
fichier d'entête stdio.h pour la fonction printf() utilisée plus tard dans le programme.
Dans le corps de la fonction main() , l'instruction de la ligne 6 déclare une variable entière, i. La ligne 7
8 affiche le titre de la sortie à l'écran.
Les lignes 9 à 11 contiennent l' instruction for . Notez que la première expression de l' instruction for
est i = 0, qui est une expression d'affectation qui initialise la variable entière i à 0.
La deuxième expression de l' instruction for est i < 16, qui est une expression relationnelle.
Cette expression a une valeur différente de zéro (vrai) tant que la relation indiquée par l'opérateur
inférieur à (<) est vérifiée. Comme mentionné précédemment, la deuxième expression est évaluée
par l' instruction for à chaque fois après une boucle réussie. Si la valeur de i est inférieure à 16, ce
qui signifie que l'expression relationnelle reste vraie, l' instruction for démarrera une autre boucle.
Sinon, il s'arrêtera de boucler et sortira.
La troisième expression de l' instruction for est i++. Lorsque cette expression est évaluée, la variable
entière i est augmentée de 1. Ceci est fait après l'exécution de chaque instruction à l'intérieur du corps
de l' instruction for . Ici, peu importe que l'opérateur de postincrémentation (i++) ou l'opérateur de pré
incrémentation (++i) soit utilisé dans la troisième expression.
En d'autres termes, lorsque la boucle for est rencontrée pour la première fois, i est défini sur 0,
l'expression i<16 est évaluée et trouvée vraie, et par conséquent les instructions dans le corps de la
boucle for sont exécutées. Après l'exécution de la boucle for , la troisième expression i++ est exécutée
en incrémentant i à 1, et i<16 est à nouveau évalué et trouvé vrai, ainsi le corps de la boucle est exécuté
à nouveau. Le bouclage dure jusqu'à ce que l'expression conditionnelle i<16 ne soit plus vraie.
Il n'y a qu'une seule instruction dans le corps de l'instruction for , comme vous pouvez le voir à la ligne
10. L'instruction contient la fonction printf() , qui est utilisée pour afficher les nombres hexadécimaux
(majuscules et minuscules) convertis à partir des valeurs décimales à l'aide de la spécificateurs de
format, %X et %x.
La valeur décimale est fournie par la variable entière i. Comme expliqué précédemment, i contient la
valeur initiale de 0 juste avant et pendant le premier bouclage. Après chaque boucle, i est augmenté
de 1 à cause de la troisième expression, i++, dans l' instruction for . La dernière valeur fournie par i
est 15. Lorsque i atteint 16, la relation indiquée par la deuxième expression,
Machine Translated by Google
112 Heure 7
i<16, n'est plus vrai. Par conséquent, la boucle est arrêtée et l'exécution de l' instruction for est
terminée.
Ensuite, l'instruction de la ligne 12 renvoie 0 pour indiquer une fin normale du programme, et
enfin, la fonction main() se termine et renvoie le contrôle au système d'exploitation.
Comme vous le voyez, avec l' instruction for , vous pouvez écrire un programme très concis. En fait,
le programme du Listing 7.3 est plus court de plus de 10 lignes que celui du Listing 5.5, bien que les deux
programmes finissent par faire exactement la même chose.
En fait, vous pouvez rendre le programme du Listing 7.3 encore plus court en supprimant les accolades
({ et }) puisqu'il n'y a qu'une seule instruction à l'intérieur du bloc d'instructions.
La déclaration nulle
Comme vous pouvez le remarquer, l' instruction for ne se termine pas par un pointvirgule. L' instruction
for contient soit un bloc d'instructions qui se termine par l'accolade fermante (}), soit une seule instruction
qui se termine par un pointvirgule. L' instruction for suivante contient un seul
déclaration:
Notez que les accolades ({ et }) sont supprimées car l' instruction for ne contient qu'une seule
déclaration.
Dans le langage C, il existe une instruction spéciale appelée instruction nulle. Une instruction nulle ne
contient rien d'autre qu'un pointvirgule. En d'autres termes, une instruction nulle est une instruction sans
expression.
Par conséquent, lorsque vous examinez l'instruction for (i=0; i<8; i++);, vous pouvez voir qu'il s'agit en fait
d'une instruction for avec une instruction nulle. En d'autres termes, vous pouvez le réécrire comme
Étant donné que l'instruction null n'a pas d'expression, l' instruction for ne fait en réalité rien d'autre
qu'une boucle. Vous verrez quelques exemples utilisant l'instruction null avec l' instruction for plus loin
dans le livre.
Machine Translated by Google
Étant donné que l'instruction null est parfaitement légale en C, vous devez faire attention
à placer des pointsvirgules dans vos instructions for. Par exemple, supposons que vous
ayez l'intention d'écrire une boucle for comme ceci : for (i=0; i<8; i++) sum += i;
votre compilateur C l'acceptera toujours, mais les résultats des deux instructions for
seront assez différents. (Voir l'exercice 1 dans cette leçon pour un exemple.)
N'oubliez pas que la boucle do while est la seule instruction en boucle qui utilise un pointvirgule
immédiatement après dans sa syntaxe. Les instructions while et for sont immédiatement suivies
d'une boucle, qui peut être une seule instruction suivie d'un pointvirgule, un bloc d'instructions sans
pointvirgule ou juste un pointvirgule (instruction nulle) seul.
Ici, dans la première expression, les deux variables entières i et j sont initialisées, respectivement, avec 0
et 10 lorsque l' instruction for est rencontrée pour la première fois. Ensuite, dans le deuxième champ, les
expressions relationnelles i!=j sont évaluées et testées. S'il est évalué à zéro (faux), la boucle est terminée.
Après chaque itération de la boucle, i est augmenté de 1 et j est réduit de 1 dans la troisième expression.
Ensuite, l'expression i!=j est évaluée pour déterminer s'il faut ou non exécuter à nouveau la boucle.
114 Heure 7
int je, j ;
7:
8: for (i=0, j=8; i<8; i++, j) printf(“%d +
9: %d = %d\n”, i, j, i+j); renvoie 0 ;
10 :
11 : }
J'obtiens la sortie suivante affichée à l'écran après avoir exécuté le fichier exécutable,
07L04.exe :
0+8=81+7=
SORTIR 82+6=83+
5=84+4=85
+3=86+2=8
7+1=8
Dans le Listing 7.4, la ligne 6 déclare deux variables entières, i et j, qui sont utilisées dans une
UNE ANALYSE
boucle for .
A la ligne 8, i est initialisé avec 0 et j est mis à 8 dans la première expression de l' instruction for . La
deuxième expression contient une condition, i < 8, qui indique à l'ordinateur de continuer à boucler
tant que la valeur de i est inférieure à 8.
Chaque fois, après l'exécution de l'instruction contrôlée par for à la ligne 9, la troisième expression
est évaluée, ce qui fait que i est augmenté (incrémenté) de 1 tandis que j est réduit (décrémenté) de
1. Parce qu'il n'y a qu'une seule instruction à l'intérieur de for boucle, aucune accolade ({ et }) n'est
utilisée pour former un bloc d'instructions.
L'instruction de la ligne 9 affiche l'addition de i et j à l'écran pendant la boucle, qui produit huit résultats
pendant la boucle en ajoutant les valeurs des deux variables, i et j.
L'ajout de plusieurs expressions dans l' instruction for est un moyen très pratique de manipuler plus
d'une variable dans une boucle. Pour en savoir plus sur l'utilisation de plusieurs expressions dans une
boucle for , regardez l'exemple du Listing 7.5.
Machine Translated by Google
LISTE 7.5 Un autre exemple d'utilisation de plusieurs expressions dans l' instruction for
TAPER
int je, j ;
7:
8:
7
for (i=0, j=1; i<8; i++, j++) printf(“%d
9: %d = %d\n”, j, i, j return 0; je);
10 :
11 : }
La sortie suivante s'affiche à l'écran après l'exécution de l'exécutable 07L05.exe sur ma machine :
10=121=1
SORTIR 3 2 = 114 43==
1 5 66 =51=81 77
=1
Dans le programme du Listing 7.5, deux variables entières, i et j, sont déclarées à la ligne 6.
UNE ANALYSE
Notez qu'à la ligne 8, il y a deux expressions d'affectation, i=0 et j=1, dans la première expression de l'
instruction for . Ces deux expressions d'affectation initialisent respectivement les variables entières i et
j.
Il y a une expression relationnelle, i<8, dans le deuxième champ, qui est la condition qui doit être
remplie avant que le bouclage puisse être effectué. Parce que i commence à 0 et est incrémenté de
1 après chaque boucle, il y a un total de 8 boucles qui seront exécutées par le for
déclaration.
La troisième expression contient deux expressions, i++ et j++, qui augmentent les deux variables
entières de 1 à chaque fois après l'exécution de l'instruction de la ligne 9.
La fonction printf() de la ligne 9 affiche la soustraction des deux variables entières, j et i, dans la
boucle for . Comme il n'y a qu'une seule instruction dans le bloc d'instructions, les accolades ({ et })
ne sont pas nécessaires.
Machine Translated by Google
116 Heure 7
int je, j ;
7:
8: pour (je=1; je<=3; je++) { /* boucle externe */
9: printf("Le début de l'itération %d de la boucle externe.\n", i); for (j=1; j<=4; j+
10 : +) /* boucle interne */ printf(“
11 : Itération %d de la boucle interne.\n”, j); printf("La
12 : fin de l'itération %d de la boucle externe.\n", i);
13 :
14 : } renvoie 0 ;
15 : }
UNE ANALYSE
Dans le Listing 7.6, deux boucles for sont imbriquées. La boucle for externe commence à la ligne
8 et se termine à la ligne 13, tandis que la boucle for interne commence à la ligne 10 et se termine à
la ligne 11.
La boucle interne est une seule instruction qui imprime le numéro d'itération en fonction de la valeur numérique
de la variable entière j. Comme vous le voyez à la ligne 10, j est initialisé avec 1, et est augmenté de 1 après
chaque bouclage (c'estàdire, itération). L'exécution de la boucle interne s'arrête lorsque la valeur de j est
supérieure à 4.
7
Outre la boucle interne, la boucle externe contient deux instructions aux lignes 9 et 12, respectivement.
La fonction printf() à la ligne 9 affiche un message indiquant le début d'une itération à partir de la boucle
externe. Un message de fin est envoyé à la ligne 12 pour montrer la fin de l'itération à partir de la boucle externe.
À partir de la sortie, vous pouvez voir que la boucle interne est terminée avant que la boucle externe ne
commence une autre itération. Lorsque la boucle externe commence une autre itération, la boucle interne est
rencontrée et exécutée à nouveau. La sortie du programme du Listing 7.6 montre clairement les ordres
d'exécution des boucles internes et externes.
Ne confondez pas les deux opérateurs relationnels (< et <=) et abusezen dans
les expressions de boucles.
Par exemple, ce qui suit for
(j=1; j<10; j++){ /* bloc
d'instructions */
}
signifie que si j est inférieur à 10, continuez à boucler. Ainsi, le nombre total
d'itérations est de 9. Cependant, dans l'exemple suivant, pour (j=1 ; j<=10 ; j++){
/* bloc d'instructions */
}
le nombre total d'itérations est de 10 car l'expression relationnelle j<=10 est évaluée
dans ce cas. Notez que l'expression est évaluée à 1 (vrai logique) tant que j est
inférieur ou égal à 10.
Par conséquent, vous voyez que la différence entre les opérateurs < et <= fait
que la boucle dans le premier exemple est une itération plus courte que la boucle
dans le deuxième exemple.
Machine Translated by Google
118 Heure 7
Résumé
Dans cette leçon, vous avez appris les concepts et énoncés importants suivants :
• La boucle peut être utilisée pour exécuter le même ensemble d'instructions encore et encore jusqu'à ce que
conditions spécifiées sont remplies.
trois instructions, while, et dowhile, et for, qui sont utilisées pour la boucle
en C.
• L' instruction while contient une expression, qui est l'expression conditionnelle qui contrôle la boucle.
• Il y a trois expressions dans l' instruction for . La deuxième expression est l'expression conditionnelle.
• Plusieurs expressions, combinées via des virgules, peuvent être utilisées comme une seule expression dans le
pour déclaration.
• Dans une boucle imbriquée, la boucle interne se termine avant que la boucle externe ne reprenne son itération dans
boucles imbriquées.
Dans la leçon suivante, vous découvrirez d'autres opérateurs utilisés dans le langage C.
Questions et réponses
A La principale différence est que dans l' instruction while , l'expression conditionnelle est évaluée en
haut de la boucle, tandis que dans l' instruction dowhile , l'expression conditionnelle est évaluée en
bas de la boucle. Par conséquent, les instructions contrôlées par l' instruction dowhile sont garanties
d'être exécutées au moins une fois alors que la boucle d'une instruction while peut ne jamais être
exécutée du tout.
A Il y a trois expressions dans l' instruction for . Le premier champ contient une initiale
izer qui est évalué en premier et une seule fois avant l'itération. La deuxième expression est l'expression
conditionnelle qui doit être évaluée à une valeur différente de zéro (vrai logique) avant que les
instructions contrôlées par l' instruction for ne soient exécutées. Si le conditionnel
Machine Translated by Google
expression prend une valeur différente de zéro (vrai), ce qui signifie que la condition spécifiée est
remplie, une itération de la boucle for est effectuée. Après chaque itération, la troisième expression
est évaluée, puis le deuxième champ est à nouveau évalué. Ce processus avec les deuxième et
troisième expressions est répété jusqu'à ce que l'expression conditionnelle soit évaluée à zéro
(faux logique).
R Par définition, l' instruction while ne se termine pas par un pointvirgule. Cependant, il est légal
en C de mettre un pointvirgule juste après l' instruction while comme ceci : while(expression);,
7
ce qui signifie qu'il y a une instruction nulle contrôlée par l' instruction while . N'oubliez pas que
le résultat sera très différent de ce à quoi vous vous attendiez si vous mettez accidentellement
un pointvirgule à la fin de l' instruction while .
Q Si deux boucles sont imbriquées, laquelle doit finir en premier, la boucle intérieure ou
la boucle externe ?
A L'intérieur doit finir en premier. Ensuite, la boucle externe continuera jusqu'à la fin, puis
commencera une autre itération si sa condition spécifiée est toujours remplie.
Atelier
Pour vous aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons
à essayer de répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de
passer à la leçon suivante. Les réponses et les conseils aux questions et aux exercices sont donnés à
l'annexe D, « Réponses aux quiz et aux exercices ».
Questionnaire
120 Heure 7
Des exercices
2. Écrivez un programme contenant les deux morceaux de code présentés dans l'exercice 1, puis
exécutez le programme. Qu'allezvous voir à l'écran ?
3. Réécrivez le programme du Listing 7.1. Cette fois, vous voulez que l' instruction while continue de
tourner en boucle jusqu'à ce que l'utilisateur entre le caractère K.
4. Réécrivez le programme présenté dans le Listing 7.2 en remplaçant la boucle do while par un
pour la boucle.
5. Réécrivez le programme du Listing 7.6. Cette fois, utilisez une boucle while comme boucle externe et
une boucle do while comme boucle interne.
Machine Translated by Google
HEURE 8
Utilisation du conditionnel
Les opérateurs
La civilisation progresse en augmentant le nombre d'opérations importantes que nous
pouvons effectuer sans y penser.
—AN Whitehead
Au cours de l'heure 6, "Manipuler des données", vous avez découvert certains opérateurs
importants en C, tels que les opérateurs d'affectation arithmétique, l'opérateur moins unaire,
les opérateurs d'incrémentation et de décrémentation et les opérateurs relationnels. Dans
cette leçon, vous apprendrez plus d'opérateurs qui sont très importants dans la
programmation C, y compris
• L'opérateur conditionnel
Machine Translated by Google
122 Heure 8
Alors, comment connaître la taille d'un type de données sur votre machine ? La réponse est que vous pouvez
mesurer la taille du type de données en utilisant l' opérateur sizeof fourni par C.
taillede (expression)
Ici , expression est le type de données ou la variable dont la taille est mesurée par l' opérateur sizeof . L'
opérateur sizeof évalue la taille, en octets, de son opérande. L'opérande de l' opérateur sizeof peut être un mot
clé du langage C désignant un type de données (comme int, char ou float), ou il peut s'agir d'une expression
faisant référence à un type de données dont la taille peut être déterminée (comme une constante ou le nom
d'une variable).
Les parenthèses sont facultatives dans la forme générale de l'opérateur. Si l'expression n'est pas un motclé C
pour un type de données, les parenthèses peuvent être ignorées. Par exemple, la déclaration suivante :
taille = taillede(entier);
Place la taille, en octets, du type de données int dans une variable nommée size. Le programme du Listing 8.1
trouve les tailles des types de données char, int, float et double sur ma machine.
Une fois ce programme compilé et lié, un fichier exécutable, 08L01.exe, est créé. Voici la sortie
imprimée à l'écran après l'exécution de l'exécutable sur ma machine :
La taille de dbl_num est : 8byte[ic:analysis]La ligne 2 du Listing 8.1 inclut le fichier d'entête stdio.h
pour la fonction printf() utilisée dans les instructions à l'intérieur du corps de la fonction main() . Les
lignes 6 à 9 déclarent respectivement une variable char (ch), une variable int (int_num), une variable
float (flt_num) et une variable double (dbl_num) . De plus, ces quatre variables sont initialisées. Notez
qu'à la ligne 8, la valeur initiale de flt_num est suffixée par f pour spécifier float. (Comme vous l'avez
appris à l'heure 4, vous pouvez utiliser f ou F pour spécifier le type flottant d'un nombre à virgule
flottante.)
Les lignes 11 et 12 affichent la taille du type de données char , ainsi que la variable char ch.
Notez que l' opérateur sizeof est utilisé à la fois dans la ligne 11 et la ligne 12 pour obtenir le nombre
d'octets que le type de données char ou la variable ch peut avoir. Comme la variable ch n'est pas un
motclé en C, les parenthèses sont ignorées pour l' opérateur sizeof à la ligne 12.
Les deux premières lignes de la sortie sont imprimées par les deux instructions des lignes 11 et 12,
respectivement. À partir de la sortie, vous voyez que la taille du type de données char est de 1 octet,
ce qui est identique à la taille de la variable ch. Ce n'est pas surprenant car la variable ch est déclarée
comme la variable char .
De même, les lignes 13 et 14 affichent les tailles du type de données int et de la variable int int_num
en utilisant l' opérateur sizeof . Vous voyez que la taille de chacun est de 2 octets.
De plus, en utilisant l' opérateur sizeof , les lignes 15 à 18 donnent respectivement les tailles du type de
données flottant , de la variable flottante flt_num, du type de données double et de la variable double
dbl_num . Les résultats dans la section de sortie montrent que le type de données float et la variable
flt_num ont la même taille (4 octets). Les tailles du type de données double et de la variable dbl_num
sont toutes deux de 8 octets.
Machine Translated by Google
124 Heure 8
|| L'opérateur logique OU
Les deux premiers, les opérateurs AND et OR, sont des opérateurs binaires ; c'estàdire qu'ils prennent
tous les deux deux opérandes (un à gauche et un à droite de l'opérateur). L'opérateur logique ET (&&)
est utilisé pour évaluer la vérité ou la fausseté d'une paire d'expressions. Si l'une ou l'autre des
expressions est évaluée à 0 (c'estàdire, logiquement faux), l'opérateur donne une valeur de 0.
Sinon, si et seulement si les deux expressions d'opérande donnent des valeurs non nulles, l'opérateur
logique ET donne la valeur 1 (logiquement vrai).
L'opérateur logique OR (||) donne la valeur 1 chaque fois qu'une ou les deux expressions d'opérande
ont une valeur différente de zéro (logiquement vraie). Le || L'opérateur renvoie 0 uniquement si les deux
expressions d'opérande ont la valeur 0 (faux). L'opérateur de négation logique (!) est un opérateur
unaire ; c'estàdire qu'il ne prend qu'un seul opérande (l'expression à sa droite). Si l'opérande est
évalué à une valeur différente de zéro, le ! l'opérateur donne 0 (logiquement faux) ; ce n'est que lorsque
l'expression de l'opérande est évaluée à 0 que l'opérateur donne 1 (logiquement vrai).
Les trois sections suivantes contiennent des exemples qui vous montrent comment utiliser les trois
opérateurs logiques.
où exp1 et exp2 sont deux expressions d'opérandes évaluées par l'opérateur AND.
Une bonne façon de comprendre l'opérateur AND est de consulter un tableau qui montre les valeurs
fournies par l'opérateur AND en fonction des valeurs possibles de exp1 et exp2. Voir le tableau 8.1, qui
peut être appelé la table de vérité de l'opérateur ET.
non nul 0 0
non nul 0
00 0
Machine Translated by Google
TAPER
8
LISTE 8.2 Utilisation de l'opérateur logique ET (&&)
int si;
nombre =
0 ; printf("L'opérateur ET donne : %d\n", (num%2
== 0) && (num%3 == 0)); nombre = 2 ;
8 : 9 : 10 : 11printf("L'opérateur
: ET donne : %d\n", (num%2 ==
12 : 0) && (num%3 == 0)); nombre = 3 ; printf("L'opérateur
13: ET donne : %d\n", (num%2 == 0) &&
14: (num%3 == 0)); nombre = 6 ; printf("L'opérateur ET
donne : %d\n", (num%2 == 0) && (num%3 == 0));
15 : 16 : 17 :
18h19h20h21h
renvoie 0 ;
22 : }
Une fois ce programme compilé et lié, un fichier exécutable, 08L02.exe, est créé. La sortie suivante
s'affiche après l'exécution de l'exécutable sur ma machine :
L'opérateur ET donne : 1
SORTIR
L'opérateur ET donne : 0
L'opérateur ET donne : 0
L'opérateur ET donne : 1
Dans le Listing 8.2, une variable entière, num, est déclarée à la ligne 6 et initialisée pour la
UNE ANALYSE
première fois à la ligne 8. Les lignes 9 et 10 affichent la valeur obtenue par l'opérateur logique
AND dans l'expression suivante :
Ici, vous voyez deux expressions relationnelles, num%2 == 0 et num%3 == 0. Dans l'heure 3
"Apprentissage de la structure d'un programme C", vous avez appris que l'opérateur arithmétique %
peut être utilisé pour obtenir le reste après son premier opérande est divisé par le deuxième opérande.
Par conséquent, num%2 donne le reste de num divisé par 2. L'expression relationnelle num%2
== 0 donne 1 si le reste est égal à 0, c'estàdire que la valeur de num peut être complètement
divisée par 2 . De même, si la valeur de num peut être divisée par 3, la valeur relationnelle
Machine Translated by Google
126 Heure 8
expression num%3 == 0 donne également 1 . Ensuite, selon la table de vérité de l' opérateur &&
(voir Tableau 8.1), vous savez que la combinaison de l'opérateur logique ET (&&) et des deux expressions
relationnelles donne 1 si les deux expressions relationnelles sont toutes deux non nulles ; sinon, il donne
0.
Dans notre cas, lorsque num est initialisé à 0 à la ligne 8, 0%2 et 0%3 produisent des restes de zéro,
de sorte que les deux expressions relationnelles sont évaluées à 1. Par conséquent, l'opérateur
logique ET donne 1.
Cependant, lorsque num reçoit la valeur 2 ou 3 , comme indiqué aux lignes 11 et 14, l'opérateur
logique ET de la ligne 13 ou de la ligne 16 donne 0. La raison en est que 2 ou 3 ne peuvent pas être
divisés à la fois par 2 et 3 .
La ligne 17 attribue alors à num la valeur de 6. Comme 6 est un multiple de 2 et de 3, l'opérateur logique
ET de la ligne 19 donne 1 qui est affiché par la fonction printf() aux lignes 18 et 19.
exp1 || exp2
où exp1 et exp2 sont deux expressions d'opérandes évaluées par l'opérateur OR.
non nul 0 1
0 non nul 1
0 00
3 : 4 : principal()
5:{6:7:8: 8
9 : 10 : 11 :int si;
12 : 13 : }
printf("Entrez un seul chiffre qui peut être divisé\npar 2 et 3 :\n"); pour (num = 1; (num%2 !=
0) || (num%3 != 0); )
num = getchar() – '0' ;
printf("Vous avez un tel nombre : %d\n", num); renvoie
0;
Voici la sortie affichée après l'exécution du fichier exécutable 08L03.exe sur ma machine. Les
chiffres en gras sont ceux que j'ai saisis. (La touche Entrée est enfoncée à chaque fois après la
saisie d'un des nombres.) Dans la plage de 0 à 9, 0 et 6 sont les deux seuls nombres qui peuvent
être complètement divisés par 2 et 3 :
Vous avez un tel nombre : 6 Dans le Listing 8.3, une variable entière, num, est déclarée à
UNE ANALYSE
la ligne 6. La ligne 8 du Listing 8.3 imprime deux titres demandant à l'utilisateur d'entrer un
seul chiffre.
A la ligne 9, la variable entière num est initialisée dans la première expression de l' instruction
for . La raison d'initialiser num avec 1 est que 1 est un nombre divisible
par ni 2 ni 3. De cette façon, la boucle for est garantie d'être exécutée au moins une fois.
La partie clé du programme du Listing 8.3 est l'expression logique dans l' instruction for :
(num%2 != 0) || (num%3 != 0)
La boucle for ne s'arrête que si l'utilisateur saisit un chiffre qui peut être divisé à la fois par 2 et 3. En
d'autres termes, lorsque les deux expressions relationnelles sont évaluées à 0, l'opérateur logique
OR donne 0, ce qui provoque la fin de la boucle for . boucle.
Machine Translated by Google
128 Heure 8
!expression
0 1
Examinons maintenant l'exemple présenté dans le Listing 8.4, qui montre comment utiliser l'opérateur
de négation logique (!).
TAPER
LISTE 8.4 Utilisation de l'opérateur de négation logique (!)
int si;
nombre =
7 ; printf("Num donné = 7\n");
printf(“!(num < 7) donne : %d\n”, !(num < 7)); printf(“!(num > 7)
8 : 9 : 10 : 11donne
: : %d\n”, !(num > 7)); printf(“!(num == 7) donne : %d\n”, !
12 : (num == 7)); renvoie 0 ;
13 : 14 : }
UNE ANALYSE À la ligne 8, notez qu'une variable entière num est initialisée à 7, qui est ensuite affichée par
la fonction printf() à la ligne 9.
Machine Translated by Google
À la ligne 10, l'expression relationnelle num < 7 est évaluée à 0 car la valeur de num n'est pas inférieure à 7.
Cependant, en utilisant l'opérateur de négation logique, !(num < 7) donne 1.
(Reportezvous à la table de vérité de l' opérateur ! présenté dans le tableau 8.3.)
8
De même, l'expression logique !(num > 7) donne 1 à la ligne 11.
Comme num a la valeur 7, l'expression relationnelle num == 7 donne 1 ; cependant, l'expression logique !(num == 7) à
la ligne 12 est évaluée à 0.
0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
UN 1010 dix
continue
Machine Translated by Google
130 Heure 8
Hexagone
Binaire Décimal
B 1011 11
C 1100 12
ré 1101 13
ET 1110 14
F 1111 15
Voyons comment convertir un nombre décimal en nombre binaire ou hexadécimal, ou vice versa.
Comme vous le savez, le binaire est un système de numérotation basé sur 2. Chaque chiffre d'un nombre binaire
est appelé un bit et peut être 1 ou 0. Si la position d'un bit dans un nombre binaire est n, le bit peut avoir une valeur
de 0 ou 2 à la puissance n. La position d'un bit dans un nombre binaire est comptée à partir de la droite du nombre
binaire. Le bit le plus à droite est à la position zéro.
Ainsi, étant donné un nombre binaire 1000 (sa valeur hexadécimale est 8), nous pouvons calculer sa valeur décimale
comme ceci :
3
1000 → 1 * 23 + 0 * 22 + 0 * 21 + 0 * 20 → 2 → 8 (décimal)
De même, étant donné un nombre binaire 1110, sa valeur hexadécimale est E, vous pouvez calculer sa valeur
décimale comme ceci :
3
1110 → 1 * 23 + 1 * 22 + 1 * 21 + 0 * 20 → 2 → 14 (décimal)
Si vous voulez convertir un nombre décimal, par exemple 10, en son homologue binaire, vous avez le processus
suivant :
3
10 → 2 + 21 → 1 * 23 + 0 * 22 + 1 * 21 + 0 * 20 → 1010 (binaire) ou A (hex)
De même, vous pouvez convertir le reste des nombres décimaux du tableau 8.4 en leurs homologues binaires, ou
vice versa.
Opérateur La description
Opérateur La description
Cette section et la suivante donnent des explications et des exemples des opérateurs de manipulation de bits.
Les formes générales des opérateurs au niveau du bit sont les suivantes :
x & yx
| aa
^
X
~x
L' opérateur & compare chaque bit de x au bit correspondant de y. Si les deux bits sont à 1, 1 est placé à la même
position du bit dans le résultat. Si l'un des bits ou les deux sont 0, 0 est placé dans le résultat.
Par exemple, l'expression avec deux opérandes binaires, 01 et 11, donne 01.
Le | place 1 dans le résultat si l'un ou l'autre des opérandes est 1. Par exemple, l'expression 01 | 11 donne 11. Le |
l'opérateur donne un bit 0 si et seulement si les deux bits d'opérande
sont 0.
L' opérateur ^ place 1 dans le résultat si exactement un opérande, mais pas les deux, vaut 1. Par conséquent, l'expression
01 ^ 11 donne 10.
Enfin, l' opérateur ~ ne prend qu'un seul opérande. Cet opérateur inverse chaque bit de l'opérande. Par exemple,
~01 donne 10.
Le tableau 8.5 montre d'autres exemples d'utilisation des opérateurs au niveau du bit dans les formats décimal, hexadécimal
et binaire (dans les trois colonnes de gauche). Les résultats correspondants, aux formats binaire, hexadécimal et décimal,
sont répertoriés dans les trois colonnes de droite. Les numéros hexadécimaux sont préfixés par 0x.
du bit Résultats
132 Heure 8
Notez que la valeur complémentaire de 12 est 65 523 car le type de données entier non signé (16 bits) a le
nombre maximum 65 535. En d'autres termes, 65 523 est le résultat de la soustraction de 12 à 65 535. (Le
modificateur de données non signé est introduit dans l'heure 9, "Travailler avec les modificateurs de données
et les fonctions mathématiques".)
entier x, y, z ;
x = 4321 ; y
= 5678 ;
printf("Étant donné x = %u, c'estàdire 0X%04X\n", x, x); printf("
8 : 9 : 10 : 11y: = %u, c'estàdire 0X%04X\n",
renvoie : %6u, y, y);
c'estàdire
z = x & y0X%04X\n",
; printf("x & yz,
12 : z) ; z = x | y; printf("x | y renvoie : %6u, c'estàdire 0X%04X\n",
13: z, z) ;
14:
^
z=x y;
15 : 16 : 17 printf("x
: ^ y renvoie : %6u, c'estàdire 0X%04X\n", z, z) ;
18 : printf(" ~x renvoie : %6u, c'estàdire 0X%04X\n", ~x, ~x); renvoie 0 ;
19 :
20 : }
Une fois le fichier exécutable, 08L05.exe, créé et exécuté sur mon ordinateur, la sortie suivante s'affiche à
l'écran :
Dans le Listing 8.5, trois variables entières, x, y et z, sont déclarées à la ligne 6. Les lignes 8 et 9
UNE ANALYSE
fixent x et y à 4321 et 5678, respectivement. Lignes 10 et 11 puis imprimez
les valeurs de x et y dans les formats décimal et hexadécimal. Les numéros hexadécimaux sont préfixés
par 0X.
L'instruction de la ligne 12 affecte le résultat de l'opération effectuée par l'opérateur ET au niveau du bit
(&) avec les variables x et y. Ensuite, la ligne 13 affiche le résultat aux formats décimal et hexadécimal.
Machine Translated by Google
Les lignes 14 et 15 effectuent l'opération spécifiée par l'opérateur OU au niveau du bit (|) et impriment le
résultat aux formats décimal et hexadécimal. De même, les lignes 16 et 17 donnent le résultat de
l'opération effectuée par l'opérateur XOR au niveau du bit (^).
8
Enfin, l'instruction de la ligne 18 imprime la valeur complémentaire de x en utilisant l'opérateur de
complément au niveau du bit (~). Le résultat est affiché à l'écran aux formats décimal et hexadécimal.
Notez que le spécificateur de format entier non signé avec une largeur de champ minimale de 6,
%6u, et le spécificateur de format hexadécimal majuscule avec une largeur minimale de 4, %04X, sont
utilisés dans la fonction printf() . Le type de données entier non signé est utilisé ici afin que la valeur
complémentaire d'un entier puisse être affichée et comprise facilement. Plus de détails sur le
modificateur de données non signées sont introduits dans l'heure 9.
Ne confondez pas les opérateurs bit à bit & et | avec les opérateurs logiques && et
||. Par exemple,
Il y a deux opérateurs de décalage en C. L' opérateur >> décale les bits d'un opérande vers la droite ;
l' opérateur << décale les bits vers la gauche.
x >> yx
<< y
Ici x est un opérande qui va être décalé. y contient le nombre spécifié de places à décaler.
Par exemple, l'expression 8 >> 2 indique à l'ordinateur de décaler l'opérande 8 vers la droite de 2 bits,
ce qui donne le nombre 2 en décimal. Ce qui suit:
134 Heure 8
De même, l' expression 5 << 1 décale l'opérande 5 vers la gauche de 1 bit et donne 10 en décimal.
Le programme du Listing 8.6 imprime plus de résultats en utilisant les opérateurs de décalage.
TAPER
LISTE 8.6 Utilisation des opérateurs de décalage
entier x, y, z ;
x = 255 ; y
=5;
printf("Étant donné x = %4d, c'estàdire 0X%04X\n", x, x); printf(" y =
8 : 9 : 10 : 11%4d,
: c'estàdire 0X%04X\n",
%6d, c'estàdire
y, y); z =0X%04X\n",
x >> y ; printf("x
z, z);>>
z =y xdonne
<< y ;:
12 : printf("x << y donne : %6d, c'estàdire 0X%04X\n", z, z); renvoie 0 ;
13:
14:
15 :
16 :
17 : }
La sortie suivante est obtenue en exécutant le fichier exécutable 08L06.exe sur mon ordinateur :
UNE ANALYSE Trois variables entières, x, y et z, sont déclarées à la ligne 6 du Listing 8.6. x est initialisé à 255
à la ligne 8 ; y est initialisé à 5 à la ligne 9. Ensuite, les lignes 10 et 11 dis
jouer les valeurs de x et y sur l'écran.
L'instruction de la ligne 12 décale y bits de l'opérande x vers la droite, puis affecte le résultat à z. La ligne
13 imprime le résultat du décalage effectué à la ligne 12. Le résultat est 7 en décimal ou 0X0007 en
hexadécimal.
Les lignes 14 et 15 décalent l'opérande x vers la gauche de y bits et affichent également le résultat à
l'écran. Le résultat du décalage vers la gauche est 8160 en décimal, ou 0x1FE0 en hexadécimal.
Machine Translated by Google
L'opération de l'opérateur de décalage vers la droite (>>) équivaut à diviser par des
puissances de deux. Autrement dit, ce qui suit :
8
x >> y
est équivalent à
X *2
X?y:z
Ici x, y et z sont trois expressions d'opérandes. Parmi eux, x contient la condition de test, et y et z
représentent les deux valeurs finales possibles de l'expression. Si x est évalué comme non nul
(logiquement vrai), alors y est choisi ; sinon, z est le résultat obtenu par l'expression conditionnelle.
L'opérateur conditionnel est utilisé comme une sorte de raccourci pour un if
déclaration.
prend la valeur 'T' si la valeur de x est supérieure à 0. Sinon, l'expression conditionnelle prend la
valeur 'F'.
continue
Machine Translated by Google
136 Heure 8
6: entier x ;
7:
8: x = taillede(entier);
9: printf(“%s\n”, (x == 2)
dix:
11 : ? "Le type de données int a 2 octets." : "int n'a
12 : pas 2 octets."); printf("La valeur maximale de int
13: est : %d\n", (x != 2) ? ~(1 << x * 8 1) : ~(1 << 15) ); renvoie 0 ;
14:
15:
16 : }
La sortie suivante s'affiche à l'écran lorsque j'exécute le fichier exécutable 08L07.exe sur ma
machine :
Le type de données int a 2 octets
SORTIR La valeur maximale de int est : 32767
Dans le Listing 8.7, la taille du type de données int est mesurée en premier à la ligne 8 en
UNE ANALYSE
utilisant l' opérateur sizeof , et le nombre d'octets est affecté à la variable entière x.
Les lignes 9 à 12 contiennent une instruction, dans laquelle l'opérateur conditionnel (?:) est utilisé
pour tester si le nombre d'octets enregistrés dans x est égal à 2, et le résultat est imprimé. Si l'
expression x == 2 est différente de zéro, la chaîne Le type de données int a 2 octets est imprimée
par la fonction printf() dans l'instruction. Sinon, la deuxième chaîne, int n'a pas 2 octets, s'affiche à
l'écran.
De plus, l'instruction des lignes 11 et 12 essaie de trouver la valeur maximale du type de données
int sur la machine actuelle. L' expression x != 2 est évaluée en premier dans l'instruction. Si
l'expression renvoie une valeur différente de zéro (c'estàdire que le nombre d'octets du type de
données int n'est pas égal à 2), l' expression
comme valeur
~(1 <<de
x *retour
8 1) .est
Ici,évaluée
l' expression
et le résultat
~(1 << xest
* 8choisi
1) est
une forme générale pour calculer la valeur maximale du type*de
[ic:super](x 8 données intl'opérateur
1) 1. (Le , qui équivaut
de à
complément, ~, et l'opérateur de décalage, <<, ont été introduits dans les sections2 précédentes de
cette heure.)
Le résultat affiché à l'écran montre que le type de données int sur ma machine a une longueur de
2 octets (ou 16 bits) et que la valeur maximale du type de données int est 32767.
Machine Translated by Google
Résumé
Dans cette leçon, vous avez appris les très importants opérateurs logiques et de manipulation de bits 8
suivants en C :
• L' opérateur sizeof correspond au nombre d'octets qu'un type de données spécifié
a. Vous pouvez utiliser cet opérateur pour mesurer la taille d'un type de données sur votre machine.
• L'opérateur logique OU (||) ne donne 0 que si ses deux opérandes sont évalués à 0. Sinon, l'opérateur
donne 1.
• L'opérateur de négation logique (!) donne 0 lorsque son opérande est différent de zéro,
et ne donne 1 que si son opérande vaut 0.
• Il existe six opérateurs de manipulation de bits : l'opérateur ET au niveau du bit (&), l'opérateur OU au
niveau du bit (|), l'opérateur XOR au niveau du bit (^), l'opérateur de complément au niveau du bit ~),
l'opérateur de décalage vers la droite (>>), et l'opérateur de décalage à gauche (<<).
• L'opérateur conditionnel (?:) est le seul opérateur en C qui peut prendre trois
opérandes.
Dans la prochaine leçon, vous découvrirez les modificateurs de type de données dans le langage C.
Questions et réponses
A L' opérateur sizeof peut être utilisé pour mesurer la taille de tous les types de données définis en C.
Lorsque vous écrivez un programme C portable qui a besoin de connaître la taille d'une variable entière,
il est déconseillé de coder en dur la taille en fonction de la machine que vous utilisez actuellement. La
meilleure façon d'indiquer au programme la taille de la variable est d'utiliser l' opérateur sizeof , qui donne
la taille de la variable entière au moment de l'exécution.
Un | est l'opérateur OU au niveau du bit qui prend deux opérandes. Le | l'opérateur compare
chaque bit d'un opérande au bit correspondant d'un autre opérande. Si les deux bits sont 0, 0 est placé à
la même position du bit dans le résultat. Sinon, 1 est placé dans le résultat.
D'autre part, ||, en tant qu'opérateur logique OU, nécessite deux opérandes (ou expressions).
L'opérateur ne donne 0 que si ses deux opérandes sont évalués à 0.
Sinon, l'opérateur donne 1.
Machine Translated by Google
138 Heure 8
R S'il y a deux réponses possibles sous certaines conditions, vous pouvez utiliser l' opérateur ?: pour
sélectionner l'une des deux réponses en fonction du résultat obtenu en testant les conditions. Par
exemple, l'expression (âge > 65) ? « Retraité » : « Non retraité » indique à l'ordinateur que si la valeur de
l' âge est supérieure à 65 ans, la chaîne Retraité doit être choisie ; sinon, Non retiré est sélectionné.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et
exercices du quiz ».
Questionnaire
1. Que donnent les expressions (x=1) && (y=10) et (x=1) & (y=10) , respectivement
activement ?
3. Si vous avez deux variables int x et y, avec x défini sur la valeur binaire
0011000000111001 et y mis à la valeur binaire 1100111111000110, quelles valeurs sont fournies par
les deux expressions ~x et ~y ?
Des exercices
1. Étant donné x = 0xEFFF et y = 0x1000 (c'estàdire EFFF et 1000 comme valeurs hexadécimales), quel
valeurs hexadécimales obtenezvous en évaluant ~x et ~y ?
2. En prenant les valeurs de x et y assignées dans l'exercice 1, écrivez un programme qui imprime les
valeurs de !x et !y en utilisant à la fois les formats %d et %u dans la fonction printf() .
Machine Translated by Google
3. Étant donné x = 123 et y = 4, écrivez un programme qui affiche les résultats de l'expression
sions x << y et x >> y.
8
4. Écrivez un programme qui affiche les valeurs (en hexadécimal) des expressions 0xFFFF^0x8888,
0xABCD & 0x4567, et 0xDCBA | 0x1234.
5. Utilisez l' opérateur ?: et l'instruction for pour écrire un programme qui continue à prendre les
caractères saisis par l'utilisateur jusqu'à ce que le caractère q soit pris en compte. (Astuce : placez
?1 l'expression x!='q' : 0 comme deuxième expression dans une instruction for .)
Machine Translated by Google
Machine Translated by Google
HEURE 9
• signé
• non signé
• court
• longue
Machine Translated by Google
142 Heure 9
Vous allez également découvrir plusieurs fonctions mathématiques fournies par le langage C,
telles que
• La fonction sin()
• La fonction cos()
• La fonction tan()
• La fonction pow()
• La fonction sqrt()
Normalement, un bit peut être utilisé pour indiquer si la valeur d'un nombre représenté au format
binaire est négative. Ce bit est appelé bit de signe. Les deux sections suivantes présentent deux
modificateurs de données, signés et non signés, qui peuvent être utilisés pour activer ou désactiver le
bit de signe.
Il convient de noter que certains ordinateurs peuvent ne pas exprimer les nombres négatifs de la
manière décrite ; en fait, la norme du langage C n'exige pas l'utilisation d'un bit de signe, bien qu'il
s'agisse d'une méthode courante. La chose importante à comprendre est la différence entre les types
de données signés et non signés .
bit le plus à gauche peut être utilisé comme bit de signe. Par exemple, si le type de données int a une longueur
de 16 bits et que le bit le plus à droite est compté comme bit 0, vous pouvez utiliser le bit 15 comme bit de signe.
Lorsque le bit de signe est défini sur 1, le compilateur C sait que la valeur représentée par la variable
de données est négative.
Il existe plusieurs façons de représenter une valeur négative des types de données float ou double .
Les implémentations des types de données float et double sortent du cadre de ce livre. Vous pouvez
vous référer au livre de Kernighan et Ritchie, The C Programming Language, pour plus de détails sur
les implémentations des valeurs négatives de type float ou double .
Le langage C fournit un modificateur de données, signé, qui peut être utilisé pour indiquer
au compilateur que les types de données entiers (char, int, short int et long int) utilisent le signe
Machine Translated by Google
bit. (Les modificateurs courts et longs sont présentés plus loin dans ce chapitre). Par défaut, tous les types de
données entiers à l'exception du type de données char sont des quantités signées. Mais la norme ANSI n'exige
pas que le type de données char soit signé ; c'est aux vendeurs de compilateurs de décider. Par conséquent, si
vous souhaitez utiliser une variable de caractère signée et assurezvous que le compilateur la connaît, vous
pouvez déclarer la variable de caractère comme ceci :
afin que le compilateur sache que la variable caractère ch est signée, ce qui signifie que la variable peut 9
contenir à la fois des valeurs négatives et positives. Si le type char a une longueur de 8 bits, alors un char signé
7 7
contiendra des valeurs de 128 (c'estàdire 2 ) à 127 (2 1). En revanche, un
8
caractère non signé dans ce cas serait compris entre 0 et 255 (2 1).
donne également le modificateur non signé , qui peut être utilisé pour indiquer au compilateur C que le type
de données spécifié ne peut contenir que des valeurs non négatives.
Comme le modificateur signé , le modificateur non signé n'a de sens que pour les types de
données entiers (char, int, short int et long int).
indique au compilateur C que la variable entière x ne peut prendre que des valeurs positives de 0 à 65535
(c'estàdire 2161), si le type de données int a une longueur de 16 bits ; un int (signé) contiendrait des
valeurs de 32768 (2 151) à 32767 (2 15).
En fait, unsigned int est équivalent à unsigned (par luimême) selon la norme ANSI. En d'autres termes,
unsigned int x; est identique à x non signé;.
De plus, la norme ANSI vous permet d'indiquer qu'une constante est de type non signé en suffixant u ou U
à la constante. Par exemple,
Ici, les constantes entières non signées 12345U et 0xABCDu sont respectivement affectées aux variables x et
y.
Le programme du Listing 9.1 est un exemple d'utilisation des modificateurs signés et non signés .
Machine Translated by Google
144 Heure 9
Voici la sortie affichée à l'écran après avoir lancé l'exécutable sur mon ordinateur :
Comme vous le voyez dans le Listing 9.1, la ligne 6 déclare une variable char signée, ch. La
UNE ANALYSE
variable int x et la variable int non signée y sont déclarées aux lignes 7 et 8, respectivement
activement. Les trois variables, ch, x et y, sont initialisées aux lignes 10–12. Notez qu'à la ligne 12, u
est suffixé à 0xFFFF pour indiquer que la constante est un entier non signé.
L'instruction de la ligne 13 affiche la valeur décimale de la variable char signée ch. La sortie à l'écran
montre que la valeur décimale correspondante de 0xFF est 1 pour la variable char signée ch.
Les lignes 14 et 15 impriment les valeurs décimales de la variable int x (qui est signée par défaut) et de
la variable int non signée y, respectivement. Notez que pour la variable y, le spécificateur de format
entier non signé %u est utilisé dans la fonction printf() à la ligne 15.
Machine Translated by Google
(En fait, vous vous souviendrez peutêtre que %u a été utilisé pour spécifier le type de données int non signé
comme format d'affichage dans l'heure précédente.)
En fonction de la sortie, vous voyez que 0xFFFF est égal à 1 pour le type de données int signé et 65535 pour le
type de données int non signé . Ici, le type de données entier a une longueur de 16 bits.
Les lignes 16 et 17 impriment 0x3039 et 0xCFC7, qui sont les formats hexadécimaux des valeurs décimales de
12345 et 12345, respectivement. Selon la méthode mentionnée dans la dernière section, 0xCFC7 est obtenu en
ajoutant 1 à la valeur complémentée de 0x3039. 9
Vous pouvez obtenir des résultats différents à partir de cet exemple, selon la largeur des différents types
de données sur votre système. La chose importante à comprendre est la différence entre les types de données
signés et non signés .
Le modificateur court
Un type de données peut être modifié pour utiliser moins de mémoire en utilisant le modificateur court .
Par exemple, vous pouvez appliquer le modificateur short à une variable entière longue de 32 bits, ce qui
peut réduire la mémoire utilisée par la variable à 16 bits seulement.
x court ;
ou alors
Par défaut, un type de données int court est un nombre signé. Par conséquent, dans le court x; , x est
une variable signée d'entier court.
besoin de plus de mémoire pour conserver les valeurs d'une plage plus large, vous pouvez utiliser le
modificateur long pour définir un type de données avec un espace de stockage accru.
Par exemple, étant donné une variable entière x longue de 16 bits, la déclaration
entier long x ;
146 Heure 9
La norme ANSI permet d'indiquer qu'une constante est de type long en suffixant l ou
L à la constante :
entier long x, y ; x
= 123456789l ; y =
0xABCD1234L ;
Ici, les constantes du type de données int long , 123456789l et 0xABCD1234L, sont
respectivement affectées aux variables x et y.
De plus, vous pouvez déclarer une variable entière longue simplement comme ceci :
x long ;
qui équivaut à
entier long x ;
Le Listing 9.2 contient un programme qui peut imprimer le nombre d'octets fournis par le compilateur
C utilisé pour compiler le programme pour différents types de données modifiés.
J'obtiens le résultat suivant après avoir exécuté l'exécutable 09L02.exe sur mon ordinateur :
La taille de l'entier court est : 2.
SORTIR La taille de l'entier long est : 4.
La taille du flotteur est : 4.
La taille du double est : 8.
La taille du double long est : 10.
Machine Translated by Google
UNE ANALYSE
Dans le Listing 9.2, l' opérateur sizeof et la fonction printf() sont utilisés pour mesurer la taille des
types de données modifiés et afficher les résultats à l'écran.
Par exemple, les lignes 6 et 7 obtiennent la taille du type de données int court et impriment le nombre
d'octets, 2, à l'écran. D'après la sortie, vous savez que le type de données int court fait 2 octets sur ma
machine.
De même, les lignes 8 et 9 trouvent que la taille du type de données long int est de 4 octets, ce qui correspond
à la même longueur que le type de données float obtenu aux lignes 10 et 11. 9
Les lignes 12 et 13 obtiennent la taille du type de données double , qui est de 8 octets sur ma
machine. Ensuite, après avoir été modifié par le modificateur long , la taille du type de données double est
augmentée à 10 octets (c'estàdire 80 bits), ce qui est affiché par l' appel printf() aux lignes 14 et 15.
Comme dans l'exemple précédent, vos résultats seront probablement différents si votre système
prend en charge des largeurs de données différentes de celles de ma machine. En exécutant ce programme
sur votre propre ordinateur, vous pouvez déterminer les largeurs de ces types de données pour votre
système.
Ajout de h, l ou L aux spécificateurs de format printf et fprintf Les fonctions printf et fprintf doivent
connaître le type de données exact des arguments qui leur sont transmis afin d'évaluer
correctement ces arguments et d'imprimer leurs valeurs de manière significative. La chaîne de format des
fonctions printf et fprintf utilise les spécificateurs de conversion d, i, o, u, x ou X pour indiquer que l'argument
correspondant est un entier et est de type int ou unsigned int.
Vous pouvez ajouter h dans le spécificateur de format entier (comme ceci : %hd, %hi ou %hu) pour spécifier que
l'argument correspondant est un entier court ou un entier court non signé.
D'autre part, l'utilisation de %ld ou %Ld spécifie que l'argument correspondant est un entier long. %lu ou
%Lu est ensuite utilisé pour les données de type entier long non signé .
entier court X;
continue
Machine Translated by Google
148 Heure 9
Une fois le fichier exécutable 09L03.exe créé et exécuté sur ma machine, la sortie suivante s'affiche à
l'écran :
L'entier court de 0xFFFF est 1.
SORTIR L'entier non signé de 0xFFFF est 65535.
L'entier long de 0xFFFFFFFF est 1.
L'entier long non signé de 0xFFFFFFFF est 4294967295
Il y a quatre types de données déclarés dans le Listing 9.3 : la variable int courte x, la variable
UNE ANALYSE
int non signée y, la variable int longue s et la variable int longue non signée t. Les quatre
variables sont initialisées aux lignes 6–9.
Pour afficher les valeurs décimales de x, y, s et t, les spécificateurs de format %hd, %u, %ld et %lu sont
utilisés respectivement aux lignes 15 à 18 pour convertir les nombres hexadécimaux correspondants en
nombres décimaux. La sortie du programme du Listing 9.3 montre que les valeurs contenues par x, y, s
et t ont été correctement affichées à l'écran.
Fonctions mathématiques en C
Fondamentalement, les fonctions mathématiques fournies par le langage C peuvent être classées en trois
groupes:
Vous devez inclure le fichier d' entête math.h dans votre programme C avant de pouvoir utiliser les
fonctions mathématiques définies dans le fichier d'entête.
Les deux sections suivantes présentent plusieurs fonctions mathématiques et décrivent comment les
utiliser dans vos programmes.
Machine Translated by Google
Par exemple, étant donné un angle x en radians, l' expression sin renvoie le sinus de l'angle.
La formule suivante peut être utilisée pour convertir la valeur d'un angle en degrés en une valeur en radians :
9
radians = degré * (3,141593 / 180,0).
Ici, 3,141593 est la valeur approximative de pi. Si nécessaire, vous pouvez utiliser plus de chiffres
décimaux à partir de pi.
SYNTAXE
#include <math.h>
double sin(double x);
Ici, la variable double x contient la valeur d'un angle en radians. La fonction sin() renvoie le sinus de x dans le
type de données double .
#include <math.h>
SYNTAXE
Ici, la variable double x contient la valeur d'un angle en radians. La fonction cos() renvoie le cosinus de x dans
le type de données double .
#include <math.h>
double tan(double x);
SYNTAXE
Ici, la variable double x contient la valeur d'un angle en radians. La fonction tan() renvoie la tangente de x dans
le type de données double .
Le Listing 9.4 montre comment utiliser les fonctions sin(), cos() et tan() .
LISTE 9.4 Calcul des valeurs trigonométriques avec sin(), cos() et tan()
4:
continue
Machine Translated by Google
150 Heure 9
5 : principal()
6:{7:
double X;
La sortie suivante s'affiche à l'écran lorsque le fichier exécutable 09L04.exe est exécuté :
Notez que le fichier d'entête math.h est inclus à la ligne 3, ce qui est requis par les fonctions
UNE ANALYSE
mathématiques C.
La variable double x du Listing 9.4 est initialisée avec 45,0 à la ligne 9. Ici, 45,0 est la valeur de l'angle
en degrés, qui est convertie en la valeur correspondante en radians à la ligne 10.
La ligne 13 donne la valeur tangente de x en utilisant la fonction tan() . Comme vous le savez peutêtre,
la tangente de x est égale au sinus de x divisé par le cosinus de x. Étant donné que le sinus d'un angle
de 45 degrés est le même que le cosinus d'un angle de 45 degrés, la tangente d'un angle de 45 degrés
est égale à 1. Le résultat (au format à virgule flottante) de 1,000000, dans le troisième ligne de la sortie
de la liste, le prouve.
Pour simplifier les choses, vous pouvez déclarer une variable PI initialisée à 3,141593 et une autre
variable initialisée à 180,0, et les utiliser dans vos calculs. Ou, déclarez simplement une seule
constante initialisée au résultat de 3.141593/180.0.
SYNTAXE
#include <math.h>
double pow(double x, double y);
Ici, la valeur de la variable double x est élevée à la puissance y. La fonction pow() renvoie le résultat
dans le type de données double .
SYNTAXE
#include <math.h> 9
double sqrt(double x);
Ici, la fonction sqrt() renvoie la racine carrée non négative de x dans le type de données double .
Une erreur se produit si x est négatif.
Si vous passez 0,5 à la fonction pow() comme second argument, et que x contient une valeur non
négative, les deux expressions, pow(x, 0,5) et sqrt, sont équivalentes.
Maintenant, regardez comment appeler les fonctions pow() et sqrt() dans le programme présenté dans
le Listing 9.5.
5 : principal()
6:{7:
double x, y, z ;
x = 64,0 ; y
= 3,0 ; z =
8 : 9 : 10 : 110,5
: ;
12 : printf("pow(64.0, 3.0) renvoie : %7.0f\n", pow(x, y)); printf("sqrt(64.0)
13: renvoie : %2.0f\n", sqrt); printf("pow(64.0, 0.5)
z));renvoie
renvoie: %2.0f\n",
0; pow(x,
14:
15 :
16 : }
Ensuite, la sortie suivante s'affiche à l'écran après l'exécution du fichier exécutable 09L05.exe :
UNE ANALYSE Les trois variables doubles du Listing 9.5, x, y et z, sont initialisées avec 64.0, 3.0 et 0.5,
respectivement, aux lignes 9–11.
Machine Translated by Google
152 Heure 9
La fonction pow() de la ligne 12 prend x et y puis calcule la valeur de x élevée à la puissance y. Parce que le
résultat est un double, mais je sais que la partie fractionnaire sera composée uniquement de chiffres décimaux
de 0, le spécificateur de format %7.0f est utilisé dans la fonction printf() pour convertir uniquement la partie non
fractionnaire de la valeur. Le résultat s'affiche à l'écran sous la forme
262144.
À la ligne 13, la racine carrée non négative de x est calculée en appelant la fonction sqrt() .
Comme à la ligne 12, le spécificateur de format %2.0f est utilisé à la ligne 13 pour convertir la partie non
fractionnaire de la valeur renvoyée par la fonction sqrt() car la partie fractionnaire se compose uniquement de 0.
Comme vous le voyez dans la sortie, la racine carrée non négative de x est 8.
Comme je l'ai mentionné plus tôt, l'expression pow(x, 0.5) est équivalente à l'expression sqrt.
Ainsi, il n'est pas surprenant de voir que pow(x, z) dans l'instruction de la ligne 14 produit le même résultat que sqrt
dans la ligne 13.
Tous les calculs en virgule flottante, y compris les types de données float et double, sont
effectués en arithmétique à double précision. C'estàdire qu'une variable flottante doit être
convertie en un double pour poursuivre le calcul.
Après le calcul, le double doit être reconverti en flottant avant que le résultat puisse être
affecté à la variable flottante. Par conséquent, un calcul flottant peut prendre plus de temps.
La raison principale pour laquelle C prend en charge le type de données float est
d'économiser de l'espace mémoire car le type de données double prend deux fois plus
d'espace mémoire pour le stockage que le type de données float. Dans de nombreux cas,
une précision audelà de ce qui est fourni par float est tout simplement inutile.
Résumé
Dans cette leçon, vous avez appris les modificateurs et fonctions mathématiques importants suivants :
• Le modificateur signé peut être utilisé pour déclarer des types de données char et int capables de
détenir des valeurs négatives et non négatives.
modificateur unsigned peut être utilisé pour déclarer des types de données char et int qui ne peuvent pas
contenir de valeurs négatives. Cela double effectivement la plage de valeurs positives que la variable peut
contenir.
• L'espace mémoire occupé par une variable de données peut être réduit ou augmenté en utilisant
le modificateur de données court ou long , respectivement.
Machine Translated by Google
• Il existe un ensemble de fonctions de la bibliothèque C, telles que sin(), cos() et tan(), qui peuvent être
utilisé pour effectuer des calculs trigonométriques ou hyperboliques.
• La fonction sqrt() renvoie une racine carrée non négative. L'expression sqrt est équivalente à l'
expression pow(x, 0.5) , si x a une valeur non négative. Vous ne pouvez pas passer une valeur
négative à la fonction sqrt() , car cela provoquerait une erreur. • Le fichier d'entête math.h doit être
9
inclus dans votre programme C si vous appelez des fonctions mathématiques déclarées dans ce fichier
d'entête.
Dans la leçon suivante, vous apprendrez plusieurs instructions de flux de contrôle très importantes en C.
Questions et réponses
Q Quel bit peut être utilisé comme bit de signe dans un entier ?
A Le bit le plus à gauche peut être utilisé comme bit de signe pour un entier. Par exemple, supposons que le
type de données int ait une longueur de 16 bits. Si vous comptez la position du bit de droite à gauche et
que le premier bit compté est le bit 0, le bit 15 est le bit le plus à gauche qui peut être utilisé comme bit de
signe.
A Le spécificateur de format %lu peut être utilisé dans une chaîne printf() pour convertir le
argument répondant au type de données int long non signé . De plus, le spécificateur %lu pour mat est
équivalent à %Lu.
A Si vous avez besoin d'économiser de l'espace mémoire et que vous savez que la valeur d'une variable de
données entière reste dans une plage plus petite, vous pouvez essayer d'utiliser le modificateur court
pour indiquer au compilateur C de réduire l'espace mémoire par défaut affecté à la variable, par exemple,
de 32 bits à 16 bits.
D'un autre côté, si une variable doit contenir un nombre qui dépasse la plage actuelle d'un type de
données, vous pouvez utiliser le modificateur long pour augmenter l'espace de stockage de la variable afin
de contenir le nombre.
A Comme les autres fonctions mathématiques trigonométriques en C, la fonction sin() prend une valeur en
radians. Si vous avez un angle en degrés, vous devez le convertir en radians. La formule est :
154 Heure 9
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les réponses
et les conseils aux questions et exercices sont donnés dans l'annexe D, « Réponses aux questions et exercices du
quiz ».
Questionnaire
1. Étant donné une variable int x et une variable int non signée y, ainsi que x = 0x8765 et y = 0x8765, et si le
bit le plus à gauche est utilisé comme bit de signe, x estil égal à y ?
2. Que devezvous faire si vous essayez d'attribuer une grande valeur à une variable int , mais que la valeur
que vous attribuez est trop grande et que vous vous retrouvez avec un nombre négatif auquel vous ne
vous attendiez pas ?
3. Quel spécificateur de format, %ld ou %lu, doit être utilisé pour spécifier un long non signé
variable entière ?
4. Quel est le nom du fichier d'entête que vous devez inclure si vous appelez des fonctions mathématiques C
depuis votre programme C ?
Des exercices
2. Écrivez un programme pour mesurer les tailles d' entier court, d'entier long et de double long sur votre machine.
3. Écrivez un programme pour multiplier deux variables entières signées par des valeurs positives et affichez le
résultat sous la forme d'un entier long.
4. Écrivez un programme pour afficher les nombres entiers négatifs au format hexadécimal avec leur signe
équivalents entiers .
5. Étant donné un angle de 30 degrés, écrivez un programme pour calculer son sinus et sa tangente
valeurs.
HEURE 10
Programme de contrôle
Flux
Il est plus difficile de commander que d'obéir.
F. Nietzsche
Dans l'heure 7, "Travailler avec des boucles", vous avez appris à utiliser les instructions
while, dowhile et for pour faire les mêmes choses encore et encore. Ces trois
instructions peuvent être regroupées dans la catégorie des instructions en boucle
utilisées pour le contrôle de flux en C.
Dans cette leçon, vous découvrirez les instructions appartenant à un autre groupe
d' instructions de flux de contrôle, le branchement conditionnel (ou le saut), comme
• L' instruction if
• L' instruction ifelse
• L' instruction switch
• L' instruction break
• L' instruction continue
156 Heure 10
En fait, une tâche importante d'un programme consiste à demander à l'ordinateur de se brancher (c'està
dire de sauter) vers différentes parties du code et de travailler sur différentes tâches chaque fois que les conditions
spécifiées sont remplies.
Cependant, dans la plupart des cas, vous ne savez pas à l'avance ce qui va suivre. Ce que vous savez, c'est
que quelque chose doit arriver si certaines conditions sont remplies. Par conséquent, vous pouvez simplement
écrire les tâches et les conditions dans le programme. Les décisions concernant le moment d'exécution des
tâches sont prises par les instructions de branchement conditionnel.
En C, l' instruction if est l'instruction de branchement conditionnel la plus populaire ; il peut être utilisé pour
évaluer les conditions ainsi que pour décider si le bloc de code
si (expression)
{ instruction1 ;
instruction2 ;
.
.
.
}
Ici , l' expression est le critère conditionnel. Si expression donne une valeur différente de zéro, les instructions
entre accolades ({ et }), telles que instruction1 et instruction2, sont exécutées. Si expression prend la valeur zéro,
les instructions sont ignorées.
Notez que les accolades ({ et }) forment un bloc d'instructions qui est sous le contrôle de l' instruction if . S'il n'y
a qu'une seule instruction à l'intérieur du bloc, les accolades peuvent être omises.
Les parenthèses (( et )), cependant, doivent toujours être utilisées pour délimiter l'expression conditionnelle.
if (x > 0.0)
printf("La racine carrée de x est : %f\n", sqrt);
indique à l'ordinateur que si la valeur de la variable à virgule flottante x est supérieure à 0,0 (c'estàdire
positive), il doit calculer la racine carrée de x en appelant la fonction sqrt() , puis imprimer le résultat. Ici, le critère
conditionnel est l'expression relationnelle
Machine Translated by Google
x > 0,0, qui prend la valeur 1 (logiquement vrai) si x est supérieur à zéro, et prend la valeur 0
(logiquement faux) si x est inférieur ou égal à zéro.
int je ;
printf("Entiers qui peuvent être divisés à la fois par 2 et 3\n"); printf("(entre 0 et 100):\n"); for
(i=0; i<=100; i++){ if ((i%2 == 0) && (i%3 == 0)) printf(“ %d\n”, i); dix
8 : 9 : 10 : 11 :
12 :
13 : } 14 :
renvoie 0 ; 15 : }
Comme vous le voyez dans le Listing 10.1, la ligne 6 déclare une variable entière, i. Les
UNE ANALYSE
lignes 8 et 9 impriment deux titres. À partir de la ligne 10, l' instruction for continue de boucler 101
fois.
Machine Translated by Google
158 Heure 10
Dans la boucle for , l'instruction if des lignes 11 et 12 évalue l'expression logique (i%2 == 0) && (i%3 ==
0). Si l'expression est évaluée à 1 (c'estàdire que la valeur de i peut être complètement divisée par 2
et 3 ), la valeur de i est affichée à l'écran en appelant la fonction printf() à la ligne 12. Sinon, l'instruction
dans la ligne 12 est sautée.
Notez que les accolades ({ et }) ne sont pas utilisées car il n'y a qu'une seule instruction sous le contrôle
de l' instruction if .
Le résultat affiché à l'écran donne tous les nombres entiers compris entre 0 et 100 qui peuvent être
divisés de manière égale par 2 et 3.
La déclaration ifelse
Dans l' instruction if , lorsque l'expression conditionnelle prend une valeur différente de zéro,
l'ordinateur passe directement aux instructions contrôlées par l' instruction if et les exécute
immédiatement. Si l'expression prend la valeur zéro, l'ordinateur ignorera les instructions contrôlées
par l' instruction if .
Vous souhaiterez souvent que l'ordinateur exécute un autre ensemble d'instructions lorsque l'expression
conditionnelle de l' instruction if est évaluée comme logiquement fausse. Pour ce faire, vous pouvez
utiliser une autre instruction de branchement conditionnel en C : l' instruction ifelse .
si (expression)
{ instruction1 ;
instruction2 ;
.
.
.
} else
{ instruction_A ;
instruction_B ;
.
.
.
}
Si expression donne une valeur différente de zéro, les instructions contrôlées par if, y compris
instruction1 et instruction2, sont exécutées. Cependant, si expression prend la valeur zéro, instruction_A
et instruction_B suivant le motclé else sont exécutées à la place.
int je ;
7:
8: printf("Nombre pair Nombre impair\n"); for (i=0; i<10; i++)
9: if (i%2 == 0) printf("%d", i); sinon printf("%14d\n", je);
10 :
11 :
12 :
13 :
14 :
15 : renvoie 0 ; dix
16 : }
4 5
6 7
8 9
La ligne 6 du Listing 10.2 déclare une variable entière, i. La fonction printf() à la ligne 8
UNE ANALYSE
affiche un titre à l'écran.
La variable entière i est initialisée dans la première expression de l' instruction for de la ligne 9.
Contrôlée par l' instruction for , l'instruction ifelse des lignes 10 à 13 est exécutée 10 fois. Selon
l' instruction ifelse , l' appel printf() à la ligne 11 imprime les nombres pairs si l'expression
relationnelle i%2 == 0 à la ligne 10 est évaluée à 1 (logiquement vrai). Si l'expression relationnelle est
évaluée à 0 (logiquement faux), l' appel printf() contrôlé par le motclé else à la ligne 13 renvoie des
nombres impairs sur la sortie standard.
Étant donné que l' instruction ifelse est traitée comme une instruction unique, les accolades { et } ne
sont pas nécessaires pour former un bloc d'instructions sous l' instruction for . De même, aucune
accolade n'est utilisée dans l' instruction ifelse car les motsclés if et else contrôlent chacun une seule
instruction aux lignes 11 et 13 respectivement.
Notez que la largeur minimale de 14 est spécifiée dans la fonction printf() à la ligne 13, de sorte
que la sortie des nombres impairs est répertoriée à droite des nombres pairs, comme vous pouvez
le voir dans la section de sortie. Le programme du Listing 10.2 vérifie les nombres compris entre 0
et 9 et montre que 0, 2, 4, 6 et 8 sont des nombres pairs et que 1, 3, 5, 7 et 9 sont des nombres impairs.
Machine Translated by Google
160 Heure 10
Instructions if imbriquées
Comme vous l'avez vu dans les sections précédentes, une instruction if permet à un programme de prendre
une décision. Dans de nombreux cas, un programme doit prendre une série de décisions connexes. À cette
fin, vous pouvez utiliser des instructions if imbriquées .
int je ;
7:
8: for (i=5; i<=5; i++){ if (i > 0)
9: if (i%2 == 0) printf(“%d
10 : est un nombre pair.
11 : \n”, i); sinon printf("%d est un nombre impair.\n",
12 : i); sinon si (i == 0) printf("Le nombre est zéro.\n");
13 : sinon printf("Négatif : %d\n", i); renvoie 0 ;
14 :
15 :
16 :
17 :
18 : }19 :
20 : }
Nombre négatif : 5
SORTIR Nombre négatif : 4
Nombre négatif : 3
Nombre négatif : 2
Nombre négatif : 1 Le
nombre est zéro. 1 est
un nombre impair. 2 est
un nombre pair. 3 est un
nombre impair. 4 est un
nombre pair. 5 est un
nombre impair.
UNE ANALYSE Le Listing 10.3 contient une boucle for , commençant à la ligne 8 et se terminant à la ligne 18.
Selon les expressions de l' instruction for de la ligne 8, toutes les tâches contrôlées
par l' instruction for sont exécutées jusqu'à 11 fois.
Machine Translated by Google
Tout d'abord, une décision doit être prise sur la base de l'évaluation de l'expression relationnelle i > 0
dans l' instruction if de la ligne 9. L' expression i > 0 est utilisée pour tester si la valeur de i est positive
ou autre (nombres négatifs, y compris zéro.) Si l'expression est évaluée à 1, l'ordinateur saute à la
deuxième instruction if (c'estàdire imbriquée) de la ligne 11.
Notez que la ligne 11 contient une autre expression relationnelle, i%2 == 0, qui teste si la variable
entière i est paire ou impaire. Par conséquent, la deuxième décision d'afficher des nombres pairs ou
des nombres impairs doit être prise en fonction de l'évaluation de la deuxième expression relationnelle,
i%2 == 0. Si cette évaluation donne 1, l' appel printf() à la ligne 11 imprime un nombre pair. Sinon,
l'instruction de la ligne 13 est exécutée et un nombre impair s'affiche à l'écran.
L'ordinateur passe à la ligne 14 si l' expression i > 0 de la ligne 9 donne 0 ; c'estàdire si la valeur de i
n'est pas supérieure à 0. À la ligne 14, une autre instruction if est imbriquée dans une phrase else et
l'expression relationnelle i == 0 est évaluée. Si i == 0 est évalué comme logiquement vrai, ce qui signifie
dix
que i contient la valeur zéro, la chaîne Le nombre est zéro s'affiche à l'écran. Sinon, la valeur de i doit
être négative, selon l'évaluation précédente de l' expression i > 0 à la ligne 9. L'instruction de la ligne
17 affiche alors le nombre négatif sur la sortie standard.
Comme vous pouvez le voir dans l'exemple, la valeur de i est comprise entre 5 et 5. Ainsi, 5, 4, 3, 2
et 1 sont imprimés sous forme de nombres négatifs. Ensuite, un message est imprimé lorsque i vaut
zéro, puis les nombres impairs 1, 3 et 5, ainsi que les nombres pairs 2 et 4 sont imprimés.
La déclaration de commutateur
Dans la dernière section, vous avez vu que les instructions if imbriquées sont utilisées lorsqu'il y a des
décisions successives et liées à prendre. Cependant, les instructions if imbriquées peuvent devenir très
complexes si de nombreuses décisions doivent être prises. Parfois, un programmeur aura des
problèmes pour suivre une série d' instructions if imbriquées complexes .
Heureusement, il existe une autre instruction en C, l' instruction switch , que vous pouvez utiliser pour
prendre des décisions ou des choix illimités en fonction de la valeur d'une expression conditionnelle
et de cas spécifiés.
case expressionconstante2 :
Machine Translated by Google
162 Heure 10
instruction2 ;
.
.
.
par
défaut : instructiondefault ;
}
Ici, l'expression conditionnelle, expression, est évaluée en premier. L'instruction switch passera alors à
l' étiquette de cas appropriée et exécutera, dans l'ordre, les instructions qui suivent. Si expression
donne une valeur égale à l'expression constante constanteexpression1, l'instruction instruction1 est
exécutée, suivie de instruction2 et de tout jusqu'à instructiondefault. Si la valeur renvoyée par
expression est la même que celle de expressionconstante2, instruction2 est exécutée en premier. Si,
toutefois, la valeur de expression n'est égale à aucune des valeurs des expressions constantes étiquetées
par le motclé case , l' instruction (instructiondefault) qui suit le motclé default est exécutée.
Vous devez utiliser le motclé case pour étiqueter chaque cas. Notez que chaque étiquette de cas se
termine par deux points et non par un pointvirgule. Il s'agit de la syntaxe des étiquettes en C. Le mot
clé par défaut doit être utilisé pour le cas "par défaut", c'estàdire lorsqu'aucune étiquette de cas ne
correspond à l'expression conditionnelle. Notez qu'aucune des expressions constantes associées aux
étiquettes de cas ne peut être identique dans l' instruction switch .
En C, une étiquette est utilisée comme une sorte de signet dans votre code pour être utilisée par
l'instruction de branchement conditionnel. Une étiquette n'est pas, en ellemême, une déclaration ;
il indique plutôt un endroit où sauter lorsque vous souhaitez vous écarter du flux d'exécution
normal de haut en bas.
La syntaxe appropriée pour une étiquette est un identifiant unique suivi de deuxpoints — et
non d'un pointvirgule . Dans ce chapitre, vous verrez plusieurs manières d'utiliser les étiquettes,
ainsi que les noms d'étiquette réservés case expression : et default :.
Le programme du Listing 10.4 vous donne un exemple d'utilisation de l' instruction switch . Le
programme démontre également une caractéristique importante de l' instruction switch .
int jour ;
Machine Translated by Google
7:
8: printf("Veuillez saisir un seul chiffre pour un jour\n"); printf("(entre
9: 1 et 3):\n"); jour = getchar(); switch (jour){ case '1' :
10 :
11 :
12 :
13 : printf("Jour 1\n"); cas
14 : '2' :
15 : printf("Jour 2\n"); cas
16 : '3' :
17 : printf("Jour 3\n"); défaut:
18 :
19 : ;
20 :
21 : } renvoie 0 ;
22 : }
dix
Si je lance le fichier exécutable 10L04.exe et que j'entre 3, j'obtiens le résultat suivant :
Jour 3
Comme vous pouvez le voir à la ligne 6, une variable int , day, est déclarée ; on lui affecte l'entrée saisie par
UNE ANALYSE
l'utilisateur à la ligne 10.
À la ligne 11, la valeur de la variable entière day est évaluée dans l' instruction switch . Si la valeur est égale à l'une
des valeurs des expressions constantes, l'ordinateur commence à exécuter des instructions à partir de là. Les
expressions constantes sont étiquetées en préfixant la casse devant elles.
Par exemple, j'ai entré 3 , puis j'ai appuyé sur la touche Entrée. La valeur numérique de 3 est affectée au jour
à la ligne 10. Ensuite, après avoir trouvé un cas dans lequel la valeur de l'expression constante correspond à la
valeur contenue par jour, l'ordinateur saute à la ligne 17 pour exécuter la fonction printf() et afficher Jour 3 à l'écran.
Notez que sous l' étiquette par défaut du Listing 10.4, il y a une instruction vide (c'estàdire nulle) se terminant par
un pointvirgule à la ligne 19. L'ordinateur ne fait rien avec l'instruction vide. Cela signifie que si aucune des
expressions constantes ne s'applique, l' instruction switch finit par ne rien faire du tout.
Cependant, si j'entre 1 sur mon clavier et que j'appuie sur la touche Entrée lors de l'exécution du fichier
exécutable 10L04.exe, j'obtiens le résultat suivant :
164 Heure 10
(dans la plage de 1 à 3) : 1
Jour 1
Jour 2
Jour 3
À partir de la sortie, vous pouvez voir que l'instruction contrôlée par le cas sélectionné, le cas 1, et les
instructions contrôlées par le reste des cas, sont exécutées, car Jour 1, Jour 2 et Jour 3 sont affichés à
l'écran. De même, si j'entre 2 à partir de mon clavier, j'ai Jour 2 et Jour 3 affichés à l'écran.
Il s'agit d'une caractéristique importante de l' instruction switch : l'ordinateur continue d'exécuter les
instructions suivant le cas sélectionné jusqu'à la fin de l' instruction switch .
Vous allez apprendre comment quitter plus tôt l'exécution de l' instruction switch dans la section suivante.
La déclaration de rupture
Si vous souhaitez quitter complètement le commutateur après chaque étiquette de cas, vous pouvez
ajouter une instruction break à la fin de la liste d'instructions qui suit chaque étiquette de cas . L'
instruction break quitte simplement le commutateur et reprend l'exécution après la fin du bloc
d'instructions switch .
Le programme du Listing 10.5 ressemble à celui du Listing 10.4, mais cette fois, l' instruction break
est utilisée et les résultats sont différents.
int jour ;
20 : Pause;
21 : cas '4' :
22 : printf("Le jour 4 est mercredi.\n"); Pause;
23 : cas '5' :
24 :
25 : printf("Le jour 5 est jeudi.\n"); Pause;
26 : case '6' :
27 :
28 : printf("Le jour 6 est vendredi.\n");
29 : Pause; cas '7' :
30 :
31 : printf("Le jour 7 est samedi.\n"); Pause;
32 : défaut:
33 :
34 : printf("Le chiffre n'est pas compris entre 1 et 7.\n"); Pause;
35 :
36 :
37 : } renvoie 0 ;
dix
38 : }
Avec l'aide de l' instruction break , je peux exécuter le fichier exécutable 10L05.exe et obtenir uniquement la sortie du
cas sélectionné :
UNE ANALYSE
Ce programme a sept étiquettes de cas suivies des expressions constantes de
'1', '2', '3', '4', '5', '6' et '7', respectivement. (Voir les lignes 12, 15, 18, 21, 24, 27
et 30.)
Dans chaque cas, il y a une instruction suivie d'une instruction break . Comme mentionné, les instructions break
quitteront la construction switch avant que l'ordinateur n'atteigne l'étiquette de cas suivante et les instructions qui la
suivent.
Par exemple, une fois que la variable int day a reçu la valeur 1 et a été évaluée dans l' instruction switch , le cas
avec '1' est sélectionné et l'instruction de la ligne 13 est exécutée.
Ensuite, l' instruction break de la ligne 14 est exécutée, ce qui interrompt le contrôle de l' instruction switch et renvoie
le contrôle à l'instruction suivante en dehors de la construction switch . Dans
Listing 10.5, l'instruction suivante est l' instruction return de la ligne 37, qui termine la fonction main .
L' appel printf() de la ligne 13 génère une chaîne indiquant que le jour 1 est dimanche. sur l'écran.
Notez que dans une instruction switch , les accolades ne sont pas nécessaires pour regrouper les instructions dans un
cas individuel, car case n'est qu'une étiquette et ne contrôle pas les instructions qui la suivent. Ils sont simplement
exécutés dans l'ordre, en commençant par l'étiquette.
Machine Translated by Google
166 Heure 10
tandis
que
{ instruction1 ; instruction2 ;
.
.
.
}
La boucle for cidessus omet les trois expressions. Ainsi, l' instruction for exécute toujours la
boucle. L' instruction while utilise 1 comme expression conditionnelle, et comme cela n'est bien
sûr jamais évalué à 0, l'instruction while continue toujours la boucle.
Le programme du Listing 10.6 montre un exemple d'utilisation de l' instruction break dans
une boucle while infinie .
entier c ;
7:
8: printf("Entrez un caractère :\n(entrez x pour quitter)\n"); tandis que
9: { c = getc(stdin); si (c == 'x') pause ;
10 :
11 :
12 :
13 :
14 : } printf("Brise la boucle while infinie. Au revoir !\n"); renvoie 0 ;
15 :
16 : }
Machine Translated by Google
Voici le résultat que j'ai obtenu après avoir exécuté le fichier exécutable (10L06.exe) sur ma
machine :
X
Cassez la boucle while infinie. Au revoir!
Il existe une boucle while infinie dans le Listing 10.6, qui commence à la ligne 9 et se termine
UNE ANALYSE
à la ligne 13. Dans la boucle infinie, les caractères saisis par l'utilisateur sont affectés,
un à la fois, à la variable entière c (voir ligne 10.)
L'expression relationnelle c == 'x' dans l' instruction if (voir ligne 11) est évaluée à chaque fois
pendant la boucle. Si l'expression donne la valeur 0 (c'estàdire que l'utilisateur n'a pas saisi la lettre
x), la boucle se poursuit. Sinon, l' instruction break de la ligne 12 est exécutée, ce qui fait que l'ordinateur
dix
saute hors de la boucle infinie et commence à exécuter l'instruction suivante, qui est montrée à la ligne
14.
Vous pouvez voir dans l'exemple de sortie, la boucle while se poursuit jusqu'à ce que j'aie entré la lettre
x, ce qui provoque la rupture de la boucle infinie et un message, Break the Infinity while loop. Bye!, à
afficher à l'écran.
La déclaration continue
Au lieu de casser une boucle, il y a des moments où vous voulez rester dans une boucle mais ignorer
certaines instructions dans la boucle. Pour ce faire, vous pouvez utiliser l' instruction continue . L'
instruction continue fait sauter immédiatement l'exécution au bas de la boucle.
Par exemple, le Listing 10.7 montre comment utiliser l' instruction continue dans une boucle faisant
des sommes.
somme =
0 ; for (i=1; i<8; i++){ if ((i==3) ||
(i==5)) continuer ;
8 : 9 : 10 : 11 :
continue
Machine Translated by Google
168 Heure 10
12 : somme += je ;
13 :
14 : } printf("La somme de 1, 2, 4, 6 et 7 est : %d\n", somme); renvoie 0 ;
15 :
16 : }
Une fois le fichier exécutable 10L07.exe exécuté sur mon ordinateur, la sortie suivante s'affiche
à l'écran :
La somme de 1, 2, 4, 6 et 7 est : 20
SORTIR
Dans le Listing 10.7, nous voulons calculer la somme des valeurs entières de 1, 2, 4, 6 et
UNE ANALYSE
7. Comme les entiers sont presque consécutifs, une boucle for est construite aux lignes 9–
13. L'instruction de la ligne 12 additionne tous les entiers consécutifs de 1 à 7 (à l'exception de 3 et
5, qui ne figurent pas dans la liste et sont ignorés dans la boucle for ).
Pour sauter ces deux nombres, l'expression (i==3) || (i==5) est évalué dans l' instruction if de la
ligne 10. Si l'expression est évaluée à 1 (c'estàdire que la valeur de i est égale à 3 ou 5), l'
instruction continue de la ligne 11 est exécutée, ce qui provoque l'opération de somme de la ligne 12
doit être ignorée et une autre itération doit être lancée à l' instruction for . De cette façon, vous
obtenez la somme des valeurs entières de 1, 2, 4, 6 et 7, mais sautez 3 et 5, automatiquement en
utilisant une boucle for .
Après la boucle for , la valeur de sum, 20, est affichée à l'écran par l' appel printf() dans l'instruction
de la ligne 14.
La déclaration goto
Ce livre ne serait pas complet sans mentionner l' instruction goto , bien que je ne vous recommande
pas d'utiliser l' instruction goto . La principale raison pour laquelle l' instruction goto est déconseillée
est que son utilisation risque de rendre le programme C peu fiable et difficile à déboguer.
Les programmeurs sont souvent tentés d'utiliser l' instruction goto , surtout s'ils ont utilisé d'autres
langages sans le riche ensemble d'instructions de branchement conditionnel structuré fournies par
C. Le fait est que toute utilisation de goto peut être entièrement évitée en utilisant les autres
instructions de branchement.
Si rien d'autre, vous devez savoir ce qu'est une instruction goto afin que vous puissiez correctement grincer des
dents lorsque vous en voyez une dans le code de quelqu'un d'autre.
Machine Translated by Google
instruction1 ;
instruction2 ;
.
.
.
aller au nom de l'étiquette ;
Ici labelname est un nom d'étiquette qui indique à l' instruction goto où sauter. Vous devez
placer labelname à deux endroits : l'un est à l'endroit où l' instruction goto va sauter (notez
qu'un deuxpoints doit suivre le nom de l'étiquette), et l'autre est l'endroit suivant le motclé
goto .
L'étiquette de l' instruction goto vers laquelle sauter peut apparaître avant ou après l'instruction.
dix
L'une des meilleures choses à propos du C est qu'il encourage la programmation
structurée. Les programmes doivent agir de manière prévisible et leur comportement doit
être raisonnablement évident à la simple lecture du code source.
Bien sûr, l'un des autres avantages du C est que le langage luimême n'applique pas
cet idéal. C'est à vous, le programmeur, d'utiliser les outils qui vous sont donnés pour
écrire un code propre, élégant, lisible et structuré.
Dans ce chapitre, nous avons vu les instructions break, continue et goto.
L'utilisation inappropriée de ces instructions de branchement peut conduire à ce que l'on
appelle le "code spaghetti". (Si vous imprimez le code source et dessinez des flèches sur
la page pour indiquer le flux d'exécution, vous vous retrouverez avec un dessin de
spaghetti.) Lorsque l'exécution d'un programme saute de manière imprévisible, cela le
rend très difficile (ou pour un grand projet complexe, souvent presque impossible) pour
déterminer le comportement prévu ou réel d'un pro
gramme.
170 Heure 10
Résumé
Dans cette leçon, vous avez appris les déclarations et motsclés importants suivants pour le branchement
conditionnel et le bouclage en C :
• Une tâche importante d'un programme est de demander à l'ordinateur de sauter à différents
parties du code selon les conditions de branche spécifiées.
• L' instruction if est une instruction très importante pour le branchement conditionnel en C. • L'
instruction if peut être imbriquée pour prendre une série de décisions liées dans votre
programme.
• L' instruction ifelse est une extension de l' instruction if . • L' instruction
switch vous aide à rendre votre programme plus lisible lorsqu'il y a plus que quelques décisions liées à
prendre dans votre code. • Le motclé case , suivi de deuxpoints et d'une valeur constante intégrale,
est utilisé comme étiquette dans l' instruction switch . Par défaut : l' étiquette est utilisée à la fin d'un
commutateur
• L' instruction break peut être utilisée pour quitter la construction switch ou une boucle (généralement, une
boucle infinie).
• L' instruction continue est utilisée pour vous permettre de rester dans une boucle tout en sautant
quelques déclarations.
Dans la leçon suivante, vous découvrirez un concept très important : les pointeurs.
Questions et réponses
R L' instruction if n'accepte qu'une seule expression pour contenir les critères conditionnels. Lorsque
l'expression donne une valeur différente de zéro (c'estàdire que les conditions sont remplies), les
instructions contrôlées par l' instruction if sont exécutées. Sinon, ces instructions sont ignorées et
l'instruction suivante suivant le bloc d'instructions if est exécutée.
à sa piste d'origine après l'exécution des instructions contrôlées par else . En d'autres termes, l'
instruction if permet d'exécuter ou d'ignorer entièrement un seul bloc d'instructions, tandis que l'
instruction ifelse exécute l'un des deux blocs d'instructions sous le contrôle de l' instruction ifelse .
Q Pourquoi avezvous normalement besoin d'ajouter l' instruction break dans le commutateur
déclaration?
A Lorsque l'un des cas dans l' instruction switch est sélectionné, le contrôle du programme se branche sur
le cas et exécute toutes les instructions dans le cas sélectionné et le
reste des cas qui le suivent. Par conséquent, vous pourriez obtenir plus de résultats que prévu.
Pour indiquer à l'ordinateur d'exécuter uniquement les instructions à l'intérieur d'un cas
sélectionné, vous pouvez placer une instruction break à la fin du cas afin que le flux de contrôle
du programme quitte la construction switch après que les instructions dans le cas sont
réalisé. dix
Q Que peut faire l' instruction continue dans une boucle ?
A Lorsque l' instruction continue à l' intérieur d'une boucle est exécutée, le contrôle du programme est
branché à la fin de la boucle afin que l'instruction de contrôle while ou for puisse être exécutée et
qu'une autre itération puisse être lancée si l'expression conditionnelle est toujours valable. À l'intérieur
de la boucle, toutes les instructions suivant l' instruction continue seront ignorées à chaque exécution
de l'instruction continue .
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à répondre
aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante.
Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses aux
questions et exercices du quiz ».
Questionnaire
1. Étant donné x = 0, les opérations arithmétiques à l'intérieur de l' instruction if suivante seront elles
effectué ? si
(x != 0) y =
123 / x + 456 ;
172 Heure 10
x=1;
for (i=2; i<10; i++){ if (i%3
== 0) continue ; x +=
je ;
Des exercices
1. Réécrivez le programme du Listing 10.1. Cette fois, utilisez l'expression logique i%6 ==
0 dans l' instruction if .
3. Écrivez un programme pour lire des caractères à partir des E/S standard. Si les caractères sont A, B
et C, affichez leurs valeurs numériques à l'écran. (L' instruction switch est obligatoire.)
4. Écrivez un programme qui continue à lire les caractères de l'entrée standard jusqu'à ce que le
caractère q soit entré.
PARTIE III
Pointeurs et tableaux
Heure
11 Comprendre les pointeurs
HEURE 11
Comprendre les pointeurs
Les devoirs du pointeur étaient de désigner, en appelant leurs noms, ceux de la congrégation
qui devraient prendre note d'un point soulevé dans le sermon.
Vous avez découvert de nombreux types de données, opérateurs, fonctions et boucles C importants
au cours des 10 dernières heures. Dans cette leçon, vous découvrirez l'une des fonctionnalités les
plus importantes et les plus puissantes des pointeurs C:. Les sujets abordés pendant cette heure
sont
• Variables de pointeur
Le concept d'indirection • La
d'adresse de • L'opérateur de
déréférencement
Plus d'exemples d'application de pointeurs seront démontrés dans les prochaines heures du livre,
en particulier dans l'heure 16, "Applying Pointers".
Machine Translated by Google
176 Heure 11
Au lieu d'attribuer des valeurs directement aux variables, vous pouvez manipuler indirectement une variable
en créant une variable appelée pointeur, qui contient l'adresse mémoire d'une autre variable.
Alors, pourquoi estce si important ? Pour commencer, utiliser l'adresse mémoire de vos données est souvent
le moyen le plus rapide et le plus simple d'y accéder. Il y a beaucoup de choses qui sont difficiles, voire
carrément impossibles, à faire sans pointeurs, comme l'allocation dynamique de mémoire, la transmission de
grandes structures de données entre les fonctions, voire la communication avec le matériel de votre ordinateur.
En fait, vous avez déjà utilisé un pointeur — dans l'heure 1, de ce livre « Faire le premier pas » ! Vous
souvenezvous de la chaîne « Salut, voisin ! C'est mon premier programme C.\n" ? Une chaîne est en
fait un tableau, qui est luimême une sorte de pointeur.
Il y a beaucoup plus de discussions plus loin dans ce livre sur les tableaux, l'allocation de mémoire et les
merveilleuses choses que vous pouvez faire avec les pointeurs. Pour l'instant, la première étape consiste à
comprendre ce qu'est un pointeur et comment l'utiliser dans vos programmes.
D'après la définition d'un pointeur, vous savez deux choses : premièrement, qu'un pointeur est une variable,
vous pouvez donc affecter différentes valeurs à une variable de pointeur, et deuxièmement, que la valeur
contenue par un pointeur doit être une adresse qui indique la emplacement d'une autre variable dans la
mémoire. C'est pourquoi un pointeur est aussi appelé une variable d'adresse.
Chaque emplacement mémoire doit avoir une adresse unique afin que l'ordinateur puisse lire ou écrire dans
l'emplacement mémoire sans aucune confusion. Ceci est similaire au concept selon lequel chaque maison
dans une ville doit avoir une adresse unique.
Lorsqu'une variable est déclarée, un morceau de mémoire inutilisé sera réservé pour la variable, et
l'adresse unique de la mémoire sera associée au nom de la variable. L'adresse associée au nom de la
variable est généralement appelée la valeur de gauche de la variable.
Machine Translated by Google
Ensuite, lorsqu'une valeur est affectée à la variable, la valeur est stockée dans l'emplacement de mémoire réservé
en tant que contenu. Le contenu est aussi appelé la bonne valeur de la variable.
Par exemple, une fois que la variable entière x est déclarée et affectée à une valeur comme celleci :
entier
x;x=7;
Valeur correcte : 7
Ici, la valeur de gauche, 1000, est l'adresse de l'emplacement mémoire réservé pour x. La bonne valeur, 7, est le
contenu stocké dans l'emplacement mémoire. Notez que selon les ordinateurs et les systèmes d'exploitation, la
valeur de gauche de x peut être différente d'une machine à l'autre.
Vous pouvez imaginer que la variable x est la boîte aux lettres devant votre maison, qui a l'adresse (normalement
le numéro de la rue) 1000. La bonne valeur, 7, peut être considérée comme une lettre livrée à la boîte aux lettres.
Notez que lorsque votre programme C est compilé et qu'une valeur est affectée à une variable, le compilateur
C doit vérifier la valeur de gauche de la variable. Si le compilateur ne trouve pas la valeur de gauche, il émettra un
11
message d'erreur indiquant que la variable n'est pas définie dans votre programme. C'est pourquoi, en C, vous devez
déclarer une variable avant de pouvoir l'utiliser.
(Imaginez un facteur se plaignant de ne pas pouvoir déposer les lettres qui vous sont adressées parce que vous
n'avez pas encore construit de boîte aux lettres.)
En utilisant la valeur de gauche d'une variable, le compilateur C peut facilement localiser le stockage de mémoire
approprié réservé à une variable, puis lire ou écrire la valeur de droite de la variable.
entier long x ;
entier long *y ;
y = &x;
affecte l'adresse de la variable entière longue x à une variable pointeur, y. (Plus d'informations à ce sujet et sur la
signification de *y seront discutées plus loin dans ce chapitre.)
Machine Translated by Google
178 Heure 11
Le Listing 11.1 montre un autre exemple d'obtention d'adresses (c'estàdire de valeurs de gauche)
de variables.
TAPER
LISTE 11.1 Obtention des valeurs de gauche des variables
caractère
c ; entier
x ; flotter y ;
15 : 16 : 17 :
18 :
19 :
20 : }
Une fois le fichier exécutable (11L01.exe) de ce programme créé et exécuté sur mon ordinateur, la sortie
suivante s'affiche à l'écran :
Vous pouvez obtenir des résultats différents, en fonction de votre ordinateur et de votre
système d'exploitation, et en particulier en fonction de la situation de la mémoire de votre
ordinateur lorsque vous exécutez le programme.
c : adresse=0x1AF4, contenu=@ x :
SORTIR
adresse=0x1AF2, contenu=32557 y :
adresse=0x1AF6, contenu=0.00 c :
adresse=0x1AF4, contenu=A x :
adresse=0x1AF2, contenu=7 y : adresse=
0x1AF6, contenu=123,45
UNE ANALYSE
Comme vous pouvez le voir dans le Listing 11.1, il y a trois variables, c, x et y, déclarées
respectivement aux lignes 6 à 8.
Machine Translated by Google
Notez que le spécificateur de format %p est utilisé dans la fonction printf() de la ligne 10 pour afficher
l'adresse produite par &c.
De même, les lignes 11 et 12 impriment les adresses de x et y, ainsi que le contenu de x et y. Dans la
première partie de la sortie, vous voyez que les adresses de c, x et y sont 0x1AF4, 0x1AF2 et 0x1AF6.
Mon ordinateur a imprimé ces adresses au format hexadécimal.
Cependant, le spécificateur de format %p ne garantit pas l'impression des adresses au format
hexadécimal, juste pour convertir les adresses en une séquence de caractères imprimables. Vous
devriez consulter le manuel de votre compilateur C pour savoir à quel format vous attendre. Comme ces
trois variables n'ont pas encore été initialisées, le contenu contenu dans leurs emplacements mémoire
y est laissé depuis la dernière écriture en mémoire.
Cependant, après les initialisations effectuées aux lignes 13 à 15, les emplacements mémoire
réservés aux trois variables ont le contenu des valeurs initiales. Lignes 16 à 18 dis
lire les adresses et le contenu de c, x et y après l'initialisation.
Vous pouvez voir dans la deuxième partie de la sortie, le contenu de c, x et y sont maintenant 'A', 7 11
et 123.45, respectivement, avec les mêmes adresses mémoire.
Le spécificateur de format %p utilisé dans la fonction printf() est pris en charge par la norme
ANSI. Si, d'une manière ou d'une autre, votre compilateur ne prend pas en charge %p, vous
pouvez essayer d'utiliser %u ou %lu dans la fonction printf() pour convertir et imprimer une valeur
de gauche (c'estàdire une adresse).
De plus, les adresses imprimées par les exemples de cette leçon sont obtenues en exécutant les
exemples sur ma machine. Les valeurs peuvent être différentes de ce que vous pouvez obtenir
en exécutant les exemples sur votre machine. En effet, l'adresse d'une variable peut varier d'un
type d'ordinateur à l'autre.
180 Heure 11
Ici datatype spécifie le type de données vers lequel pointe le pointeur. nompointeur est le nom de la
variable pointeur, qui peut être n'importe quel nom de variable valide en C.
Notez que juste avant le nom du pointeur se trouve un astérisque *, qui indique que la variable est un
pointeur. Lorsque le compilateur voit l'astérisque dans la déclaration, il note que la variable peut être
utilisée comme pointeur.
Le programme du Listing 11.2 montre comment déclarer des pointeurs et leur affecter des valeurs.
TAPER
LISTE 11.2 Déclarer et attribuer des valeurs aux pointeurs
c = 'A' ; x
8 : 9 : 10 : 11=: 7
;y=
12 : 123,45 ;
13: printf("c : adresse=%p, contenu=%c\n", &c, c); printf("x :
14: adresse=%p, contenu=%d\n", &x, x); printf("y : adresse=%p,
contenu=%5.2f\n", &y, y); ptr_c = &c; printf(“ptr_c : adresse=%p,
contenu=%p\n", &ptr_c, ptr_c); printf("*ptr_c => %c\n", *ptr_c); ptr_x =
15 : 16 : 17 : &x; printf("ptr_x : adresse=%p, contenu=%p\n", &ptr_x, ptr_x); printf("*ptr_x =>
%d\n", *ptr_x); ptr_y = &y; printf("ptr_y : adresse=%p, contenu=%p\n", &ptr_y, ptr_y);
printf("*ptr_y => %5.2f\n", *ptr_y); renvoie 0 ;
18h19h20h21h
22:
23:
24:
25 :
26 : }
Machine Translated by Google
J'obtiens la sortie suivante affichée à l'écran après avoir exécuté le fichier exécutable
11L02.exe depuis ma machine :
c : adresse=0x1B38, contenu=A
SORTIR x : adresse=0x1B36, contenu=7 y :
adresse=0x1B32, contenu=123,45 ptr_c :
adresse=0x1B30, contenu=0x1B38 *ptr_c =>
A ptr_x : adresse=0x1B2E, contenu=0x1B36
*ptr_x => 7 ptr_y : adresse=0x1B2C,
contenu=0x1B32 *ptr_y => 123,45
UNE ANALYSE
Dans le Listing 11.2, il y a trois variables, c, x et y, et trois variables de pointeur, ptr_c, ptr_x
et ptr_y, déclarées respectivement aux lignes 6 à 8.
Les instructions des lignes 10 à 12 initialisent les trois variables c, x et y. Ensuite, les lignes 13 à 15
impriment les adresses ainsi que le contenu des trois variables.
A la ligne 16, la valeur de gauche de la variable caractère c est affectée à la variable pointeur
ptr_c. La sortie faite par l'instruction de la ligne 17 montre que la variable de pointeur ptr_c contient
l'adresse de c. En d'autres termes, le contenu (c'estàdire la valeur de droite) de ptr_c est l'adresse
(c'estàdire la valeur de gauche) de c. 11
Ensuite, à la ligne 18, la valeur référencée par le pointeur *ptr_c est imprimée. La sortie prouve
que le pointeur *ptr_c pointe vers l'emplacement mémoire de c.
La ligne 19 affecte la valeur de gauche de l'entier x à la variable de pointeur d'entier ptr_x. Les
instructions des lignes 20 et 21 impriment la valeur gauche et la valeur droite de la variable de
pointeur ptr_x, ainsi que la valeur référencée par le pointeur *ptr_x.
Les instructions des lignes 16, 19 et 22 vous montrent comment affecter la valeur d'une variable à
une autre, de manière indirecte. En d'autres termes, la valeur gauche d'une variable peut être
affectée à une autre variable afin que cette dernière puisse être utilisée comme variable pointeur
pour obtenir la valeur droite de la première. Dans ce cas, le nom de la variable et le pointeur font
référence au même emplacement mémoire. Par conséquent, si le nom de la variable ou le pointeur
est utilisé dans une expression pour modifier le contenu de l'emplacement mémoire, le contenu de
l'emplacement mémoire a également changé pour l'autre.
Pour vous aider à comprendre l'indirection de l'attribution de valeurs, la figure 11.1 montre l'image
mémoire des relations entre c et ptr_c, x et ptr_x, et y et ptr_y, sur la base de la sortie obtenue sur
ma machine.
Machine Translated by Google
182 Heure 11
FIGURE 11.1 .
.
L'image mémoire des
.
variables et leur ptr_y 0x1B2C
pointeurs. 0x1B32
ptr_x 0x1B2E
0x1B36
ptr_c 0x1B30 *ptr_y
0x1B38
Oui 0x1B32
*ptr_x
123,45
X
0x1B36
7 *ptr_c
c 0x1B38
'UN'
.
.
.
Par exemple, dans le programme présenté dans le Listing 11.2, après que l'adresse de la
variable caractère c est assignée à la variable pointeur ptr_c, l'expression *ptr_c fait référence à
la valeur contenue par c. Par conséquent, vous pouvez utiliser l' expression *ptr_c , au lieu d'utiliser
directement la variable c , pour obtenir la valeur de c.
De même, étant donné une variable entière x et x = 1234, vous pouvez déclarer une variable de
pointeur entier, ptr_x, par exemple, et affecter la valeur gauche (adresse) de x à ptr_x, c'està
dire ptr_x = &x. Ensuite, l'expression *ptr_x produit 1234, qui est la bonne valeur (contenu) de x.
Pointeurs nuls
Un pointeur est dit pointeur nul lorsque sa valeur droite est 0. N'oubliez pas qu'un pointeur nul ne peut jamais pointer
vers des données valides. Pour cette raison, vous pouvez tester un pointeur pour voir s'il est affecté à 0 ; si c'est le cas,
vous savez qu'il s'agit d'un pointeur nul et qu'il n'est pas valide.
Pour définir un pointeur nul, affectez simplement 0 à la variable de pointeur. Par example:
char *ptr_c;
entier *ptr_int;
ptr_c = ptr_int = 0 ;
Ici , ptr_c et ptr_int deviennent des pointeurs nuls après que la valeur entière de 0 leur ait été affectée.
Vous verrez les applications des pointeurs nuls utilisés dans les instructions et les tableaux de flux de contrôle plus loin
dans ce livre.
Cette section vous montre que vous pouvez écrire une nouvelle valeur dans l'emplacement mémoire d'une variable à
l'aide d'un pointeur contenant la valeur gauche de la variable. Le Listing 11.3 montre un exemple.
TAPER LISTE 11.3 Modification des valeurs de variables via des pointeurs
char c, *ptr_c;
c = 'A' ;
printf("c : adresse=%p, contenu=%c\n", &c, c); ptr_c = &c;
printf(“ptr_c : adresse=%p, contenu=%p\n", &ptr_c, ptr_c);
printf("*ptr_c => %c\n", *ptr_c); *ptr_c = 'B'; printf(“ptr_c : adresse=%p,
contenu=%p\n", &ptr_c, ptr_c);
7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 :
continue
Machine Translated by Google
184 Heure 11
Après avoir exécuté le fichier exécutable 11L03.exe sur ma machine, j'obtiens la sortie suivante
affichée à l'écran :
c : adresse=0x1828, contenu=A
SORTIR ptr_c : adresse=0x1826, contenu=0x1828
*ptr_c => A ptr_c : adresse=0x1826,
contenu=0x1828 *ptr_c => B c :
adresse=0x1828, contenu=B
Une variable char , c, et une variable pointeur char , ptr_c, sont déclarées à la ligne 6 du
UNE ANALYSE
Listing 11.3.
La variable c est initialisée avec 'A' à la ligne 8, qui est imprimée, avec l'adresse de la variable,
par la fonction printf() à la ligne 9.
À la ligne 10, la variable de pointeur ptr_c reçoit la valeur de gauche (adresse) de c. Il n'est pas
surprenant de voir la sortie imprimée par les instructions des lignes 11 et 12, où la valeur droite de ptr_c
est la valeur gauche de c, et le pointeur *ptr_c pointe sur la valeur droite de c.
À la ligne 13, l'expression *ptr_c = 'B' demande à l'ordinateur d'écrire 'B' à l'emplacement pointé par
le pointeur ptr_c. La sortie imprimée par l'instruction à la ligne 15 prouve que le contenu de
l'emplacement mémoire pointé par ptr_c est mis à jour. L'instruction de la ligne 14 imprime les valeurs
gauche et droite de la variable de pointeur ptr_c et montre que ces valeurs restent les mêmes. Comme
vous le savez, l'emplacement pointé par ptr_c est celui où réside la variable caractère c . Par
conséquent, l'expression *ptr_c = 'B' met à jour le contenu (c'estàdire la bonne valeur) de la variable c
en 'B'. Pour le prouver, l'instruction de la ligne 16 affiche les valeurs gauche et droite de c à l'écran.
Effectivement, la sortie montre que la bonne valeur de c a été modifiée.
Le programme du Listing 11.4 montre un autre exemple de pointage vers la même chose avec
plusieurs pointeurs.
LISTE 11.4 Pointer vers le même emplacement mémoire avec plusieurs pointeurs
TAPER
entier
x ; entier *ptr_1, *ptr_2, *ptr_3 ;
x = 1234 ;
printf("x : adresse=%p, contenu=%d\n", &x, x); ptr_1 = &x;
8 : 9 : 10 : 11printf("ptr_1
: : adresse=%p, contenu=%p\n", &ptr_1, ptr_1);
12 :
13: printf("*ptr_1 => %d\n", *ptr_1); ptr_2 = &x;
14: printf("ptr_2 : adresse=%p, contenu=%p\n",
&ptr_2, ptr_2);
printf("*ptr_2 => %d\n", *ptr_2); ptr_3 =
15 : 16 : 17 ptr_1
: ; printf("ptr_3 : adresse=%p, contenu=%p\n",
&ptr_3, ptr_3);
11
printf("*ptr_3 => %d\n", *ptr_3); renvoie 0 ;
18h19h20h21h}
La sortie suivante s'affiche à l'écran en exécutant le fichier exécutable 11L04.exe sur ma machine
(notez que vous pouvez obtenir différentes valeurs d'adresse en fonction de votre système) :
Comme indiqué dans le Listing 11.4, la ligne 6 déclare une variable entière, x, et
UNE ANALYSE
la ligne 7 déclare trois variables de pointeur entier, ptr_1, ptr_2 et ptr_3.
L'instruction de la ligne 10 imprime les valeurs gauche et droite de x. Sur ma machine, la valeur
gauche (adresse) de x est 0x1838. La bonne valeur (contenu) de x est 1234, qui est la valeur
initiale attribuée à x à la ligne 9
Machine Translated by Google
186 Heure 11
La ligne 11 affecte la valeur gauche de x à la variable de pointeur ptr_1 afin que ptr_1 puisse être utilisé pour faire
référence à la valeur droite de x. Pour vous assurer que la variable de pointeur ptr_1 contient maintenant l'adresse
de x, la ligne 12 imprime la valeur droite de ptr_1, ainsi que sa valeur gauche. La sortie montre que ptr_1 contient
l'adresse de x, 0x1838. Ensuite, la ligne 13 imprime la valeur 1234, qui est référencée par l' expression *ptr_1 .
Notez que l'astérisque * dans l'expression est l'opérateur de déréférencement
À la ligne 14, l' expression *ptr_2 = &x affecte la valeur gauche de x à une autre variable de pointeur, ptr_2 ; c'est
àdire que la variable de pointeur ptr_2 est maintenant liée à l'adresse de x. L'instruction de la ligne 16 affiche
l'entier 1234 à l'écran en utilisant l'opérateur de déréférencement * et son opérande, ptr_2. En d'autres termes,
l'emplacement mémoire de x est désigné par le second pointeur *ptr_2.
À la ligne 17, la variable de pointeur ptr_3 reçoit la bonne valeur de ptr_1. Comme ptr_1 contient maintenant
l'adresse de x, l'expression ptr_3 = ptr_1 est équivalente à ptr_3 = &x.
Ensuite, à partir de la sortie faite par les instructions des lignes 18 et 19, vous voyez à nouveau l'entier 1234
à l'écran. Cette fois, l'entier est référencé par le troisième pointeur, ptr_3.
Résumé
Dans cette leçon, vous avez appris les concepts très importants suivants sur les pointeurs en C :
• Un pointeur est une variable dont la valeur pointe vers une autre variable. • Une
• L'opérateur d'adresse de (&) peut être utilisé pour obtenir la valeur gauche (adresse) de
une variable.
• L'astérisque (*) dans une déclaration de pointeur indique au compilateur que la variable est un
variable de pointeur.
• L'opérateur de déréférencement (*) est un opérateur unaire ; en tant que tel, il ne nécessite que
un opérande.
• L' expression *ptr_name est évaluée à la valeur pointée par la variable de pointeur
ptr_name, où ptr_name peut être n'importe quel nom de variable valide en C.
• Si la valeur droite de la variable de pointeur a reçu la valeur 0, le pointeur est un pointeur nul. Un pointeur
nul ne peut pas pointer vers des données valides.
• Vous pouvez mettre à jour la valeur d'une variable référencée par une variable pointeur.
• Plusieurs pointeurs peuvent pointer sur le même emplacement d'une variable dans la mémoire.
Machine Translated by Google
Vous verrez plus d'exemples d'utilisation des pointeurs dans le reste du livre.
Dans la leçon suivante, vous découvrirez un type d'agrégat, un tableau, qui est étroitement lié aux pointeurs en C.
Questions et réponses
A La valeur de gauche est l'adresse d'une variable et la valeur de droite est le contenu stocké
dans l'emplacement mémoire d'une variable. Il existe deux façons d'obtenir la bonne valeur d'une variable :
utiliser directement le nom de la variable ou utiliser la valeur de gauche de la variable et l'opérateur de
déréférencement pour faire référence à l'emplacement de la bonne valeur. La deuxième voie est aussi appelée
voie indirecte.
A En utilisant l'opérateur d'adresse, &. Par exemple, étant donné une variable entière x, l' expression &x s'évalue
à l'adresse de x. Pour imprimer l'adresse de x, vous pouvez utiliser le spécificateur de format %p dans la
fonction printf() .
R Avant cette heure, le seul moyen que vous connaissiez pour lire ou écrire dans une variable était d'invoquer
11
directement la variable. Par exemple, si vous vouliez écrire un nombre décimal, 16, dans une variable entière
x, vous pourriez utiliser l'instruction x = 16;.
Comme vous l'avez appris au cours de cette heure, C vous permet d'accéder à une variable d'une autre
manière, en utilisant des pointeurs. Par conséquent, pour écrire 16 dans x, vous pouvez d'abord déclarer un
pointeur entier (ptr) et affecter la valeur gauche (adresse) de x à ptr, c'estàdire ptr = &x;. Ensuite, au lieu
d'exécuter l'instruction x = 16;, vous pouvez utiliser une autre instruction :
*ptr = 16 ;
Ici, le pointeur *ptr fait référence à l'emplacement mémoire réservé par x, et le contenu stocké dans l'emplacement
mémoire est mis à jour à 16 après l'exécution de l'instruction. Donc, vous voyez, utiliser des pointeurs pour
accéder aux emplacements mémoire des variables est un moyen d'indirection.
R Non. Un pointeur nul ne peut pas pointer vers des données valides. Cela est dû au fait que la valeur contenue
par un pointeur nul a été définie sur 0. Vous verrez des exemples d'utilisation de pointeurs nuls dans des
tableaux, des chaînes et une allocation de mémoire plus loin dans le livre.
Machine Translated by Google
188 Heure 11
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses
aux questions et exercices du quiz ».
Questionnaire
2. Dans les expressions suivantes, quel astérisque (*) est un opérateur de déréférencement, et
lequel est un opérateur de multiplication ?
• *ptr
•x * Oui
• Oui
*= x + 5
• *y *= *x + 5
3. Étant donné que x = 10, l'adresse de x est 0x1A38, et ptr_int = &x, qu'estce qui
ptr_int et *ptr_int produisent respectivement ?
4. Étant donné que x = 123, et ptr_int = &x après l'exécution de *ptr_int = 456,
que contient x ?
Des exercices
1. Étant donné trois variables entières, x = 512, y = 1024 et z = 2048, écrivez un programme
pour imprimer leurs valeurs de gauche ainsi que leurs valeurs de droite.
2. Écrivez un programme pour mettre à jour la valeur de la variable double flt_num de 123,45 à 543,21
en utilisant un double pointeur.
3. Étant donné une variable de caractère ch et ch = 'A', écrivez un programme pour mettre à jour la valeur
de ch à la décimale 66 en utilisant un pointeur.
4. Étant donné que x=5 et y=6, écrivez un programme pour calculer la multiplication des deux entiers et
imprimez le résultat, qui est enregistré dans x, le tout dans le sens de l'indirection (c'estàdire en
utilisant des pointeurs).
Machine Translated by Google
HEURE 12
Comprendre les tableaux
Rassemblez les fragments qui restent, que rien ne soit perdu.
—Jean 6:12
Dans la leçon de la dernière heure, vous avez appris les pointeurs et le concept d'indirection.
Dans cette leçon, vous découvrirez les tableaux, qui sont des collections d'éléments de données
similaires et sont étroitement liés aux pointeurs. Les principaux sujets abordés dans cette leçon
sont
et tableaux • Tableaux de
caractères • Tableaux
multidimensionnels • Tableaux
non dimensionnés
Machine Translated by Google
190 Heure 12
Un tableau est une collection de variables qui sont du même type de données. Chaque élément d'un tableau est
appelé un élément. Tous les éléments d'un tableau sont référencés par le nom du tableau et sont stockés dans un
ensemble d'emplacements de mémoire consécutifs et adjacents.
Ici datatype est le spécificateur de type qui indique le type de données du tableau déclaré. ArrayName est le nom
du tableau déclaré. ArraySize définit le nombre d'éléments que le tableau peut contenir. Notez que les crochets
([ et ]) sont nécessaires pour déclarer un tableau. La paire de parenthèses ([ et ]) est également appelée opérateur
d'indice de tableau.
int tableau_int[8] ;
où int spécifie le type de données du tableau dont le nom est array_int. La taille du tableau est 8, ce qui signifie
que le tableau peut stocker huit éléments (c'estàdire des entiers dans ce cas).
En C, vous devez déclarer explicitement un tableau, comme vous le faites pour d'autres variables, avant de
pouvoir l'utiliser.
Tableaux d'indexation
Après avoir déclaré un tableau, vous pouvez accéder à chacun des éléments du tableau séparément.
jour de l'omble[7] ;
Vous pouvez accéder aux éléments du tableau de jour les uns après les autres. Pour ce faire, vous utilisez le nom
du tableau dans une expression suivi d'un nombre, appelé index, entre crochets.
La chose importante à retenir est que tous les tableaux en C sont indexés à partir de 0. En d'autres termes, l'index
du premier élément d'un tableau est 0, et non 1. Par conséquent, le premier élément du tableau de jour est jour[0 ].
Comme il y a 7 éléments dans le tableau day , le dernier élément est day[6], pas day[7].
Machine Translated by Google
Les sept éléments du tableau ont les expressions suivantes : jour[0], jour[1], jour[2], jour[3],
jour[4], jour[5] et jour[6].
Étant donné que ces expressions font référence aux éléments du tableau, elles sont parfois appelées
références d'éléments de tableau.
Par exemple, vous pouvez initialiser le premier élément du tableau de jour, qui a été déclaré dans la
dernière section, comme ceci :
jour[0] = 'S' ;
De même, l'instruction day[1] = 'M'; affecte 'M' au deuxième élément, jour[1], dans le tableau.
La deuxième façon d'initialiser un tableau consiste à initialiser tous les éléments du tableau ensemble. Par
exemple, l'instruction suivante initialise un tableau d'entiers, arInteger :
Ici, les entiers à l'intérieur des accolades ({ et }) sont affectés de manière correspondante aux
éléments du tableau arInteger. Autrement dit, 100 est attribué au premier élément (arInteger[0]), 8 au
deuxième élément (arInteger[1]), 3 au troisième (arInteger[2]), etc.
int je ;
int liste_int[10] ;
192 Heure 12
Comme vous pouvez le voir dans le Listing 12.1, il existe un tableau d'entiers, appelé list_int,
UNE ANALYSE
qui est déclaré à la ligne 7. Le tableau list_int contient 10 éléments.
Les lignes 9 à 12 constituent une boucle for qui itère 10 fois. L'instruction de la ligne 10 initialise
list_int[i], le ième élément du tableau list_int, avec le résultat de l'expression i + 1.
vous pouvez ensuite calculer le nombre total d'octets du tableau par l'expression suivante :
Ici datatype est le type de données du tableau ; ArraySize spécifie le nombre total d'éléments que le
tableau peut prendre. Cette expression évalue le nombre total d'octets pris par le tableau.
Une autre façon de calculer le nombre total d'octets d'un tableau est plus simple ; il utilise
l'expression suivante :
sizeof(nomtableau)
Le programme du Listing 12.2 montre comment calculer l'espace mémoire occupé par un tableau.
Machine Translated by Google
TAPER
LISTE 12.2 Calcul de la taille d'un tableau
Après avoir exécuté l'exécutable 12L02.exe, j'ai la sortie suivante affichée sur l'écran de mon
ordinateur :
La taille de int est longue de 2 octets.
SORTIR
Le tableau de 10 entiers a un total de 20 octets
L'adresse du premier élément : 0x1806 L'adresse
du dernier élément : 0x1818
UNE ANALYSE Notez que vous pouvez obtenir des valeurs d'adresse différentes lorsque vous exécutez
le programme du Listing 12.2 sur votre machine. Cependant, la différence entre l'adresse de
le premier élément et l'adresse du dernier élément doivent être égaux au nombre total d'octets du
tableau.
12
Dans le Listing 12.2, il y a un tableau d'entiers, list_int, qui est déclaré à la ligne 7. L'espace mémoire
total occupé par le tableau est le résultat de la multiplication de la taille de int et du nombre total
d'éléments dans le tableau. Comme déclaré dans cet exemple, il y a un total de 10 éléments dans le
tableau list_int.
La déclaration de la ligne 10 imprime la taille de int sur ma machine. Vous pouvez voir à partir de la
sortie que chaque élément entier du tableau prend 2 octets. Par conséquent, l'espace mémoire total
(en octets) pris par le tableau est de 10 * 2. En d'autres termes, l'instruction de la ligne 9 attribue la
valeur de 20, produite par l'expression sizeof (int) * 10, à la variable entière total_byte . La ligne 11
affiche alors la valeur contenue par la variable total_byte à l'écran.
Pour prouver que le tableau prend l'espace mémoire consécutif de 20 octets, l'adresse du premier
élément du tableau est imprimée par l'instruction de la ligne 12. Notez que l'esperluette (&), qui a été
introduite comme adresse de l'opérateur de l'heure 11, "Comprendre les pointeurs", est utilisé à la
ligne 12 pour obtenir l'adresse du premier élément,
Machine Translated by Google
194 Heure 12
list_int[0], dans le tableau. Ici, l'adresse du premier élément est l'adresse de début du tableau. À partir de la
sortie, vous pouvez voir que l'adresse de l' élément list_int[0] est 0x1806 sur ma machine.
Ensuite, l' expression &list_int[9] de la ligne 13 donne l'adresse de l'élément final du tableau, qui est 0x1818
sur ma machine. Ainsi, la distance entre le dernier élément et le premier élément est de 0x1818–0x1806, soit
18 octets.
Comme mentionné précédemment dans le livre, l'hexadécimal est un système de numérotation à base de
16. Nous savons que 0x1818 moins 0x1806 produit 0x0012 (c'estàdire 0x12). Alors 0x12 en hexadécimal est
égal à 1*16 + 2 ce qui donne 18 en décimal.
Étant donné que chaque élément prend 2 octets et que l'adresse de l'élément final est le début de cet élément
de 2 octets, le nombre total d'octets pris par le tableau list_int est en effet de 20 octets. Vous pouvez le calculer
d'une autre manière : la distance entre le dernier élément et le premier élément est de 18 octets. Le nombre total
d'octets pris par le tableau doit être compté du tout premier octet du premier élément au dernier octet du dernier
élément. Par conséquent, le nombre total d'octets pris par le tableau est égal à 18 plus 2, soit 20 octets.
La figure 12.1 vous montre l'espace mémoire occupé par le tableau list_int
FIGURE 12.1
L'espace mémoire
occupé par le tableau &list_int[0] 0x1806 1 octet
list_int. 2 octets
1 octet
1 octet
2 octets
1 octet
Tableaux et pointeurs
Comme je l'ai mentionné plus tôt dans cette heure, les pointeurs et les tableaux ont une relation étroite en C.
En fait, vous pouvez créer un pointeur qui fait référence au premier élément d'un tableau en affectant simplement
Machine Translated by Google
insérant le nom du tableau à la variable de pointeur. Si un tableau est référencé par un pointeur,
les éléments du tableau sont accessibles à l'aide du pointeur.
Comme l'adresse du premier élément du tableau list_c est l'adresse de début du tableau, la
variable de pointeur ptr_c référence en fait maintenant le tableau via l'adresse de début.
15 : 16 : 17 :
18 :
19 : }
Après l'exécution de l'exécutable 12L03.exe sur mon ordinateur, la sortie suivante s'affiche à
l'écran :
Dans le Listing 12.3, une variable de pointeur entier, ptr_int, est déclarée à la ligne 6.
UNE ANALYSE
Ensuite, un tableau d'entiers, list_int, qui est déclaré à la ligne 7, est initialisé par le
list_int[i] = i + 1 expression dans une boucle for . (Voir les lignes 10 et 11.)
Machine Translated by Google
196 Heure 12
La ligne 13 affiche l'adresse affectée à la variable de pointeur ptr_int. La sortie montre que 0x1802 est l'adresse
de début du tableau. (Vous pourriez obtenir une adresse différente sur votre machine.) L' expression *ptr_int
de la ligne 14 est évaluée à la valeur référencée par le pointeur. Cette valeur est la même valeur contenue par
le premier élément du tableau, qui est la valeur initiale, 1, assignée dans la boucle for . Vous pouvez voir que la
sortie de l'instruction de la ligne 14 affiche correctement la valeur.
L'instruction de la ligne 15 est équivalente à celle de la ligne 12, qui affecte l'adresse du premier élément à la
variable de pointeur. Les lignes 16 et 17 impriment alors l'adresse et la valeur conservées par le premier
élément, 0x1802 et 1, respectivement.
Dans l'heure 16, « Application des pointeurs », vous apprendrez à accéder à un élément d'un tableau en
incrémentant ou en décrémentant un pointeur.
Plus important encore en C, une chaîne de caractères est définie comme une séquence contiguë de caractères
terminée par et incluant le premier caractère nul ('\0'). L'heure 13, "Manipulation des chaînes", présente plus de
détails sur les chaînes.
Dans le Listing 12.4, vous voyez différentes manières d'afficher un tableau de caractères à l'écran.
char array_ch[7] = {'H', 'e', 'l', 'l', 'o', '!', '\0'} ; int je ;
array_ch[0] contient : H
SORTIR array_ch[1] contient : e
array_ch[2] contient : l
array_ch[3] contient : l
array_ch[4] contient : o
array_ch[5] contient : !
array_ch[6] contient :
Assemblez tous les éléments (Méthode I) :
Bonjour !
Rassemblez tous les éléments (Méthode II) :
Bonjour !
Comme vous pouvez le voir dans le Listing 12.4, un tableau de caractères, array_ch, est
UNE ANALYSE
déclaré et initialisé à la ligne 6. Chaque élément du tableau de caractères est imprimé par le
appel printf() dans une boucle for illustrée aux lignes 9 et 10. Il y a un total de sept éléments
dans le tableau ; ils contiennent les constantes de caractère suivantes : 'H', 'e', 'l', 'l', 'o', '!'
et '\0'.
Il existe deux manières d'afficher ce tableau : afficher tous les caractères individuellement ou les traiter
comme une chaîne de caractères.
12
Les lignes 12 à 14 montrent la première manière, qui récupère chaque élément individuel, array_ch[i],
consécutivement dans une boucle, et imprime un caractère à côté d'un autre en utilisant le spécificateur
de format de caractère %c dans l' appel printf() en ligne 14.
Chaque fois que vous avez affaire à un tableau de caractères, comme mentionné précédemment, le
caractère nul '\0' signale la fin de la chaîne (même s'il ne s'agit pas encore de la fin du tableau). C'est une
bonne idée de surveiller le caractère nul afin de savoir quand arrêter l'impression, ainsi l'expression
conditionnelle de la ligne 13 terminera la boucle for si l'élément courant est un caractère nul.
La deuxième façon est plus simple. Vous indiquez simplement à la fonction printf() où trouver le premier
élément du tableau (l'adresse de son premier élément). De plus, vous devez utiliser la chaîne pour le
spécificateur mat %s dans l' appel printf() comme indiqué à la ligne 17. Notez que l' expression array_ch à
la ligne 17 contient l'adresse du premier élément du tableau, c'estàdire l'adresse de départ. adresse du
tableau. Le nom du tableau, en luimême, est une manière abrégée de dire array_ch[0] ; ils signifient la
même chose.
Machine Translated by Google
198 Heure 12
Vous vous demandez peutêtre comment la fonction printf() sait où se trouve la fin du tableau de caractères.
Vous souvenezvous que le dernier élément du tableau de caractères array_ch est un caractère '\0' ? C'est
ce caractère nul qui marque la fin de la chaîne. Comme je l'ai mentionné précédemment, une séquence
contiguë de caractères se terminant par un caractère nul est appelée une chaîne de caractères en C. Nous
ne disons pas à printf() combien d'éléments sont dans le tableau, donc le spécificateur de format %s indique
à printf() de continuez à imprimer des caractères jusqu'à ce qu'il trouve un caractère nul, comme nous l'avons
fait nousmêmes dans la première méthode.
Le caractère nul ('\0'), qui est toujours évalué comme une valeur de zéro, peut également être utilisé pour
un test logique dans une instruction de flux de contrôle. Le Listing 12.5 montre un exemple d'utilisation du
caractère nul dans une boucle for .
char array_ch[15] = {'C', ' ', 'i', 's', ' ', 'p',
'o', 'w', 'e', 'r', 'f', '
u', 'l', '!', '\0'} ;
int je ; /
8 : 9 : 10 : 11*: array_ch[i]
dans le test logique */ for (i=0;
12 : array_ch[i]; i++)
13: printf("%c", array_ch[i]);
14:
15 : printf("\n");
16 : renvoie 0 ;
17 : }
C'est puissant !
SORTIR
Machine Translated by Google
Dans le Listing 12.5, un tableau de caractères, array_ch, est déclaré et initialisé, avec les caractères
UNE ANALYSE
(y compris les espaces) de la chaîne C est puissant !, dans
lignes 6 à 9.
Notez que le dernier élément du tableau contient le caractère nul ('\0'), qui est nécessaire pour terminer la chaîne.
La boucle for des lignes 12 et 13 imprime chaque élément du tableau array_ch pour montrer que la chaîne C
est puissante ! sur l'écran. Ainsi, dans la première expression de l' instruction for , la variable entière i, qui est
utilisée comme index du tableau, est initialisée à 0.
Ensuite, l'expression conditionnelle, array_ch[i], est évaluée. Si l'expression donne une valeur différente de
zéro, la boucle for itère ; sinon, la boucle s'arrête. À partir du premier élément du tableau, l' expression
array_ch[i] continue de produire une valeur différente de zéro jusqu'à ce que le caractère nul soit rencontré. Par
conséquent, la boucle for peut mettre tous les caractères du tableau à l'écran et arrêter l'impression juste après
que l' expression array_ch[i] ait produit une valeur de zéro, lorsqu'elle trouve le caractère nul
Tableaux multidimensionnels
Jusqu'à présent, tous les tableaux que vous avez vus étaient des tableaux unidimensionnels, dans lesquels les
tailles des dimensions sont placées entre parenthèses ([ et ]).
En plus des tableaux unidimensionnels, le langage C prend également en charge les tableaux
multidimensionnels. Vous pouvez déclarer des tableaux avec autant de dimensions que votre compilateur le permet.
Parce que le tableau à deux dimensions, qui est largement utilisé, est la forme la plus simple du tableau
multidimensionnel, concentronsnous sur les tableaux à deux dimensions dans cette section. Cependant, tout
ce que vous apprenez dans cette section peut être appliqué à des tableaux de plus de deux dimensions.
int array_int[2][3] ;
Ici, il y a deux paires de crochets qui représentent deux dimensions avec une taille de 2 et 3 éléments entiers,
respectivement.
array_int[0][0] = 1 ;
array_int[0][1] = 2 ;
Machine Translated by Google
200 Heure 12
array_int[0][2] = 3 ;
array_int[1][0] = 4 ;
array_int[1][1] = 5 ;
array_int[1][2] = 6 ;
Notez que array_int[0][0] est le premier élément du tableau à deux dimensions array_int ; array_int[0]
[1] est le deuxième élément du tableau ; array_int[0][2] est le troisième élément ; array_int[1][0] est le
quatrième élément ; array_int[1][1] est le cinquième élément ; et array_int[1][2] est le sixième élément
du tableau.
Le programme du Listing 12.6 montre un tableau d'entiers à deux dimensions qui est initialisé et
affiché à l'écran.
TAPER
LISTE 12.6 Impression d'un tableau à deux dimensions
} printf("\n");
renvoie 0 ;
Comme vous pouvez le voir dans le Listing 12.6, il existe un tableau d'entiers à deux dimensions, two_dim,
UNE ANALYSE
déclaré et initialisé aux lignes 6–8.
Aux lignes 11 à 15, deux boucles for sont imbriquées. La boucle for externe incrémente la variable entière i et
imprime le caractère de retour à la ligne '\n' à chaque itération. Ici, la variable entière i est utilisée comme index
de la première dimension du tableau, two_dim.
La boucle for interne des lignes 13 et 14 imprime chaque élément, représenté par l'expression two_dim[i][j], en
incrémentant l'indice à la deuxième dimension du tableau.
J'obtiens donc la sortie suivante :
1 2 3 4
dix 5 20 30 40 50 100 200 300
400 500
une fois que les deux boucles for imbriquées ont été exécutées avec succès.
La bonne nouvelle est que le compilateur C peut en fait calculer automatiquement la taille d'une dimension d'un
tableau si un tableau est déclaré comme un tableau non dimensionné. Par exemple, lorsque le compilateur voit le
tableau non dimensionné suivant :
int list_int[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90} ;
12
cela créera un tableau assez grand pour stocker tous les éléments.
De même, vous pouvez déclarer un tableau multidimensionnel non dimensionné. Cependant, vous devez spécifier
toutes les tailles de dimension sauf la plus à gauche (c'estàdire la première). Par exemple, le compilateur peut
réserver suffisamment d'espace mémoire pour contenir tous les éléments du tableau non dimensionné à deux
dimensions suivant :
Le programme du Listing 12.7 initialise un tableau unidimensionnel de caractères non dimensionnés et un tableau
bidimensionnel d'entiers non dimensionnés, puis mesure les espaces mémoire utilisés pour stocker les deux
tableaux.
Machine Translated by Google
202 Heure 12
La sortie suivante est obtenue lorsque l'exécutable 12L07.exe est exécuté sur mon ordinateur :
Un tableau non dimensionné de caractères, array_ch, est déclaré et initialisé aux lignes 6–9.
UNE ANALYSE
Aux lignes 10 à 17, un tableau d'entiers non dimensionné à deux dimensions, list_int, est déclaré et
initialisé aussi.
L'instruction de la ligne 19 mesure et imprime l'espace mémoire total (en octets) occupé par le tableau
array_ch. Le résultat montre que le tableau de caractères non dimensionné se voit attribuer 15 octets en
mémoire pour contenir tous ses éléments après la compilation. Lorsque vous calculez manuellement le
nombre total d'éléments dans le tableau de caractères, vous constatez qu'il y a bien 15 éléments. Parce
que chaque caractère prend un octet dans la mémoire, le tableau de caractères array_ch prend un total de
15 octets en conséquence.
De même, l'instruction de la ligne 20 donne le nombre total d'octets réservés en mémoire pour le tableau
d'entiers à deux dimensions non dimensionné list_int. Parce qu'il y a un total de 21 éléments entiers dans
le tableau, et qu'un entier prend 2 octets sur ma machine, le compilateur doit allouer 42 octets pour le
tableau d'entiers list_int. Le résultat imprimé par la fonction printf() à la ligne 20 prouve qu'il y a 42 octets
réservés dans la mémoire
Machine Translated by Google
pour le tableau d'entiers à deux dimensions. (Si la taille de int est différente sur votre machine, vous pouvez obtenir
des valeurs différentes pour la taille du tableau list_int dans le programme Listing 12.7.)
Résumé
Dans cette leçon, vous avez appris les concepts très importants suivants sur les tableaux en C :
• Un tableau est une collection de variables qui sont du même type de données. • En C,
l'index d'un tableau commence à 0. • Vous pouvez initialiser chaque élément individuel d'un
tableau après la déclaration du tableau, ou vous pouvez placer toutes les valeurs initiales dans un bloc de
données entouré de { et } lors de la déclaration de un tableau.
• Le stockage en mémoire occupé par un tableau est déterminé en multipliant la taille du type de données et les
dimensions du tableau.
• On dit qu'un pointeur fait référence à un tableau lorsque l'adresse du premier élément du
tableau est assigné au pointeur. L'adresse du premier élément d'un tableau est également appelée adresse
de début du tableau.
• Pour affecter l'adresse de départ d'un tableau à un pointeur, vous pouvez soit mettre la combinaison de
l'opérateur d'adresse de (&) et du premier nom d'élément du tableau, soit simplement utiliser le nom du
tableau à droite de un opérateur d'affectation (=).
• Le caractère nul ('\0') marque la fin d'une chaîne. Fonctions C, telles que printf(),
arrêtera de traiter la chaîne lorsque le caractère nul est rencontré.
• C prend également en charge les tableaux multidimensionnels. Une paire de parenthèses vide (le soustableau
opérateur de script—[ et ]) indique une dimension.
12
• Le compilateur peut calculer automatiquement l'espace mémoire nécessaire à un fichier non dimensionné.
déployer.
Questions et réponses
A Dans de nombreux cas, vous devez déclarer un ensemble de variables qui sont du même type de données.
Au lieu de déclarer chaque variable séparément, vous pouvez déclarer toutes les variables collectivement
sous la forme d'un tableau. Chaque variable, en tant qu'élément du tableau, est accessible via la référence
d'élément de tableau ou via un pointeur qui référence le tableau.
Machine Translated by Google
204 Heure 12
A En C, l'indice minimum d'un tableau à une dimension est 0, ce qui marque le premier
élément du tableau. Par exemple, étant donné un tableau d'entiers,
int tableau_int[8] ;
A Vous pouvez utiliser un pointeur pour référencer un tableau en attribuant l'adresse de début d'un
tableau au pointeur. Par exemple, étant donné une variable de pointeur ptr_ch et un tableau de
caractères array_ch, vous pouvez utiliser l'une des instructions suivantes pour référencer le tableau
par le pointeur :
ptr_ch = array_ch ;
ou alors
ptr_ch = &array_ch[0];
Q Que peut faire le caractère nul ?
A Le caractère nul ('\0') en C peut être utilisé pour marquer la fin d'une chaîne. Pour
Par exemple, la fonction printf() continue de placer le caractère suivant à l'écran jusqu'à ce que le
caractère nul soit rencontré. En outre, le caractère nul prend toujours la valeur zéro.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon
suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».
Questionnaire
2. Étant donné un tableau, int data[3], quel est le problème avec l'initialisation suivante ?
données[1] = 1 ;
données[2] = 2 ;
données[3] = 3 ;
Machine Translated by Google
• tableau de caractères1[3][19] ;
• int tableau2[] ;
• tableau flottant3[][8][16] ;
• tableau de caractères4[][80] ;
Des exercices
2. Réécrivez le programme dans l'exercice 1, mais cette fois utilisez une boucle for pour
initialiser le tableau de caractères avec 'a', 'b', 'c', 'd' et 'e', puis imprimez la valeur de
chaque élément du tableau.
écrivez un programme pour mesurer le nombre total d'octets pris par le tableau, puis imprimez tous les
éléments du tableau.
4. Réécrivez le programme du Listing 12.5. Cette fois, mettez une chaîne de caractères, J'aime C !, sur
l'écran.
utilisez les deux méthodes équivalentes enseignées dans cette leçon pour mesurer l'espace mémoire
total occupé par la matrice, puis affichez les résultats à l'écran.
Machine Translated by Google
Machine Translated by Google
HEURE 13
Manipulation de chaînes
J'ai fait cette lettre plus longue que d'habitude, parce que je n'ai pas le temps de la faire courte.
—B. Pascal
Dans la leçon de la dernière heure, vous avez appris à utiliser des tableaux pour collecter des
variables du même type. Vous avez également appris qu'une chaîne de caractères est en fait
un tableau de caractères, avec un caractère nul \0 marquant la fin de la chaîne. Dans cette
leçon, vous en apprendrez plus sur les chaînes et les fonctions C qui peuvent être utilisées pour
manipuler les chaînes. Les sujets suivants sont couverts :
gets() et puts()
Machine Translated by Google
208 Heure 13
Par exemple, un tableau de caractères, array_ch, déclaré dans l'instruction suivante, est considéré comme une
chaîne de caractères :
En C, le caractère nul est utilisé pour marquer la fin d'une chaîne, et il est toujours évalué à 0. C traite \0 comme un
seul caractère. Chaque caractère d'une chaîne ne prend que 1 octet.
Une série de caractères entre guillemets ("") est appelée une constante de chaîne. Le compilateur C ajoutera
automatiquement un caractère nul (\0) à la fin d'une constante de chaîne pour indiquer la fin de la chaîne.
Par exemple, la chaîne de caractères "Une chaîne de caractères". est considéré comme une constante de
chaîne ; tout comme "Bonjour!".
Ici, le tableau arr_str est traité comme un tableau de caractères. Cependant, si vous ajoutez un caractère nul (\0)
dans le tableau, vous pouvez obtenir l'instruction suivante :
Ici, le tableau arr_str est étendu pour contenir sept éléments ; le dernier élément contient un caractère nul.
Désormais, le tableau de caractères arr_str est considéré comme une chaîne de caractères en raison du caractère
nul qui est ajouté (ajouté à la fin) des données de caractères.
Vous pouvez également initialiser un tableau de caractères avec une constante de chaîne, au lieu d'une liste de
constantes de caractères. Par exemple, l'instruction suivante initialise un tableau de caractères, str, avec une
constante de chaîne, « Bonjour ! » :
Le compilateur ajoutera automatiquement un caractère nul (\0) à la fin de "Hello!", et traitera le tableau de
caractères comme une chaîne de caractères. Notez que la taille du tableau est spécifiée pour contenir jusqu'à
sept éléments, bien que la constante de chaîne ne comporte que six caractères entre guillemets doubles.
L'espace supplémentaire est réservé au caractère nul qui sera ajouté ultérieurement par le compilateur.
Vous pouvez déclarer un tableau de caractères non dimensionné si vous voulez que le compilateur calcule le
nombre total d'éléments dans le tableau. Par exemple, la déclaration suivante :
initialise un tableau de caractères non dimensionné : , str, avec une constante de chaîne. Plus tard, lorsque
le compilateur verra l'instruction, il déterminera l'espace mémoire total nécessaire pour maintenir la chaîne
constante plus un caractère nul supplémentaire ajouté par le compilateur luimême.
Si vous le souhaitez, vous pouvez également déclarer un pointeur de caractère , puis initialiser le pointeur
avec une constante de chaîne. L'instruction suivante est un exemple :
Ne spécifiez pas la taille d'un tableau de caractères comme étant trop petite. Sinon, il ne peut pas
contenir une chaîne constante plus un caractère nul supplémentaire. Par exemple, la déclaration
suivante est considérée comme illégale :
L'instruction suivante est correcte, car elle spécifie la taille du tableau de caractères str suffisamment
grand pour contenir la chaîne constante plus un caractère nul supplémentaire :
Lorsqu'une variable de caractère ch et un tableau de caractères str sont initialisés avec le même caractère,
x, comme suit :
Machine Translated by Google
210 Heure 13
1 octet est réservé à la variable de caractère ch et deux octets sont alloués au tableau de caractères str. La raison pour
laquelle un octet supplémentaire est nécessaire pour str est que le compilateur doit ajouter un caractère nul au tableau.
Une autre chose importante est qu'une chaîne, puisqu'il s'agit d'un tableau, est en réalité un pointeur de caractère .
Ainsi, vous pouvez affecter directement une chaîne de caractères à une variable pointeur, comme ceci :
caractère
*ptr_str ; ptr_str = "Une chaîne de caractères.";
Cependant, vous ne pouvez pas affecter une constante de caractère à la variable de pointeur, comme illustré cidessous :
En d'autres termes, la constante de caractère 'x' contient une valeur de droite et la variable de pointeur ptr_str attend une
valeur de gauche. Mais C nécessite les mêmes types de valeurs des deux côtés d'un opérateur d'affectation =.
Il est légal d'assigner une constante de caractère à un pointeur char déréférencé comme ceci :
caractère *ptr_str ;
*ptr_str = 'x' ;
Maintenant, les valeurs des deux côtés de l' opérateur = sont du même type.
Le programme du Listing 13.1 montre comment initialiser ou affecter des tableaux de caractères avec des constantes
de chaîne.
16 : printf("\n"); /*
17 : affiche str2 */ for (i=0;
18 : str2[i]; i++)
19 : printf("%c", str2[i]);
20 : printf("\n"); /* assigne une
21 : chaîne à un pointeur */ ptr_str = "Assigne
22 : une chaîne à un pointeur."; pour (i=0; *ptr_str; i++)
23 :
24 : printf("%c", *ptr_str++); renvoie
25 : 0;
26 : }
Comme vous pouvez le voir dans le Listing 13.1, il y a deux tableaux de caractères, str1 et
UNE ANALYSE
str2, qui sont déclarés et initialisés aux lignes 6–9. Dans la déclaration de str1, un ensemble
de constantes de caractères, y compris un caractère nul, est utilisé pour initialiser le tableau. Pour
str2, une constante de chaîne est affectée au tableau de la ligne 9. Le compilateur ajoutera un
caractère nul à str2. Notez que str1 et str2 sont déclarés comme des tableaux non dimensionnés pour
lesquels le compilateur déterminera automatiquement la quantité de mémoire nécessaire. L'instruction
de la ligne 10 déclare une variable de pointeur char , ptr_str.
La boucle for des lignes 14 et 15 affiche ensuite tous les éléments de str1. Comme le dernier élément
contient un caractère nul (\0) évalué comme 0, str1[i] est utilisé comme expression conditionnelle de l'
instruction for . L'expression str1[i] prend une valeur différente de zéro pour chaque élément de str1
sauf celui contenant le caractère nul. Après l'exécution de la boucle for , la chaîne Une constante de
chaîne s'affiche à l'écran.
De même, une autre boucle for dans les lignes 18 et 19 affiche la constante de chaîne affectée à
13
str2 en plaçant chaque élément du tableau à l'écran. Étant donné que le compilateur ajoute un
caractère nul au tableau, l'expression str2[i] est évaluée dans l' instruction for .
La boucle for arrête d'itérer lorsque str2[i] est évalué à 0. À ce momentlà, le contenu de la constante
de chaîne, Une autre constante de chaîne, a déjà été affiché sur le
écran.
L'instruction de la ligne 22 affecte une constante de chaîne, « Attribuer une chaîne à un pointeur. », :
à la variable de pointeur char ptr_str. De plus, une boucle for est utilisée pour afficher la constante de
la chaîne en plaçant chaque caractère de la chaîne à l'écran (voir lignes 23 et 24). Notez que le
pointeur déréférencé *ptr_str est utilisé pour faire référence à l'un des caractères de la chaîne
Machine Translated by Google
212 Heure 13
constante. Lorsque le caractère nul ajouté à la chaîne est rencontré, *ptr_str prend la valeur 0, ce qui
provoque l'arrêt de l'itération de la boucle for . À la ligne 24, l'expression *ptr_str++ déplace le pointeur
vers le caractère suivant de la chaîne après la récupération du caractère actuel auquel le pointeur fait
référence. Dans l'heure 16, "Appliquer des pointeurs", vous en apprendrez plus sur l'arithmétique des
pointeurs.
de la fonction strlen() .
Ici s est une variable de pointeur char . La valeur de retour de la fonction est le nombre d'octets dans
la chaîne, sans compter le caractère nul '\0'. size_t est un type de données défini dans le fichier d'en
tête string.h . La taille du type de données dépend du système informatique particulier. Notez que
string.h doit être inclus dans votre programme avant de pouvoir appeler la fonction strlen() .
,
Le Listing 13.2 donne un exemple d'utilisation de la fonction strlen() pour mesurer la longueur des chaînes.
5 : principal()
6:{7:
char str1[] = {'A', ' ', 's', 't', 'r', 'i',
'n', 'g', ' ', 'c', 'o', 'n ', 's', 't', 'a', 'n', 't', '\0'} ;
renvoie 0 ;
17 : 18 : }
Dans le Listing 13.2, deux tableaux de caractères , str1 et str2, et une variable de
UNE ANALYSE
pointeur, ptr_str, sont déclarés et initialisés aux lignes 7 à 11, respectivement.
Ensuite, l'instruction de la ligne 13 obtient la longueur de la constante de chaîne détenue par str1 et
imprime le résultat. D'après le résultat, vous pouvez voir que le caractère nul (\0) à la fin de str1 n'est pas
compté par la fonction strlen() .
Aux lignes 14 à 16, les longueurs des constantes de chaîne référencées par str2 et ptr_str sont
mesurées et affichées à l'écran. Les résultats indiquent que la fonction strlen() ne compte pas non plus les
caractères nuls ajoutés aux deux constantes de chaîne par le compilateur.
Ici, le contenu de la chaîne src est copié dans le tableau référencé par dest. La fonction strcpy()
renvoie la valeur de src si elle réussit. Le fichier d'entête string.h doit être inclus dans votre
, programme avant que la fonction strcpy() ne soit appelée.
13
Le programme du Listing 13.3 montre comment copier une chaîne d'un tableau à un autre en appelant la
fonction strcpy() ou en le faisant vousmême.
continue
Machine Translated by Google
214 Heure 13
6:{7:
char str1[] = "Copier une chaîne."; char
str2[15] ; caractère str3[15] ; int je ;
8 : 9 : 10 : 11 :
12 : /* avec strcpy() */ strcpy(str2,
13: str1); /* sans strcpy() */ for
14: (i=0; str1[i]; i++) str3[i] = str1[i];
str3[i] = '\0' ; /* affiche str2 et str3
*/ printf("Le contenu de str2
15 : 16 : 17 en
: utilisant strcpy : %s\n", str2);
printf("Le contenu de str3 sans utiliser
strcpy : %s\n", str3); renvoie 0 ;
18h19h20h21h
22 : }
UNE ANALYSE Trois tableaux de caractères, str1 , str2 et str3, sont déclarés dans le Listing 13.3. De
plus, str1 est initialisé avec une constante de chaîne, "Copier une chaîne.", à la ligne 7.
L'instruction de la ligne 13 appelle la fonction strcpy() pour copier le contenu de str1 (y compris le
caractère nul ajouté par le compilateur) dans le tableau référencé par str2.
Les lignes 15 à 17 montrent une autre façon de copier le contenu de str1 dans un tableau référencé
par str3. Pour ce faire, la boucle for des lignes 15 et 16 continue de copier les caractères de str1
dans les éléments correspondants de str3 les uns après les autres, jusqu'à ce que le caractère nul
(\0) ajouté par le compilateur soit rencontré. Lorsque le caractère nul est rencontré, l' expression
str1[i] utilisée comme condition de l' instruction for à la ligne 15 est évaluée à 0, ce qui termine la
boucle.
Étant donné que la boucle for ne copie pas le caractère nul de str1 vers str3, l'instruction de la ligne
17 ajoute un caractère nul au tableau référencé par str3. En C, il est très important de s'assurer que
tout tableau utilisé pour stocker une chaîne a un caractère nul à la fin de la chaîne.
Pour prouver que la constante de chaîne référencée par str1 a été copiée avec succès dans str2
et str3 , le contenu détenu par str2 et str3 s'affiche à l'écran. Noter que
Machine Translated by Google
le spécificateur de format de chaîne %s et les adresses de début de str2 et str3 sont transmis à l' appel
printf() aux lignes 19 et 20 pour imprimer tous les caractères, à l'exception du caractère nul, stockés
dans str2 et str3. Les résultats affichés à l'écran montrent que str2 et str3 ont exactement le même
contenu que str1.
Ici, les caractères lus à partir du flux d'entrée standard sont stockés dans le tableau de caractères
identifié par s. La fonction gets() arrête la lecture et ajoute un caractère nul \0 au tableau lorsqu'un
caractère de nouvelle ligne ou de fin de fichier (EOF) est rencontré.
La fonction renvoie s si elle se termine avec succès. Sinon, un pointeur nul est renvoyé.
,
La fonction puts() peut être utilisée pour écrire des caractères dans le flux de sortie standard (c'estàdire
stdout) .
Ici s fait référence au tableau de caractères qui contient une chaîne. La fonction puts() écrit la 13
chaîne dans stdout. Si la fonction réussit, elle renvoie 0. Sinon, une valeur différente de zéro est
renvoyée.
La fonction puts() ajoute un caractère de saut de ligne pour remplacer le caractère nul à la fin d'un
, tableau de caractères.
Les fonctions gets() et puts() nécessitent toutes deux le fichier d'entête stdio.h. Dans le Listing 13.4,
vous pouvez voir l'application des deux fonctions.
Machine Translated by Google
216 Heure 13
Lors de l'exécution de l'exécutable 13L04.exe, j'entre une ligne de caractères (en gras cidessous)
à partir du clavier et les caractères (tous en majuscules) s'affichent à l'écran.
Entrez une chaîne de moins de 80 caractères :
SORTIR Ceci est un test.
La chaîne saisie est (en majuscule) : CECI EST
UN TEST.
Le programme du Listing 13.4 accepte une chaîne de caractères saisie à partir du clavier
UNE ANALYSE
(c'estàdire stdin), puis convertit tous les caractères minuscules en majuscules
ceux. Enfin, la chaîne modifiée est remise à l'écran.
À la ligne 6, un tableau de caractères (str) est déclaré et peut contenir jusqu'à 80 caractères.
La fonction gets() de la ligne 10 lit tous les caractères entrés par l'utilisateur à partir du clavier
jusqu'à ce que l'utilisateur appuie sur la touche Entrée, qui est interprétée comme un caractère de
saut de ligne. Les caractères lus par la fonction gets() sont stockés dans le tableau de caractères indiqué par str.
Le caractère de nouvelle ligne n'est pas enregistré dans str. Au lieu de cela, un caractère nul est ajouté au
tableau en tant que terminateur.
La boucle while des lignes 12 à 15 a une expression conditionnelle, str[i]. La boucle while continue
d'itérer tant que str[i] donne une valeur différente de zéro. Dans la boucle, la valeur de chaque
caractère représenté par str[i] est évaluée à la ligne 13, pour savoir si le
Machine Translated by Google
caractère est un caractère minuscule dans la plage de a à z. Si le caractère est l'un des caractères minuscules, il est
converti en majuscule en soustrayant la valeur d'une variable int , delt, de sa valeur courante à la ligne 14. La variable
delt est initialisée à la ligne 7 par la valeur de l'expression 'a ' 'A', qui est la différence entre la valeur numérique d'un
caractère minuscule et son équivalent majuscule. En d'autres termes, en soustrayant la différence de 'a' et 'A' de la
valeur entière minuscule, nous obtenons la valeur entière majuscule.
Ensuite, la fonction puts() de la ligne 18 renvoie la chaîne avec tous les caractères majuscules vers stdout, qui va
à l'écran par défaut. Un caractère de saut de ligne est ajouté par la fonction puts() lorsqu'elle rencontre le caractère
nul à la fin de la chaîne.
Par exemple, vous pouvez utiliser le spécificateur de format de chaîne, %s, avec la fonction printf() pour afficher
une chaîne de caractères enregistrée dans un tableau. (Reportezvous à l'exemple du Listing 13.3.)
Dans la section suivante, la fonction scanf() est présentée comme un moyen de lire les valeurs de divers types de
données avec différents spécificateurs de format, y compris le spécificateur de format %s.
un autre moyen de lire des chaînes à partir du flux d'entrée standard. De plus, cette fonction peut en fait être
utilisée pour lire différents types de données d'entrée.
Les formats des arguments de la fonction scanf() sont assez similaires à ceux utilisés dans la fonction printf() .
218 Heure 13
Notez qu'avec scanf(), contrairement à printf(), vous devez passer des pointeurs vers vos arguments
pour que la fonction scanf() puisse modifier leurs valeurs.
Le programme du Listing 13.5 montre comment utiliser divers spécificateurs de format avec
la fonction scanf() .
15 : 16 : 17 :
18 :
19 : }
La sortie suivante s'affiche à l'écran après avoir exécuté l'exécutable 13L05.exe et saisi les données
(qui apparaissent en gras) à partir de mon clavier :
Dans le Listing 13.5, il y a un tableau de caractères (str), deux variables int (x et y) et une
UNE ANALYSE
variable flottante déclarée aux lignes 6–8.
Machine Translated by Google
Ensuite, la fonction scanf() de la ligne 11 lit deux entiers entrés par l'utilisateur et les enregistre dans les
emplacements mémoire réservés aux variables entières x et y. L'opérateur adresse de permet d'obtenir les
adresses mémoire des variables. L'instruction de la ligne 13 lit et stocke un nombre à virgule flottante dans z.
Notez que les spécificateurs de format, %d et %f, sont utilisés pour spécifier les formats appropriés pour les
nombres entrés dans les lignes 11 et 13.
La ligne 15 utilise la fonction scanf() et le spécificateur de format %s pour lire une série de caractères saisis
par l'utilisateur, puis enregistre les caractères (plus un caractère nul comme terminateur) dans le tableau
pointé par str. L'opérateur d'adresse de n'est pas utilisé ici, car str luimême pointe vers l'adresse de début
du tableau.
Pour prouver que la fonction scanf() lit tous les nombres et caractères saisis par l'utilisateur, la fonction
printf() à la ligne 17 affiche le contenu enregistré dans x, y, z et str à l'écran. Effectivement, le résultat
montre que le scanf() a fait son travail.
Une chose dont vous devez être conscient est que la fonction scanf() ne commence pas à lire l'entrée
tant que la touche Entrée n'est pas enfoncée. Les données saisies à partir du clavier sont placées dans un
tampon d'entrée. Lorsque la touche Entrée est enfoncée, la fonction scanf() recherche son entrée dans le
tampon. Vous en apprendrez plus sur l'entrée et la sortie mises en mémoire tampon dans l'heure 21, « Lecture
et écriture avec des fichiers ».
Résumé
Dans cette leçon, vous avez appris les fonctions et concepts importants suivants concernant les chaînes
en C :
• Une chaîne est un tableau de caractères avec un caractère nul marquant la fin de la chaîne. • Une
constante chaîne est une série de caractères entourés de guillemets doubles. • Le compilateur C
déréférencé. • La fonction strlen() peut être utilisée pour mesurer la longueur d'une chaîne. Cette fonction
13
ne compte pas le caractère nul.
• Vous pouvez copier une chaîne d'un tableau à un autre en appelant la fonction C
strcpy().
• La fonction gets() peut être utilisée pour lire une série de caractères. Cette fonction arrête la lecture
lorsque le caractère de nouvelle ligne ou de fin de fichier (EOF) est rencontré. La fonction ajoute un
caractère nul à la fin de la chaîne.
Machine Translated by Google
220 Heure 13
• La fonction puts() envoie tous les caractères, à l'exception du caractère nul, d'une chaîne à la
sortie standard et ajoute un caractère de saut de ligne à la sortie.
• Vous pouvez lire différents éléments de données avec la fonction scanf() en utilisant divers for
spécificateurs de tapis.
Questions et réponses
A En C, une chaîne est stockée dans un tableau de caractères et se termine par un caractère nul
('\0'). Le caractère nul indique aux fonctions de chaîne (telles que puts() et strcpy qu'elles ont
atteint la fin de la chaîne.
La fonction C strlen() peut être utilisée pour mesurer la longueur d'une chaîne. Si elle réussit,
la fonction strlen() renvoie le nombre total d'octets pris par la chaîne ; cependant, le caractère
nul dans la chaîne n'est pas compté.
Q Quelles sont les principales différences entre une constante de chaîne et un caractère
constante?
Une constante de chaîne est une série de caractères entourés de guillemets doubles, tandis qu'une
constante de caractère est un caractère unique entouré de guillemets simples. Le compilateur
ajoutera un caractère nul à la chaîne lorsqu'il est utilisé pour initialiser un tableau.
Par conséquent, un octet supplémentaire doit être réservé pour le caractère nul. Par contre,
une constante caractère ne prend qu'1 octet en mémoire et n'est pas stockée dans un
déployer.
R Non. La fonction gets() continue de lire les caractères du flux d'entrée standard jusqu'à ce qu'un
caractère de saut de ligne ou de fin de fichier soit rencontré. Au lieu d'enregistrer le caractère de
nouvelle ligne, la fonction gets() ajoute un caractère nul à la chaîne et le stocke dans le tableau
référencé par l'argument de la fonction gets() .
R Selon les spécificateurs de format de style printf() que vous transmettez à la fonction, scanf() peut
lire divers types de données, comme une série de caractères, des entiers ou des nombres à
virgule flottante. Contrairement à gets(), scanf() arrête de lire l'élément d'entrée actuel (et passe
à l'élément d'entrée suivant s'il y en a un) lorsqu'il rencontre un espace, une nouvelle ligne, une
tabulation, une tabulation verticale ou un saut de page.
Machine Translated by Google
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la
leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».
Questionnaire
• car str4[2] = « TX » ;
2. Étant donné une variable de pointeur char ptr_ch, les déclarations suivantes sontelles légales ?
• *ptr_ch = 'a';
• ptr_ch = 'x';
4. Quel spécificateur de format utilisezvous avec la fonction scanf() pour lire une chaîne, et lequel
utilisezvous pour lire un nombre à virgule flottante ?
Des exercices
écrivez un programme pour copier la chaîne de str1 dans un autre tableau, appelé str2.
2. Écrivez un programme pour mesurer la longueur d'une chaîne en évaluant les éléments d'un tableau
13
de caractères un par un jusqu'à ce que vous atteigniez le caractère nul. Pour prouver que vous
obtenez le bon résultat, vous pouvez utiliser la fonction strlen() pour mesurer à nouveau la même chaîne.
3. Réécrivez le programme du Listing 13.4. Cette fois, convertissez tous les caractères majuscules en
leurs homologues minuscules.
4. Écrivez un programme qui utilise la fonction scanf() pour lire deux nombres entiers saisis par
l'utilisateur, additionne les deux nombres entiers, puis affiche la somme à l'écran.
Machine Translated by Google
Machine Translated by Google
HEURE 14
Présentation de l'étendue
et des classes de stockage
Personne ne possède rien et tout ce que chacun a est l'usage de ses biens présumés.
—P. Wylie
Au cours des heures précédentes, vous avez appris à déclarer des variables de différents
types de données, ainsi qu'à initialiser et à utiliser ces variables. Il a été supposé que vous
pouvez accéder aux variables de n'importe où. Maintenant, la question est : pouvezvous
déclarer des variables qui ne sont accessibles qu'à certaines parties d'un programme ? Dans
cette leçon, vous découvrirez la portée et les classes de stockage des données en C. Les
principaux sujets abordés dans cette leçon sont
• Étendue du bloc •
Étendue de la fonction •
Étendue du fichier •
Étendue du programme
Machine Translated by Google
224 Heure 14
• Le spécificateur
automatique • Le
spécificateur statique • Le
• Le modificateur volatil
Dans le programme complet, il peut y avoir des variables qui doivent être partagées par toutes les
fonctions. D'autre part, l'utilisation de certaines autres variables peut être limitée à certaines fonctions
uniquement. Autrement dit, la visibilité de ces variables est limitée et les valeurs affectées à ces variables
sont masquées pour de nombreuses fonctions.
Limiter la portée des variables est très utile lorsque plusieurs programmeurs travaillent sur différentes
parties du même programme. S'ils limitent la portée de leurs variables à leurs morceaux de code, ils n'ont
pas à se soucier des conflits avec des variables du même nom utilisées par d'autres dans d'autres parties
du programme.
En C, vous pouvez déclarer une variable et indiquer son niveau de visibilité en désignant sa portée.
Ainsi, les variables à portée locale ne sont accessibles qu'à l'intérieur du bloc dans lequel elles sont
déclarées.
Les sections suivantes vous apprennent à déclarer des variables avec différentes portées.
cette section, un bloc fait référence à tout ensemble d'instructions entre accolades ({ et }). Une variable
déclarée dans un bloc a une portée de bloc. Ainsi, la variable est active et accessible depuis son point de
déclaration jusqu'à la fin du bloc. Parfois, la portée de bloc est également appelée portée locale.
Par exemple, la variable i déclarée dans le bloc de la fonction principale suivante a une portée de bloc :
int main() {
.
.
.
renvoie 0 ;
}
Habituellement, une variable avec une portée de bloc est appelée une variable locale. Notez que les variables
locales doivent être déclarées au début du bloc, avant les autres instructions.
Le Listing 14.1 montre un exemple de portées de variables dans des blocs imbriqués.
La sortie suivante s'affiche à l'écran après la création et l'exécution de l'exécutable (14L01.exe) du programme
du Listing 14.1 :
226 Heure 14
je= 3, j= 7
je= 4, j= 6
je= 5, j= 5
je= 6, j= 4
je= 7, j= 3
je= 8, j= 2
je= 9, j= 1 je
=10, j= 0
Dans le bloc extérieur : i=32
Le but du programme du Listing 14.1 est de vous montrer les différentes portées des variables
UNE ANALYSE
dans les blocs imbriqués. Comme vous pouvez le voir, il y a deux blocs imbriqués dans le
Listing 14.1. La variable entière i déclarée à la ligne 6 est visible dans le bloc extérieur délimité par les
accolades ({ et }) aux lignes 5 et 19. Deux autres variables entières, i et j, sont déclarées à la ligne 11
et ne sont visibles qu'à l'intérieur du bloc bloc de la ligne 10 à la ligne 16.
Bien que la variable entière i dans le bloc externe ait le même nom que l'une des variables entières
dans le bloc interne, les deux variables entières ne sont pas accessibles en même temps en raison de
leurs portées différentes.
Pour le prouver, la ligne 8 imprime la valeur, 32, contenue par i dans le bloc externe pour la première
fois. Ensuite, la boucle for des lignes 14 et 15 affiche 10 paires de valeurs affectées à i et j dans le bloc
interne. À ce stade, il n'y a aucun signe que la variable entière i dans le bloc externe ait des effets sur
celle du bloc interne. Lorsque le bloc interne est fermé, les variables du bloc interne ne sont plus
accessibles. En d'autres termes, toute tentative d'accès à j depuis le bloc externe serait illégale.
Enfin, l'instruction de la ligne 17 imprime à nouveau la valeur de i dans le bloc externe pour savoir si la
valeur a été modifiée en raison de la variable entière i dans le bloc interne. Le résultat montre que ces
deux variables entières se cachent l'une de l'autre et qu'aucun conflit ne se produit.
Portée de la fonction La
portée de la fonction indique qu'une variable est active et visible du début à la fin d'une fonction.
En C, seule une étiquette goto a une portée de fonction. Par exemple, l' étiquette goto , start, illustrée
dans la portion de code suivante a une portée de fonction :
int main() {
.
.
.
aller commencer ; /* l'instruction goto */
.
.
.
renvoie 0 ;
}
Les variables avec portée de programme sont également appelées variables globales, qui sont visibles
parmi tous les fichiers source qui composent un programme exécutable. Notez qu'une variable globale
est déclarée avec un initialiseur en dehors d'une fonction.
Le programme du Listing 14.2 démontre la relation entre les variables avec la portée du programme et
les variables avec la portée du bloc.
continue
Machine Translated by Google
228 Heure 14
6 : 7 : void function_1() 8 : { 9 :
10 : } 11 : 12 : main() 13 :
{ 14 : 15 : 16 : 17 : 18function_1
printf("De : 19 : :\nx=%d, y=%f\n", x, y);
20 : 21 : 22 : 23 : 24 : 25 : }
fonction_1();
printf("Dans le bloc principal :\nx=%d, y=%f\n", x, y); /* un bloc imbriqué */ {
} renvoie 0 ;
J'ai la sortie suivante affichée à l'écran après la création et l'exécution de l'exécutable 14L02.exe
sur ma machine :
À partir de function_1 :
SORTIR x=1234, y=1.234567 Dans
le bloc principal : x=4321,
y=1.234567 À partir de
function_1 : x=1234, y=1.234567
Dans le bloc imbriqué :
x=4321, y=7.654321
UNE ANALYSE
Comme vous pouvez le voir dans le Listing 14.2, il y a deux variables globales, x et y, avec la
portée du programme ; ils sont déclarés aux lignes 4 et 5.
Aux lignes 7 à 10, une fonction, appelée function_1(), est déclarée. (Plus de détails sur les
déclarations de fonction et les prototypes seront enseignés dans l'heure suivante.) La fonction
function_1() ne contient qu'une seule instruction ; il imprime les valeurs détenues par x et y. Étant
donné qu'aucune déclaration de variable n'est faite pour x ou y dans le bloc fonction, les valeurs des
variables globales x et y sont utilisées pour l'instruction à l'intérieur de la fonction. Pour prouver cela,
function_1() est appelée deux fois aux lignes 16 et 21, respectivement, à partir de deux blocs imbriqués.
La sortie montre que les valeurs des deux variables globales x et y sont transmises à printf()
dans le corps de la fonction function_1() .
Ensuite, la ligne 14 déclare une autre variable entière, x, avec une portée de bloc, qui peut
remplacer la variable globale x dans le bloc de la fonction main() . Le résultat réalisé par le
Machine Translated by Google
l'instruction à la ligne 17 montre que la valeur de x est la valeur de la variable locale x avec
portée du bloc, alors que la valeur de y est toujours celle de la variable globale y.
Il y a un bloc imbriqué dans les lignes 19 et 23, dans lequel une autre variable double y, avec une portée
de bloc, est déclarée et initialisée. Comme la variable x dans le bloc main() , cette variable, y, dans le bloc
imbriqué remplace la variable globale y. L'instruction de la ligne 22 affiche les valeurs des variables
locales x et y à l'écran
Parce qu'une variable globale est visible parmi les différents fichiers source d'un
programme, l'utilisation de variables globales augmente la complexité de votre programme,
ce qui rend votre programme difficile à maintenir ou à déboguer. Généralement, il n'est pas
recommandé de déclarer et d'utiliser des variables globales, sauf si cela est absolument
nécessaire. Par exemple, vous pouvez déclarer une variable globale dont la valeur est utilisée
(mais jamais modifiée) par plusieurs sousprogrammes de votre programme. (Dans l'heure
23, « Compilation de programmes : le préprocesseur C », vous apprendrez à utiliser la
directive #define pour définir des constantes qui sont utilisées à de nombreux endroits dans
un programme.)
Avant d'introduire la portée du fichier, permettezmoi d'abord de parler des spécificateurs de classe de stockage.
Vous avez appris la portée, qui spécifie la région spatiale d'une variable. Maintenant, concentronsnous
sur la durée, qui indique la région temporelle d'une variable.
Il existe quatre spécificateurs et deux modificateurs qui peuvent être utilisés pour indiquer la durée d'une
variable. Ces spécificateurs et modificateurs sont présentés dans les sections suivantes.
Le spécificateur automatique
Le spécificateur automatique est utilisé pour indiquer que l'emplacement mémoire d'une
variable est temporaire. En d'autres termes, l'espace réservé d'une variable dans la mémoire peut être
effacé ou déplacé lorsque la variable est hors de sa portée.
Seules les variables avec une portée de bloc peuvent être déclarées avec le spécificateur automatique . 14
Le motclé auto est cependant rarement utilisé en pratique, car la durée d'une variable avec une portée
de bloc est temporaire par défaut.
Machine Translated by Google
230 Heure 14
Le spécificateur statique
Le spécificateur statique , d'autre part, peut être appliqué à des variables avec une portée de
bloc ou une portée de programme. Lorsqu'une variable dans une fonction est déclarée avec le
spécificateur statique , la variable a une durée permanente. En d'autres termes, la mémoire
allouée à la variable n'est pas détruite lorsque l'on sort de la portée de la variable, la valeur de la
variable est maintenue hors de la portée. Si l'exécution revient à la portée de la variable, la
dernière valeur stockée dans la variable est toujours là.
la variable entière i a une durée temporaire (auto) par défaut. Mais l'autre variable entière, j, a
une durée permanente en raison du spécificateur de classe de stockage static.
Le programme du Listing 14.3 montre l'effet du spécificateur statique sur les variables.
7:8:
9 : 10 : } 11 : /* la fonction principale
*/ 12 : main() 13 : { 14 : 15 : 16 : 17 :
18 : 19 : 20 : }
int je, j ;
UNE ANALYSE Le but du programme du Listing 14.3 est d'appeler une fonction pour additionner deux
entiers, puis d'afficher le résultat renvoyé par la fonction à l'écran. La fonction est appelée
plusieurs fois. Un compteur est défini pour garder une trace du nombre de fois que la fonction a été
appelée.
Cette fonction, appelée add_two(), est déclarée aux lignes 4–10. Il y a deux arguments int , x et y,
qui sont passés à la fonction, et l'addition des deux arguments est retournée à la ligne 9. Notez qu'il y
a une variable entière, counter, qui est déclarée avec le spécificateur statique à la ligne 6 Les valeurs
stockées par compteur sont conservées car la durée de la variable est permanente. En d'autres
termes, bien que la portée du compteur soit dans le bloc de la fonction add_two() , l'emplacement
mémoire du compteur et la valeur enregistrée dans l'emplacement ne sont pas modifiés après l' appel
de la fonction add_two() et le contrôle d'exécution est renvoyé à la fonction principale() . Notez que
l'initialisation du compteur à 1 n'a lieu que la première fois que add_two() est appelée ; après cela, il
conserve sa valeur précédente chaque fois que la fonction est appelée.
Par conséquent, la variable compteur est utilisée comme compteur pour suivre le nombre d'appels
reçus par la fonction add_two() . En fait, la fonction printf() de la ligne 8 imprime la valeur enregistrée
par la variable compteur chaque fois que la fonction add_two() est appelée. De plus, le compteur est
incrémenté de un à chaque fois que la fonction printf() est exécutée.
La boucle for , déclarée aux lignes 16 à 18 dans la fonction main() , appelle cinq fois la fonction
add_two() . Les valeurs des deux variables entières, i et j, sont transmises à la fonction add_two()
où elles sont ajoutées. Ensuite, la valeur de retour de la fonction add_two() est affichée à l'écran
par l' appel printf() aux lignes 17 et 18.
14
À partir de la sortie, vous pouvez voir que la valeur enregistrée par counter est en effet incrémentée
de un à chaque fois que la fonction add_two() est appelée, et est conservée après la sortie de la
fonction car la variable entière counter est déclarée avec static. Vous pouvez voir que le compteur
n'est initialisé qu'une seule fois à 1, lorsque la fonction add_two() est appelée pour la première fois.
Machine Translated by Google
232 Heure 14
En C, une variable globale déclarée avec le spécificateur statique est dite avoir une portée de fichier. Une
variable avec une portée de fichier est visible depuis son point de déclaration jusqu'à la fin du fichier. Ici, le
fichier fait référence au fichier programme qui contient le code source. La plupart des grands programmes sont
constitués de plusieurs fichiers de programme.
La partie suivante du code source montre des variables avec une portée de fichier :
Ici, la variable int y et la variable flottante z ont toutes deux une portée de fichier.
La figure 14.1 montre la hiérarchie des quatre portées. Comme vous pouvez le voir, une variable avec une portée
de bloc est la plus limitée et n'est pas visible en dehors du bloc dans lequel la variable est déclarée. D'autre part,
une variable avec une portée de programme est visible dans tous les fichiers, fonctions et autres blocs qui
composent le programme.
La hiérarchie des
quatre portées. Portée du fichier
Portée de la fonction
Bloc
Portée
Machine Translated by Google
Le Prescripteur de registre
Le mot registre est emprunté à la terminologie du matériel informatique. Chaque ordinateur possède un certain
nombre de registres pour stocker des données et effectuer des calculs arithmétiques ou logiques.
Étant donné que les registres sont situés dans la puce CPU (unité centrale de traitement), il est beaucoup
plus rapide d'accéder à un registre qu'à un emplacement mémoire situé à l'extérieur de la puce.
Par conséquent, stocker des variables dans des registres peut aider à accélérer votre programme.
Le langage C vous fournit le spécificateur de registre . Vous pouvez appliquer ce spécificateur aux variables
lorsque vous pensez qu'il est nécessaire de placer les variables dans les registres de l'ordinateur.
Cependant, le spécificateur de registre ne donne qu'une suggestion au compilateur. En d'autres termes, une
variable spécifiée par le motclé register n'est pas garantie d'être stockée dans un registre.
Le compilateur peut ignorer la suggestion s'il n'y a pas de registre disponible ou si d'autres restrictions s'appliquent.
Il est illégal de prendre l'adresse d'une variable déclarée avec le spécificateur de registre car la variable est
destinée à être stockée dans un registre et non en mémoire. Un registre CPU n'a pas d'adresse mémoire à laquelle
vous pouvez accéder.
Dans la partie de code suivante, la variable entière i est déclarée avec le spécificateur de registre :
int main() {
La déclaration de i suggère que le compilateur stocke la variable dans un registre. Étant donné que i est utilisé de
manière intensive dans la boucle for , le stockage de i dans un registre peut augmenter la vitesse du code présenté
ici.
Le Prescripteur externe
Comme introduit dans la section intitulée "Portée du programme", plus tôt dans cette heure, une variable avec la
portée du programme est visible dans tous les fichiers source qui composent un programme exécutable. Une 14
variable avec une portée de programme est également appelée variable globale.
Voici une question : Comment une variable globale déclarée dans le fichier A peutelle être vue dans le
fichier B ? En d'autres termes, comment le compilateur saitil que la variable utilisée dans le fichier B est en fait
la même variable déclarée dans le fichier A ?
Machine Translated by Google
234 Heure 14
La solution est d'utiliser le spécificateur extern fourni par le langage C pour faire allusion à une
variable globale définie ailleurs. Dans ce cas, vous déclarez une variable globale dans le fichier A,
puis déclarez à nouveau la variable en utilisant le spécificateur extern dans le fichier B. Ce n'est pas une
déclaration séparée, mais spécifie la déclaration d'origine dans le fichier A.
Par exemple, supposons que vous ayez deux variables int globales, y et z, qui sont définies dans un
fichier, puis, dans un autre fichier, vous pourriez avoir les déclarations suivantes :
Comme vous pouvez le voir, il y a deux variables entières, y et z, qui sont déclarées avec le
spécificateur extern , respectivement à l'extérieur et à l'intérieur de la fonction main() . Lorsque le
compilateur voit les deux déclarations, il sait que les déclarations sont en fait des allusions aux variables
globales y et z qui sont définies ailleurs.
Pour rendre votre programme portable sur différentes platesformes informatiques, vous
pouvez appliquer les règles suivantes dans votre programme lorsque vous déclarez ou faites
allusion à des variables globales : • Vous pouvez ignorer le spécificateur extern, mais inclure un
• Vous devez utiliser le spécificateur extern (sans initialiseur) lorsque vous faites allusion à
une variable globale définie ailleurs.
Le modificateur const
Si vous déclarez une variable avec le modificateur const , le contenu de la variable ne peut pas être
modifié après son initialisation.
Machine Translated by Google
Par exemple, l'expression suivante indique au compilateur que circle_ratio est une variable dont la
valeur ne doit pas être modifiée :
De même, la valeur du tableau de caractères str déclaré dans l'instruction suivante ne peut pas non
plus être modifiée :
De plus, vous pouvez déclarer une variable de pointeur avec le modificateur const afin qu'un objet
pointé par le pointeur ne puisse pas être modifié. Par exemple, considérez la déclaration de pointeur
suivante avec le modificateur const :
Après l'initialisation, vous ne pouvez pas modifier le contenu de la chaîne pointée par le pointeur ptr_str.
Par exemple, l'instruction suivante n'est pas autorisée :
Cependant, le pointeur ptr_str luimême peut se voir attribuer une adresse différente d'une chaîne
déclarée avec char const.
Le modificateur volatil
Parfois, vous souhaitez déclarer une variable dont la valeur peut être modifiée sans aucune
instruction d'affectation explicite dans votre programme. Cela est particulièrement vrai lorsque vous
traitez directement avec du matériel. Par exemple, vous pouvez déclarer une variable globale qui
contient des caractères entrés par l'utilisateur. L'adresse de la variable est transmise à un registre de
périphérique qui accepte les caractères du clavier. Cependant, lorsque le compilateur C optimise
automatiquement votre programme, il a l'intention de ne pas mettre à jour la valeur détenue par la
variable à moins que la variable ne se trouve du côté gauche d'un opérateur d'affectation (=). En
d'autres termes, la valeur de la variable n'est probablement pas modifiée même si l'utilisateur tape
des caractères à partir du clavier.
Pour demander au compilateur de désactiver certaines optimisations sur une variable, vous pouvez
déclarer la variable avec le spécificateur volatile . Par exemple, dans la portion de code suivante,
une variable, keyboard_ch, déclarée avec le spécificateur volatil , indique au compilateur de ne pas 14
optimiser les expressions de la variable car la valeur enregistrée par la variable peut être modifiée
sans l'exécution d'une instruction d'affectation explicite. :
annuler read_keyboard() {
Machine Translated by Google
236 Heure 14
Résumé
Dans cette leçon, vous avez appris les concepts importants suivants sur les portées et les classes de
stockage en C :
• Une variable déclarée dans un bloc a une portée de bloc. Une telle variable est aussi appelée
variable locale et n'est visible que dans le bloc.
• Une étiquette goto a une portée de fonction, ce qui signifie qu'elle est visible à travers tout le bloc de la
fonction dans laquelle l'étiquette est placée. Il n'y a pas deux étiquettes goto qui partagent le même
nom dans un bloc fonction.
• Une variable déclarée avec le spécificateur statique en dehors d'une fonction a une portée de fichier,
ce qui signifie qu'elle est visible dans tout le fichier source dans lequel la variable est déclarée.
• Une variable déclarée en dehors d'une fonction est dite avoir une portée programme. Une telle variable
est également appelée variable globale. Une variable globale est visible dans tous les fichiers source
qui composent un programme exécutable. • Une variable avec une portée de bloc a la visibilité la plus
limitée. D'autre part, une variable avec une portée de programme est la plus visible et peut être vue à
travers tous les fichiers, fonctions et autres blocs qui composent le programme. • La classe de stockage
d'une variable fait référence à la combinaison de ses régions spatiales et temporelles (c'estàdire, sa
portée et sa durée.) • Par défaut, une variable avec une portée de bloc a une durée automatique et son
stockage en mémoire
• Une variable déclarée avec le spécificateur statique a un stockage permanent en mémoire, même après
que la fonction dans laquelle la variable est déclarée a été appelée et que la fonction
• Une variable déclarée avec le spécificateur de registre peut être stockée dans un registre pour
accélérer les performances d'un programme ; cependant, le compilateur peut ignorer le spécificateur
s'il n'y a pas de registre disponible ou si d'autres restrictions s'appliquent.
• Vous pouvez également faire allusion à une variable globale définie ailleurs en utilisant le
spécificateur extern du fichier source actuel.
Machine Translated by Google
• Pour vous assurer que la valeur enregistrée par une variable ne peut pas être modifiée, vous pouvez déclarer
variable avec le modificateur const .
• Si vous voulez faire savoir au compilateur que la valeur d'une variable peut être modifiée sans instruction
d'affectation explicite, déclarez la variable avec le modificateur volatile afin que le compilateur désactive
les optimisations sur les expressions impliquant la variable.
Dans la prochaine leçon, vous découvrirez les déclarations de fonctions et les prototypes en C.
Questions et réponses
Q Une variable globale peutelle être masquée par une variable locale avec une portée de bloc ?
R Oui. Si une variable locale partage le même nom avec une variable globale, la variable globale
La variable locale peut être masquée par la variable locale pour la portée du bloc dans lequel la variable
locale est définie avec la portée du bloc. Cependant, à l'extérieur du bloc, la variable locale n'est pas visible,
mais la variable globale redevient visible.
A Dans de nombreux cas, la valeur d'une variable est nécessaire, même si la portée du bloc, dans lequel la
variable est déclarée, est sortie. Par défaut, une variable avec une portée de bloc a un stockage en
mémoire temporaire, c'estàdire que la durée de vie de la variable commence lorsque le bloc est exécuté
et que la variable est déclarée, et se termine lorsque l'exécution de ce bloc est terminée. Par conséquent,
pour déclarer une variable à durée permanente, vous devez utiliser le spécificateur statique pour indiquer au
compilateur que l'emplacement mémoire de la variable et la valeur stockée dans l'emplacement mémoire
doivent être conservés après l'exécution du bloc.
R Pas vraiment. Déclarer une variable avec le spécificateur de registre ne fait que suggérer au compilateur
que la variable doit être stockée dans un registre. Mais il n'y a aucune garantie que la variable sera
stockée dans un registre. Le compilateur peut ignorer la demande en fonction de la disponibilité des
registres ou d'autres restrictions.
Q Lorsque vous déclarez une variable avec le spécificateur extern , définissezvous la vari
pouvoir ou faire allusion à une variable globale ailleurs ?
238 Heure 14
Atelier
Pour aider à consolider votre compréhension de cette leçon, nous vous encourageons à répondre aux
questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la leçon suivante. Les
réponses et les conseils aux questions et exercices sont donnés dans l'annexe B, « Réponses aux questions
et exercices du quiz ».
Questionnaire
1. Étant donné la portion de code suivante, quelles variables sont des variables globales et lesquelles
cellesci sont des variables locales avec une portée
de bloc ? int x = 0 ; flottant y = 0,0 ; int maFonction()
{
int je, j ;
flotter y ;
. . .
{
int x, y ;
. . .
}
. . .
}
2. Lorsque deux variables portant le même nom sont définies, comment le compilateur saitil laquelle
utiliser ?
Des exercices
1. Compte tenu de ce qui suit :
• Une variable int avec une portée de bloc et un stockage temporaire • Une
3. Compilez et exécutez le programme suivant. Qu'estce que vous obtenez à l'écran et pourquoi ?
#include <stdio.h> int
main() {
int je ;
} renvoie 0 ;
}
14
Machine Translated by Google
Machine Translated by Google
PARTIE IV
Fonctions et Dynamique
Allocation de mémoire
Heure
15 Utilisation des fonctions
16 Application de pointeurs
17 Allocation de mémoire
HEURE 15
—LH Sullivan
Dans l'heure 14, « Comprendre la portée et les classes de stockage », vous avez peut
être remarqué qu'une définition de fonction est toujours donnée en premier, avant que la
fonction ne soit appelée à partir d'une fonction main() . En fait, vous pouvez placer une
définition de fonction n'importe où, tant que vous placez la déclaration de fonction avant le
premier endroit où la fonction est appelée. Vous découvrirez de nombreuses fonctionnalités
des fonctions dans les rubriques suivantes abordées dans cette leçon :
• Déclarations de fonction
• Prototypage
• Valeurs renvoyées par les fonctions
Programmation structurée
244 Heure 15
Une déclaration de variable est une définition, mais une déclaration de fonction ne l'est pas. Une déclaration de
fonction fait allusion à une fonction définie ailleurs et spécifie le type de valeur renvoyée par la fonction. Une
définition de fonction définit ce que fait la fonction, ainsi que le nombre et le type d'arguments passés à la fonction.
Une déclaration de fonction n'est pas une définition de fonction. Si une définition de fonction est placée dans
votre fichier source avant que la fonction ne soit appelée pour la première fois, vous n'avez pas besoin de faire
la déclaration de fonction. Sinon, la déclaration d'une fonction doit être faite avant l'invocation de la fonction.
Par exemple, j'ai utilisé la fonction printf() dans presque tous les exemples de programme de ce livre. À
chaque fois, j'ai dû inclure un fichier d'entête, stdio.h, car le fichier d'entête contient la déclaration de printf(), qui
indique au compilateur le type de retour et le type de prototype de la fonction. La définition de la fonction printf()
est placée ailleurs.
En C, la définition de cette fonction est enregistrée dans un fichier de bibliothèque qui est invoqué pendant
les états de liaison.
Par défaut, le type de retour d'une fonction est int, si aucun type de données explicite n'est spécifié pour la fonction.
Un spécificateur de type de données est placé avant le nom d'une fonction comme ceci :
data_type_specifier function_name();
Ici data_type_specifier spécifie le type de données que la fonction doit renvoyer. nom_fonction est le nom
de la fonction qui doit suivre les règles de nommage des identificateurs en C.
création de la norme ANSI, une déclaration de fonction incluait uniquement le type de retour de la fonction. 15
Avec la norme ANSI, le nombre et les types d'arguments passés à une fonction peuvent être ajoutés dans la
déclaration de la fonction. Le nombre et les types d'un argument sont appelés le prototype de la fonction.
La forme générale d'une déclaration de fonction, y compris son prototype, est la suivante :
data_type_specifier function_name(
data_type_specifier argument_name1,
data_type_specifier argument_name2,
data_type_specifier argument_name3,
.
.
.
data_type_specifier argument_nameN,
);
Le but de l'utilisation d'un prototype de fonction est d'aider le compilateur à vérifier si les types de données des
arguments passés à une fonction correspondent à ce que la fonction attend. Le compilateur émet un message
d'erreur si les types de données ne correspondent pas.
Bien que les noms d'arguments, tels que nom_argument1, nom_argument2, etc., soient facultatifs, il est
recommandé de les inclure afin que le compilateur puisse identifier toute incompatibilité de noms d'arguments.
Un appel de fonction est une expression qui peut être utilisée comme une seule instruction ou dans d'autres
déclarations.
Le Listing 15.1 donne un exemple de déclaration et de définition de fonctions, ainsi que d'appels de fonction.
TAPER
LISTE 15.1 Appeler des fonctions après qu'elles aient été déclarées et définies
7: printf("Dans function_2.\n");
continue
Machine Translated by Google
246 Heure 15
FIGURE 15.1
L'exécution du Début
prog
Flux
d'ex
du Une fonction
Exécution
Une fonction
Revenir
Finir
Machine Translated by Google
Le but du programme du Listing 15.1 est de vous montrer comment déclarer et définir des
UNE ANALYSE
fonctions. L'instruction de la ligne 4 est une déclaration de fonction avec un type prototype.
La déclaration fait allusion à la fonction_1 définie plus loin dans le Listing 15.1. Le type de retour de
function_1 est int, et le prototype de la fonction inclut deux variables int , appelées x et y.
Aux lignes 5 à 9, la deuxième fonction, function_2, est définie avant d'être appelée. Comme vous
pouvez le voir, le type de retour de function_2 est double et deux variables doubles sont passées à la
fonction. Notez que les noms des deux variables sont également x et y. Ne vous inquiétez pas car
function_1 et function_2 partagent les mêmes noms d'arguments. Il n'y a pas de conflit car ces
arguments se trouvent dans des blocs fonctionnels différents et les arguments des fonctions ont une
portée de bloc.
Ensuite, dans la fonction main() définie aux lignes 11 à 23, deux variables int , x1 et y1, et deux
variables doubles , x2 et y2, sont déclarées et initialisées aux lignes 13 à 16, respectivement.
L'instruction de la ligne 18 affiche les valeurs de x1 et y1 transmises à la fonction function_1. La ligne
19 appelle la fonction_1 et affiche la valeur renvoyée par la fonction_1.
Fonctions de prototypage
Dans les soussections suivantes, vous allez étudier trois cas concernant les arguments passés
aux fonctions. Le premier cas est que les fonctions ne prennent aucun argument ; la seconde est
que les fonctions prennent un nombre fixe d'arguments ; le troisième cas est que les fonctions
prennent un nombre variable d'arguments.
Machine Translated by Google
248 Heure 15
Comme vous pouvez le voir, la deuxième instruction est laissée vide entre les parenthèses (( et ))
lorsque la fonction est appelée.
int getchar(vide);
Notez que le mot clé void est utilisé dans la déclaration pour indiquer au compilateur qu'aucun argument
n'est requis par cette fonction. Le compilateur émettra un message d'erreur si un argument est passé à
getchar() plus tard dans un programme lorsque cette fonction est appelée.
Par conséquent, pour une fonction sans argument, le type de données void est utilisé comme prototype dans
la déclaration de la fonction.
Le programme du Listing 5.2 montre un autre exemple d'utilisation de void dans les déclarations
de fonction.
TAPER
LISTE 15.2 Utilisation de void dans les déclarations de fonction
4:
5 : annuler GetDateTime(annuler) ;
6 : 7 : principal() 8 : { 9 : 10 : 11 : 12 : 13 : }
J'obtiens la sortie suivante après avoir exécuté le fichier exécutable, 15L02.exe, du programme du
Listing 15.2 :
15
Avant l'appel de la fonction GetDateTime().
SORTIR Dans GetDateTime().
La date et l'heure actuelles sont : Sam Apr 05 11:50:10 1997
Le but du programme du Listing 15.2 est de vous montrer comment déclarer et appeler une
UNE ANALYSE
fonction sans passer d'arguments. Le programme imprime la date et l'heure actuelles sur
votre ordinateur en appelant la fonction GetDateTime(), déclarée à la ligne 5. Comme aucun argument
ne doit être passé à la fonction, le type de données void est utilisé comme prototype dans la déclaration
de GetDateTime ().
De plus, un autre motclé void est utilisé devant le nom de la fonction GetDateTime() pour indiquer
que cette fonction renvoie une valeur non plus (voir ligne 5.)
Les instructions des lignes 9 et 11 impriment des messages avant et après l' appel de la
fonction GetDateTime() depuis la fonction main() .
A la ligne 10, la fonction est appelée par l'instruction GetDateTime();. Notez qu'aucun argument ne
doit être passé à cette fonction car le prototype de la fonction est vide.
La définition de GetDateTime() est aux lignes 15–23 ; il obtient l'heure calendaire et la convertit en
une chaîne de caractères en appelant plusieurs fonctions de la bibliothèque C : time(), local time() et
asctime(). Ensuite, la chaîne de caractères contenant la date et l'heure courantes est imprimée à l'écran
par la fonction printf() avec le spécificateur de format %s. Comme vous pouvez le voir, la sortie sur mon
écran montre qu'au moment où le fichier exécutable 15L02.exe est en cours d'exécution, la date et
l'heure sont
time(), localtime() et asctime() sont des fonctions de date et d'heure fournies par le langage C.
Ces fonctions sont décrites dans la soussection suivante. Vous remarquerez peutêtre que le
fichier d'entête time.h est inclus au début du programme dans le Listing 15.2 avant que ces
fonctions temporelles puissent être utilisées.
• Heure calendaire
• Heure locale
250 Heure 15
Ici , l'heure calendaire donne la date et l'heure actuelles basées sur le calendrier grégorien.
L'heure locale représente l'heure du calendrier dans un fuseau horaire spécifique. L'heure d'été est
l'heure locale selon la règle de l'heure d'été.
Dans cette section, trois fonctions de date et d'heure — time(), localtime() et asctime() — sont
brièvement présentées.
Ici, time_t est le type arithmétique utilisé pour représenter le temps. timer est une variable de
pointeur pointant vers une mémoire de stockage pouvant contenir l'heure calendaire renvoyée par
cette fonction. La fonction time() renvoie 1 si l'heure du calendrier n'est pas disponible sur
, l'ordinateur.
Ici tm est une structure qui contient les composantes du temps calendaire. struct est le motclé
pour structure, qui est un autre type de données en C. (Le concept de structures est introduit dans
l'Heure 19, « Comprendre les structures ». ) fonction temps() .
,
Pour convertir la date et l'heure représentées par la structure tm, vous pouvez appeler la fonction
asctime() .
Ici, timeptr est un pointeur faisant référence à la structure tm renvoyée par les fonctions de date
et d'heure comme localtime(). La fonction asctime() convertit la date et l'heure représentées par tm
, en une chaîne de caractères.
Comme le montre le Listing 15.2, l'instruction de la ligne 17 déclare une variable time_t appelée now.
La ligne 20 stocke l'heure du calendrier dans l'emplacement mémoire référencé par la variable now .
Notez que l'argument passé à la fonction time() doit être la valeur de gauche d'une variable ; par
conséquent, l'opérateur d'adresse (&) est utilisé jusqu'à présent. Ensuite, l'expression dans
Machine Translated by Google
ligne 22, asctime(localtime(&now)), obtient l'expression de l'heure locale de l'heure calendaire en appelant
localtime(), et convertit l'heure locale en une chaîne de caractères à l'aide de asctime(). La chaîne de caractères
15
représentant la date et l'heure est ensuite imprimée par l' appel printf() aux lignes 21 et 22, qui a le format
suivant :
Notez qu'il y a un caractère de saut de ligne ajouté juste avant le caractère nul dans la chaîne de
caractères qui est convertie et renvoyée par la fonction asctime() .
Pour déclarer une fonction avec un nombre fixe d'arguments, vous devez spécifier le type de données de
chaque argument. De plus, il est recommandé d'indiquer les noms d'arguments afin que le compilateur
puisse vérifier que les types et noms d'arguments déclarés dans une déclaration de fonction correspondent
à l'implémentation dans la définition de fonction.
Ici, le jeton de points de suspension ... (c'estàdire trois points) représente un nombre variable
d'arguments. Autrement dit, outre le premier argument qui est une chaîne de caractères, la fonction printf()
peut prendre un nombre indéterminé d'arguments supplémentaires, autant que le compilateur le permet. Les
crochets ([ et ]) indiquent que les arguments non spécifiés sont facultatifs.
Voici une forme générale pour déclarer une fonction avec un nombre variable d'argu
commentaires :
data_type_specifier
function_name( data_type_specifier argument_name1, ...
);
Notez que le nom du premier argument est suivi des points de suspension (...) qui représentent le reste des
arguments non spécifiés.
Machine Translated by Google
252 Heure 15
Un type de données, va_list, est également inclus dans stdarg.h , qui définit un type de tableau
approprié pour contenir les éléments de données nécessaires à va_start(), va_arg() et va_end().
Pour initialiser un tableau donné nécessaire à va_arg() et va_end(), vous devez utiliser la
routine de macro va_start() avant que les arguments ne soient traités.
Ici ap est le nom du tableau qui est sur le point d'être initialisé par la macroroutine va_start() .
lastfix doit être l'argument avant les points de suspension (...) dans la déclaration de la fonction.
,
En utilisant la macro va_arg() , vous pouvez traiter une expression qui a le type et la valeur
de l'argument suivant. En d'autres termes, la macro va_arg() peut être utilisée pour obtenir le
prochain argument passé à la fonction.
Ici ap est le nom du tableau qui est initialisé par la macroroutine va_start() . data_type est
, le type de données de l'argument passé à la fonction.
Pour faciliter un retour normal de votre fonction, vous devez utiliser la fonction va_end() dans
votre programme après que tous les arguments ont été traités.
Ici ap est le nom du tableau qui est initialisé par la macroroutine va_start() .
,
N'oubliez pas d'inclure le fichier d'entête stdarg.h dans votre programme avant d'appeler
va_start(), va_arg() ou va_end().
Machine Translated by Google
Le Listing 5.3 montre comment utiliser va_start(), va_arg() et va_end() dans une fonction
qui prend un nombre variable d'arguments. 15
TAPER
LISTE 15.3 Traitement des arguments variables
1 : /* 15L03.c : Traitement des arguments de variable */ 2 : #include
<stdio.h> 3 : #include <stdarg.h> 4 :
printf("Arguments donnés : %2.1f, %2.1f et %2.1f\n", d1, d2, d3); printf("Le résultat renvoyé par
18h19h20h21h
AddDouble() est : %2.1f\n\n", AddDouble(3, d1, d2, d3)); printf("Arguments donnés : %2.1f, %2.1f,
22: %2.1f et %2.1f\n", d1, d2, d3, d4); printf("Le résultat renvoyé par AddDouble() est : %2.1f\n",
23:
24:
42 : }
Machine Translated by Google
254 Heure 15
Le programme du Listing 15.3 contient une fonction qui peut prendre un nombre variable d'
UNE ANALYSE
arguments doubles , effectuer l'opération d'addition sur ces arguments, et
puis renvoyez le résultat à la fonction main() .
La définition de AddDouble() est donnée aux lignes 29 à 41, dans lesquelles un tableau
va_list, arglist , est déclaré à la ligne 31. Comme mentionné, la macro va_start() doit être appelée
avant que les arguments ne soient traités. Ainsi, la ligne 36 invoque va_start() pour initialiser le
tableau arglist. La boucle for des lignes 37 et 38 récupère le double argument suivant enregistré
dans le tableau arglist en appelant va_arg(). Ensuite, chaque argument est ajouté dans une double
variable locale appelée résultat.
La fonction va_end() est appelée à la ligne 39 après que tous les arguments enregistrés dans
arglist ont été récupérés et traités. Ensuite, la valeur de result est renvoyée à l'appelant de la
fonction AddDouble() , qui est la fonction main() dans ce cas.
La fonction va_end() doit être appelée dans un programme C pour terminer le traitement des
arguments variables. Sinon, le comportement du programme est indéfini.
Comme vous pouvez le voir, dans la fonction main() , AddDouble() est appelée quatre fois, avec un
nombre différent d'arguments à chaque fois. Ces arguments passés à AddDouble() sont affichés par
les appels printf() aux lignes 14, 17, 20 et 23. De plus, les quatre résultats différents renvoyés par
AddDouble() sont affichés à l'écran.
Machine Translated by Google
Lorsque vous commencez à écrire un programme pour résoudre un problème, une façon de le faire est de travailler
sur les plus petits éléments du problème. Tout d'abord, vous définissez et écrivez des fonctions pour chaque
élément. Une fois chaque fonction écrite et testée, vous commencez à les assembler pour créer un programme
capable de résoudre le problème. Cette approche est normalement appelée programmation ascendante.
En revanche, pour résoudre un problème, vous pouvez d'abord élaborer un schéma et commencer votre
programmation à un niveau supérieur. Par exemple, vous pouvez travailler sur la fonction main() au début, puis
passer au niveau inférieur suivant jusqu'à ce que les fonctions de niveau le plus bas soient écrites dix. Ce type
d'approche est appelé programmation descendante.
Vous constaterez qu'il est utile de combiner ces deux types de programmation structurée et de les utiliser
alternativement afin de résoudre de vrais problèmes.
Résumé
Dans cette leçon, vous avez appris les concepts importants suivants sur les fonctions en C :
• Une déclaration de fonction fait allusion à une fonction qui est définie ailleurs et spécifie également le type
d'arguments et de valeurs qui sont passés à et renvoyés par la fonction.
• Une définition de fonction réserve l'espace mémoire et définit ce que fait la fonction, ainsi que le nombre
et le type d'arguments passés à la fonction. • Une fonction peut être déclarée pour renvoyer n'importe
quel type de données, à l'exception d'un tableau ou d'une fonction. • L' instruction return utilisée dans une
définition de fonction renvoie une seule valeur dont le type doit correspondre à celui déclaré dans la
déclaration de fonction. • Un appel de fonction est une expression qui peut être utilisée comme une seule
instruction ou dans
d'autres expressions ou déclarations.
• Le type de données void est nécessaire dans la déclaration d'une fonction qui ne prend aucun argument
ment.
• Pour déclarer une fonction qui prend un nombre variable d'arguments, vous devez spécifier au moins le
premier argument et utiliser les points de suspension (...) pour représenter le reste des arguments passés
à la fonction.
Machine Translated by Google
256 Heure 15
• va_start(), va_arg() et va_end(), tous inclus dans stdarg.h, sont nécessaires pour traiter un nombre variable
d'arguments passés à une fonction.
• time(), localtime() et asctime() sont trois fonctions temporelles fournies par C. Elles peuvent être utilisées ensemble
pour obtenir une chaîne de caractères contenant des informations sur la date et l'heure locales basées sur l'heure
calendaire.
Dans la leçon suivante, vous en apprendrez plus sur les pointeurs et leurs applications en C.
Questions et réponses
Q Quelle est la principale différence entre une déclaration de fonction et une fonction
définition?
A La principale différence entre une déclaration de fonction et une définition de fonction est que
le premier ne réserve aucun espace mémoire et ne spécifie pas non plus ce que fait une fonction. Une déclaration
de fonction fait uniquement allusion à une définition de fonction placée ailleurs. Il spécifie également quel type
d'arguments et de valeurs sont passés à et renvoyés par la fonction. Une définition de fonction, en revanche,
réserve l'espace mémoire et spécifie les tâches que la fonction peut accomplir.
A En déclarant une fonction avec des prototypes, vous spécifiez non seulement le type de données
retourné par la fonction, mais aussi les types et les noms des arguments passés à la fonction. A l'aide d'un
prototype de fonction, le compilateur peut vérifier automatiquement par type de formulaire la définition de la
fonction, ce qui vous fait gagner du temps lors du débogage du programme.
R Oui. En fait, une fonction peut renvoyer une seule valeur qui peut être n'importe quel type de données à l'exception
d'un tableau ou d'une fonction. Une valeur de pointeur, c'estàdire l'adresse, renvoyée par une fonction peut faire
référence à un tableau de caractères ou à un emplacement mémoire qui stocke d'autres types de données.
Par exemple, la fonction asctime() de la bibliothèque C renvoie un pointeur de caractère qui pointe vers
une chaîne de caractères convertie à partir d'une structure dateheure.
R Oui. En pratique, vous pouvez constater que c'est en fait une bonne idée de combiner le haut
approches de programmation descendante et ascendante pour résoudre des problèmes. L'utilisation des deux
types de programmation structurée peut rendre votre programme facile à écrire et à comprendre.
Machine Translated by Google
Atelier 15
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons
à répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer
à la leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans
l'annexe B, « Réponses aux questions et exercices du quiz ».
Questionnaire
1. Étant donné les déclarations de fonction suivantes, lesquelles sont des fonctions avec
nombre d'arguments, lesquels sont des fonctions sans arguments et lesquels sont des fonctions
avec un nombre variable d'arguments ?
• int fonction_3(vide);
• void function_5(void);
2. Laquelle des deux expressions suivantes est une définition de fonction ? int
fonction_1(int x, int y); int function_2(int x, int y){retour x+y ;}
3. Quel est le type de données renvoyé par une fonction lorsqu'un spécificateur de type est omis ?
• fonction char_3(...);
Des exercices
1. Réécrivez le programme du Listing 15.2. Cette fois, utilisez le spécificateur de format %c, au
lieu de %s, pour imprimer la chaîne de caractères de l'heure locale sur votre ordinateur.
2. Déclarez et définissez une fonction, appelée MultiTwo(), qui peut effectuer une multiplication sur
deux variables entières. Appelez la fonction MultiTwo() à partir de la fonction main() et
transmettez deux entiers à MultiTwo(). Imprimez ensuite le résultat renvoyé par la fonction
MultiTwo() à l'écran.
Machine Translated by Google
258 Heure 15
3. Réécrivez le programme du Listing 15.3. Cette fois, créez une fonction qui prend un nombre
variable d' arguments int et effectue l'opération de multiplication sur ces arguments.
4. Réécrivez à nouveau le programme du Listing 15.3. Cette fois, imprimez tous les arguments
passé à la fonction AddDouble() . Estce que va_arg() récupère chaque argument dans le
même ordre (c'estàdire de gauche à droite) de la liste d'arguments passée à AddDouble() ?
Machine Translated by Google
HEURE 16
Application de pointeurs
Réfléchissez à deux fois et faites une fois.
Proverbe chinois
Dans l'heure 11, « Comprendre les pointeurs », vous avez appris les bases de l'utilisation des
pointeurs en C. Comme les pointeurs sont très utiles en programmation, cela vaut la peine de
consacrer une heure de plus à en apprendre davantage à leur sujet. Dans cette leçon, les sujets
suivants sont abordés :
Arithmétique du pointeur
En C, vous pouvez déplacer la position d'un pointeur en ajoutant ou en soustrayant des
entiers vers ou depuis le pointeur. Par exemple, étant donné une variable de pointeur de
caractère ptr_str, l'expression suivante :
ptr_str + 1
Machine Translated by Google
260 Heure 16
déplace le pointeur vers l'emplacement mémoire situé à un octet de la position actuelle de ptr_str.
Notez que pour les pointeurs de différents types de données, les entiers ajoutés ou soustraits aux pointeurs
ont des tailles différentes. En d'autres termes, ajouter (ou soustraire) 1 à un pointeur n'indique pas
nécessairement au compilateur d'ajouter (ou de soustraire) un octet à l'adresse, mais plutôt d'ajuster
l'adresse de manière à ce qu'elle saute un élément du type du aiguille.
Vous verrez plus de détails dans les sections suivantes.
nom_pointeur + n
Ici n est un entier dont la valeur peut être positive ou négative. pointer_name est le nom d'une variable de
pointeur qui a la déclaration suivante :
spécificateur_type_données *nom_pointeur ;
pointer_name + n * sizeof(data_type_specifier)
Notez que l' opérateur sizeof est utilisé pour obtenir le nombre d'octets du type de données spécifié. Par
conséquent, pour la variable de pointeur char ptr_str, l'expression ptr_str + 1 signifie en réalité
ptr_str + 1 * sizeof(char).
Étant donné que la taille d'un caractère est d'un octet, ptr_str + 1 indique au compilateur de se déplacer
vers l'emplacement mémoire situé 1 octet après l'emplacement actuel référencé par le pointeur.
Le programme du Listing 16.1 montre comment les tailles scalaires des différents types de données
affectent les décalages ajoutés ou soustraits aux pointeurs.
char *ptr_ch;
entier *ptr_int;
double *ptr_db ; /*
pointeur de caractère ptr_ch */
8 : 9 : 10 : printf("Position actuelle de ptr_ch : %p\n", ptr_ch);
Machine Translated by Google
renvoie 0 ;
Comme vous pouvez le voir dans le Listing 16.1, il existe trois pointeurs de types
UNE ANALYSE
différents — ptr_ch, ptr_int et ptr_db — déclarés aux lignes 6–8. Parmi eux, ptr_ch est un
pointeur vers un caractère, ptr_int est un pointeur vers un entier et ptr_db est un pointeur vers un
double.
Ensuite, l'instruction de la ligne 10 montre l'adresse mémoire, 0x000B, contenue par la variable de
pointeur char ptr_ch. Les lignes 11 et 12 affichent les deux adresses, 0x000C et 0x000D, lorsque ptr_ch
est additionné de 1 et 2, respectivement. De même, les lignes 13 et 14 donnent 0x000A
Machine Translated by Google
262 Heure 16
et 0x0009 lorsque ptr_ch est déplacé vers le bas vers des adresses mémoire inférieures. Étant donné
que la taille de char est de 1 octet, ptr_ch+1 signifie se déplacer vers l'emplacement mémoire supérieur
d'un octet à l'emplacement mémoire actuel, 0x000B, référencé par le pointeur ptr_ch.
La ligne 16 montre l'emplacement mémoire référencé par la variable de pointeur int ptr_int à 0x028B.
Étant donné que la taille de int est de 2 octets sur mon système, l'expression ptr_int + 1 déplace ptr_int
vers l'emplacement mémoire supérieur de 2 octets à celui pointé par ptr_int. C'est exactement le résultat
que vous voyez à la ligne 17. De même, la ligne 18 montre que ptr_int+2 déplace la référence vers
0x028F, qui est 4 octets plus haut (2*sizeof(int)) que 0x028B. L'emplacement mémoire 0x0289 est
référencé par l'expression ptr_int1 à la ligne 19 ; 0x0287 est référencé par ptr_int2 à la ligne 20.
La taille du type de données double est de 8 octets sur mon système. Par conséquent, l'expression
ptr_db+1 est interprétée comme l'adresse mémoire référencée par ptr_db plus 8 octets, c'estàdire
0x0128+8, ce qui donne 0x0130 au format hexadécimal, comme vous pouvez le voir à la ligne 23.
Les lignes 24 à 26 affichent les adresses mémoire référencées respectivement par ptr_db+2,
ptr_db1 et ptr_db2, ce qui prouve que le compilateur a utilisé la même taille scalaire de double dans
l'arithmétique du pointeur.
Les pointeurs sont très utiles lorsqu'ils sont utilisés correctement. Cependant, un pointeur peut vous
attirer rapidement des ennuis s'il contient la mauvaise valeur. Une erreur courante, par exemple,
consiste à attribuer une valeur droite à un pointeur qui attend en fait une valeur gauche.
Heureusement, de nombreux compilateurs C trouveront de telles erreurs et émettront un avertissement
message.
Il existe une autre erreur courante que le compilateur ne détecte pas toujours pour vous :
l'utilisation de pointeurs non initialisés. Par exemple, le code suivant a un problème potentiel : int
x, *ptr_int; x = 8 ; *ptr_int = x ;
Le problème est que le pointeur ptr_int n'est pas initialisé ; il pointe vers un emplacement de
mémoire inconnu. Par conséquent, l'attribution d'une valeur, comme 8 dans ce cas, à un
emplacement de mémoire inconnu est dangereuse. Il peut écraser certaines données importantes
qui sont déjà enregistrées à l'emplacement de la mémoire, causant ainsi un sérieux problème. La
solution consiste à s'assurer qu'un pointeur pointe vers un emplacement mémoire légal et valide
avant de l'utiliser.
Vous pouvez réécrire le code cidessus pour éviter le problème potentiel comme celuici : int x,
/* initialise le pointeur */
Machine Translated by Google
Soustraction de pointeur
Vous pouvez soustraire une valeur de pointeur de l'autre pour obtenir la distance entre les deux
emplacements de mémoire. Par exemple, étant donné deux variables de pointeur char , ptr_str1 et
ptr_str2, vous pouvez calculer le décalage entre les deux emplacements mémoire pointés par les deux
pointeurs comme ceci :
ptr_str2 ptr_str1
Pour obtenir des résultats significatifs, il est préférable de soustraire uniquement les pointeurs du même type de données.
16
Le Listing 16.2 montre un exemple de soustraction sur une variable de pointeur int .
renvoie 0 ;
Après avoir exécuté l'exécutable (16L02.exe) du programme du Listing 16.2 sur ma machine, j'ai la sortie
suivante affichée à l'écran :
Le programme du Listing 16.2 déclare deux variables de pointeur int , ptr_int1 et ptr_int2, à
UNE ANALYSE
la ligne 6. L'instruction de la ligne 8 imprime la position mémoire détenue par ptr_int1. La
ligne 9 affecte l'adresse mémoire référencée par ptr_int1+5 à ptr_int2.
Ensuite, le contenu de ptr_int2 est imprimé à la ligne 10.
Machine Translated by Google
264 Heure 16
L'instruction de la ligne 11 montre la différence entre les deux pointeurs int , c'estàdire la soustraction de
ptr_int2 et ptr_int1. Le résultat est 5.
La ligne 12 attribue alors une autre adresse mémoire, référencée par l'expression ptr_int15, au pointeur
ptr_int2 . Maintenant, ptr_int2 pointe vers un emplacement mémoire inférieur de 10 octets à l'emplacement
mémoire pointé par ptr_int1 (voir la sortie faite par la ligne 13.)
La différence entre ptr_int2 et ptr_int1 est obtenue par la soustraction des deux pointeurs, qui est 5
(puisqu'un int sur ma machine est de deux octets) tel qu'imprimé par l'instruction de la ligne 14.
Pointeurs et tableaux
Comme indiqué dans les leçons précédentes, les pointeurs et les tableaux ont une relation étroite. Vous
pouvez accéder à un tableau via un pointeur qui contient l'adresse de début du tableau. La soussection
suivante présente comment accéder aux éléments du tableau via des pointeurs.
En d'autres termes, étant donné un tableau, un tableau et un pointeur, ptr_array, si tableau et ptr_array sont
du même type de données, et ptr_array contient l'adresse de début du tableau, c'estàdire
ptr_array = tableau ;
*(tableau_ptr + n)
Le Listing 16.3 montre comment accéder aux tableaux et modifier les valeurs des éléments du tableau à
l'aide de pointeurs.
La sortie suivante s'affiche après la création et l'exécution du fichier exécutable 16L03.exe sur mon
ordinateur :
Le but du programme du Listing 16.3 est de vous montrer comment accéder à un tableau
UNE ANALYSE
char , str, et à un tableau int , list. Aux lignes 6 et 8, str et list sont déclarés et initialisés avec
une chaîne et un ensemble d'entiers, respectivement. Un pointeur char , ptr_str, et un pointeur int ,
ptr_int, sont déclarés aux lignes 7 et 9.
La ligne 12 affecte l'adresse de début du tableau str au pointeur ptr_str . Les instructions des lignes 13
et 14 montrent le contenu de la chaîne enregistrée dans le tableau str , ainsi que le caractère contenu
par l' élément str[5] dans le tableau avant toute modification .
à str.
La déclaration de la ligne 15 montre que la constante de caractère, 'A', est assignée à l'élément du
tableau str pointé par l'expression
*(ptr_str + 5)
Pour vérifier que le contenu de l'élément dans str a été mis à jour, les lignes 16 et 17 impriment
respectivement l'élément et la chaîne entière. La sortie indique que 'A' a remplacé la constante de
caractère d'origine, 'a'.
Machine Translated by Google
266 Heure 16
L'adresse de début de la liste de tableaux int est affectée au pointeur ptr_int à la ligne 19.
Avant de faire quoi que ce soit avec l' élément list[2] du tableau list , j'affiche sa valeur, qui est 3 en ce
moment (voir la sortie faite par la ligne 20). À la ligne 21, l' élément list[2] reçoit une autre valeur, 3, via
le pointeur déréférencé *(ptr_int + 2). L' appel printf() à la ligne 22 imprime la valeur mise à jour de list[2] .
Pointeurs et fonctions
Avant de commencer à parler de la transmission de pointeurs vers des fonctions, voyons d'abord comment
transmettre des tableaux à des fonctions.
Le programme du Listing 16.4 montre comment passer un tableau d'entiers à une fonction.
La sortie suivante est obtenue après avoir exécuté l'exécutable, 16L04.exe, et saisi trois nombres
entiers, 10, 20 et 30, sur ma machine :
Le but du programme du Listing 16.4 est d'obtenir trois entiers entrés par l'utilisateur, puis de
UNE ANALYSE
passer les trois entiers sous forme de tableau à une fonction appelée AddThree() pour
effectuer l'opération d'addition. 16
La ligne 4 donne la déclaration de la fonction AddThree() . Notez que le tableau non dimensionné,
list[], est utilisé dans l'expression d'argument, ce qui indique que l'argument contient l'adresse de
début du tableau de liste .
Le tableau list et une variable entière, sum, sont déclarés à la ligne 8. L' appel printf() à la ligne 10
affiche un message demandant à l'utilisateur d'entrer trois entiers. Ensuite, la ligne 11 utilise scanf()
pour récupérer les entiers saisis par l'utilisateur et les stocke dans les trois emplacements mémoire
des éléments du tableau d'entiers référencés par &list[0], &list[1] et &list[2], respectivement.
L'instruction de la ligne 12 appelle la fonction AddThree() avec le nom du tableau comme argument. L'
expression AddThree(list) transmet en fait l'adresse de début du tableau de liste (&list[0]) à la fonction
AddThree() .
La définition de la fonction AddThree() se trouve aux lignes 18–26 ; il ajoute les valeurs des trois
éléments dans le tableau de liste et renvoie le résultat de l'addition. Le résultat renvoyé par la fonction
AddThree() est affecté à la variable entière sum à la ligne 12 et est imprimé à la ligne 13.
Vous pouvez également spécifier la taille d'un tableau transmis à une fonction. Par
exemple, les éléments suivants :
[]); N'oubliez pas que le compilateur peut déterminer la taille du tableau non
dimensionné str[].
Pour les tableaux multidimensionnels, le format d'un tableau non dimensionné doit
toujours être utilisé dans la déclaration. (Voir la section intitulée "Passer des tableaux
multidimensionnels en tant qu'arguments", plus tard dans cette heure.)
Machine Translated by Google
268 Heure 16
Le Listing 16.5 montre un exemple de passage de pointeurs vers des fonctions, qui est similaire au
passage de tableaux passés à des fonctions.
printf("%s\n", ch);
int je ;
entier somme = 0 ;
Machine Translated by Google
Après avoir exécuté le programme 16L05.exe , j'obtiens la sortie suivante affichée sur l'écran de mon
ordinateur :
SORTIR
C'est une chaîne ! 16
C'est une chaîne !
La somme renvoyée par DataAdd() : 15 La
somme renvoyée par DataAdd() : 15
Le but du programme du Listing 16.5 est de montrer comment passer deux pointeurs (un
UNE ANALYSE
pointeur entier qui pointe sur un tableau d'entiers et un pointeur caractère qui référence
une chaîne de caractères) à deux fonctions déclarées aux lignes 4 et 5.
Notez que des expressions telles que char *ch et int *list sont utilisées comme arguments dans les
déclarations de fonction, ce qui indique au compilateur qu'un pointeur char et un pointeur int sont
respectivement passés aux fonctions ChPrint() et DataAdd().
Dans le corps de la fonction main() , les lignes 8 et 9 déclarent un tableau de caractères (str) initialisé
avec une chaîne de caractères et une variable de pointeur de caractères (ptr_str). La ligne 10 déclare
et initialise un tableau int (liste) avec un ensemble d'entiers. Une variable de pointeur int , ptr_int, est
déclarée à la ligne 11.
L'adresse de début du tableau str est affectée au pointeur ptr_str par l'instruction d'affectation de la
ligne 14. Ensuite, le pointeur ptr_str est passé à la fonction ChPrint() comme argument de la ligne 15.
Selon la définition de ChPrint() dans lignes 27 à 30, le contenu du tableau str dont l'adresse de début
est transmise à la fonction lorsque l'argument est imprimé par l' appel printf() à l'intérieur de la fonction
ChPrint() à la ligne 29.
En fait, vous pouvez toujours utiliser le nom du tableau str comme argument et le passer à la
fonction ChPrint() . La ligne 16 montre que l'adresse de début du tableau de caractères est passée à
ChPrint() via le nom du tableau.
L'instruction de la ligne 19 affecte l'adresse de début de la liste de tableaux d'entiers au pointeur d'entier
ptr_int. Ensuite, le pointeur ptr_int est passé à la fonction DataAdd() à la ligne 21, avec 5, qui est le
nombre maximum d'éléments contenus par le tableau de liste . L'argument max est utilisé car la
fonction ne peut pas déterminer la taille du tableau étant donné uniquement l'adresse de début. À partir
de la définition de la fonction DataAdd() aux lignes 32 à 40, vous pouvez voir que DataAdd() ajoute tous
les éléments entiers de la liste et renvoie la somme à l'appelant. Par la suite, l'instruction des lignes 20
et 21 imprime le résultat renvoyé par DataAdd().
Machine Translated by Google
270 Heure 16
L'expression de la ligne 23 invoque également la fonction DataAdd() , mais cette fois, le nom du tableau de
liste est utilisé comme argument de la fonction. Sans surprise, l'adresse de début du tableau de liste est
transmise avec succès à la fonction DataAdd() et l' instruction printf() des lignes 22 et 23 affiche le résultat
correct à l'écran.
Comme vous l'avez peutêtre deviné, passer un tableau multidimensionnel à une fonction revient à passer
un tableau unidimensionnel à une fonction. Vous pouvez soit transmettre le format non dimensionné d'un
tableau multidimensionnel, soit un pointeur contenant l'adresse de début du tableau multidimensionnel à une
fonction. Le Listing 16.6 est un exemple de ces deux méthodes.
int je, j ;
entier somme = 0 ;
25 : 26 : 27 pour
: (i=0; i<max1; i++)
28 : pour (j=0; j<max2; j++) somme
29 : += liste[i][j]; somme de retour ;
30 :
31 : }
Machine Translated by Google
32 : /* définition de la fonction */ 33 :
int DataAdd2(int *list, int max1, int max2) 34 : { 35 : 36 : 37 :
38 : 39 : 40 : 41 : 42 : }
int je, j ;
entier somme = 0 ;
La sortie suivante s'affiche sur l'écran de mon ordinateur après l'exécution de l'exécutable
(16L06.exe) :
La somme renvoyée par DataAdd1() : 30
SORTIR La somme retournée par DataAdd2() : 30
UNE ANALYSE Au début du programme du Listing 16.6, je déclare deux fonctions, DataAdd1() et
DataAdd2(), aux lignes 4 et 5. Notez que le premier argument de DataAdd1() à la ligne 4
est le tableau non dimensionné de list. En fait, list est un tableau d'entiers à deux dimensions
déclaré aux lignes 9 et 10 à l'intérieur du corps de la fonction main() . Les deux autres arguments,
max1 et max2, sont deux tailles de dimension du tableau de liste .
Comme vous pouvez le constater à partir de la définition de DataAdd1() aux lignes 22 à 31, chaque
élément du tableau de liste , exprimé sous la forme list[i][j], est ajouté et affecté à une variable locale
appelée sum qui est renvoyée à la fin de la fonction DataAdd1() à la ligne 30. Ici, i va de 0 à max1 1, et
j est compris entre 0 et max2 1.
La fonction DataAdd1() est appelée à la ligne 14, avec le nom du tableau de liste et les deux tailles
de dimension, 2 et 5. Le résultat renvoyé par DataAdd1() est imprimé par l'instruction aux lignes 13
et 14. Vous voyez donc , le passage d'un tableau multidimensionnel à une fonction est assez similaire
au passage d'un tableau unidimensionnel à une fonction. La fonction, dans ce cas, a besoin des deux
tailles de dimension pour déterminer le nombre total d'éléments dans le tableau.
Une autre façon de faire le travail consiste à passer un pointeur contenant l'adresse de début d'un
tableau multidimensionnel à une fonction. Dans cet exemple, la fonction DataAdd2() est déclarée à la
ligne 5 avec une expression de pointeur, int *list, comme premier argument de la fonction. La définition
de DataAdd2() est donnée aux lignes 33–42.
Notez qu'à la ligne 40, chaque élément du tableau de liste est récupéré en déplaçant le pointeur
pour pointer vers l'emplacement mémoire de l'élément. Autrement dit, le pointeur déréférencé *(list +
i*max2 + j) donne la valeur d'un élément situé à la ligne i et à la colonne j, si vous imaginez que le
tableau à deux dimensions est une matrice à la fois horizontale et verticale dimensions cal. Par
conséquent, l'ajout de i*max2 à la liste calcule l'adresse de la ligne i (c'estàdire,
Machine Translated by Google
272 Heure 16
en sautant les lignes 0 à i1), puis en ajoutant j calcule l'adresse de l'élément j (c'estàdire la colonne j)
dans la ligne actuelle (i). Dans cet exemple, la plage de la ligne va de 0 à 1 (c'estàdire un total de 2
lignes) ; la plage de la colonne va de 0 à 4 (c'estàdire un total de 5 colonnes). Voir Figure 16.1.
Le résultat renvoyé par la fonction DataAdd2() est affiché à l'écran par l' instruction printf() aux
lignes 16 et 17.
Tableaux de pointeurs
Dans de nombreux cas, il est utile de déclarer un tableau de pointeurs et d'accéder au contenu pointé par
le tableau en déréférencant chaque pointeur. Par exemple, la déclaration suivante déclare un tableau de
pointeurs int :
entier *ptr_int[3] ;
En d'autres termes, la variable ptr_int est un tableau à trois éléments de pointeurs vers des entiers. De
plus, vous pouvez initialiser le tableau de pointeurs. Par example:
entier x1 = 10 ;
entier x2 = 100 ;
entier x3 = 1000 ;
ptr_int[0] = &x1;
ptr_int[1] = &x2;
ptr_int[2] = &x3;
Le Listing 16.7 montre un autre exemple. Ici, un tableau de pointeurs est utilisé pour accéder à un tableau
de chaînes.
TAPER
LISTE 16.7 Utilisation d'un tableau de pointeurs vers des chaînes de caractères
renvoie 0 ;
int je ;
/* Affiche toutes les chaînes d'un tableau de pointeurs vers des chaînes */ for
(i=0; i<size; i++) printf(“%s\n”, str1[i]);
Un extrait d'un poème écrit par Lord Byron est imprimé après la création et l'exécution de l'exécutable
(16L07.exe) du programme du Listing 16.7 :
Examinons d'abord le tableau de pointeurs, str, qui est déclaré et initialisé aux lignes 9 à 13
UNE ANALYSE
dans le corps de la fonction main() du programme de l'extrait 16.7. Comme vous pouvez le
voir, str est un tableau de quatre éléments de pointeurs vers un ensemble de chaînes de caractères.
J'ai adopté quatre phrases d'un poème écrit par Lord Byron et je les ai utilisées comme quatre
chaînes de caractères dans le programme.
Machine Translated by Google
274 Heure 16
Vous pouvez accéder à une chaîne de caractères en utilisant un pointeur correspondant dans le tableau.
En fait, il y a deux fonctions, StrPrint1() et StrPrint2(), dans le Listing 16.7. Les deux peuvent être
appelées pour accéder aux chaînes de caractères. À partir de la déclaration de fonction à la ligne 4, vous
pouvez voir que la fonction StrPrint1() prend un pointeur de pointeurs, c'estàdire **str1, qui est déréférencé
à l'intérieur de la fonction StrPrint1() pour représenter les quatre pointeurs qui pointent vers les quatre
caractères cordes. La définition de StrPrint1() se trouve aux lignes 23–29.
La fonction StrPrint2() , d'autre part, ne prend qu'une variable de pointeur comme argument et imprime
une chaîne de caractères référencée par le pointeur. Les lignes 31 à 35 donnent la définition de la
fonction StrPrint2() .
Revenons maintenant à la fonction main() . La fonction StrPrint1() est appelée à la ligne 16 avec le nom
du tableau de pointeurs, str, comme argument. StrPrint1() affiche alors les quatre phrases du poème de
Byron à l'écran. La boucle for des lignes 17 et 18 fait la même chose en appelant quatre fois la fonction
StrPrint2() . A chaque fois, l'adresse de début d'une phrase est passée à StrPrint2(). Par conséquent, vous
voyez toutes les phrases du poème imprimées deux fois à l'écran.
Comme pour les pointeurs vers des tableaux, vous pouvez déclarer un pointeur initialisé avec la valeur de
gauche d'une fonction. (La valeur de gauche est l'adresse mémoire à laquelle se trouve la fonction.)
Ensuite, vous pouvez appeler la fonction via le pointeur.
Le programme du Listing 16.8 est un exemple qui déclare un pointeur vers une fonction.
TAPER
LISTE 16.8 Pointer vers une fonction
ptr = StrPrint ; si (!
12 : (*ptr)(str))
Machine Translated by Google
printf("Terminé !\n");
renvoie 0 ;
13 :
14 : 15 : 16 : } 17 : /* définition de la
fonction */ 18 : int StrPrint(char *str)
19 : { 20 : 21 : 22 : }
printf("%s\n", chaîne);
renvoie 0 ;
16
Une fois l'exécutable 16L08.exe du programme du Listing 16.8 créé et exécuté sur mon
SORTIR
ordinateur, la sortie suivante s'affiche à l'écran :
UNE ANALYSE
Pointant vers une fonction.
Fait!
Comme d'habitude, une déclaration de fonction vient en premier dans le Listing 16.8. La fonction StrPrint()
est déclarée avec le spécificateur de type de données int et un argument d'un pointeur char à la ligne 4.
L'instruction de la ligne 9 donne la déclaration d'un pointeur (ptr) vers la fonction StrPrint() : c'estàdire
int (*ptr)(char *str);.
Notez que le pointeur, ptr, est spécifié avec le type de données int et passé avec un pointeur char . En
d'autres termes, le format de la déclaration du pointeur à la ligne 9 est assez similaire à la déclaration de
StrPrint() à la ligne 4. N'oubliez pas que vous devez mettre l' expression *ptr entre une paire de parenthèses
(( et )) afin que le compilateur ne le confondra pas avec un nom de fonction.
À la ligne 11, la valeur de gauche (c'estàdire l'adresse) de la fonction StrPrint() est affectée au pointeur
ptr . Ensuite, l' expression (*ptr)(str) de la ligne 12 appelle la fonction StrPrint() via le pointeur déréférencé
ptr, et passe l'adresse de la chaîne déclarée à la ligne 8 à la fonction.
D'après la définition de la fonction StrPrint() aux lignes 18 à 22, vous pouvez dire que la fonction imprime le
contenu d'une chaîne dont l'adresse est passée à la fonction comme argument. Ensuite, 0 est retourné à la
fin de la fonction.
En fait, l' instruction if des lignes 12 et 13 vérifie la valeur renvoyée par la fonction StrPrint() . Lorsque la
valeur est 0, l' appel printf() à la ligne 13 affiche la chaîne Done! sur l'écran.
La sortie du programme du Listing 16.8 montre que la fonction StrPrint() a été invoquée avec succès en
utilisant un pointeur contenant l'adresse de la fonction.
Machine Translated by Google
276 Heure 16
Résumé
Dans cette leçon, vous avez appris les concepts et applications très importants suivants des pointeurs et
des tableaux en C :
• Vous devez toujours vous assurer qu'un pointeur pointe vers un emplacement de mémoire légal et
valide avant de l'utiliser.
taille scalaire d'un pointeur est déterminée par la taille de son type de données, qui est spécifiée
dans la déclaration du pointeur. • Pour deux pointeurs du même type, vous pouvez soustraire
• Les éléments d'un tableau sont accessibles via un pointeur contenant l'adresse de début
du tableau.
• Vous pouvez passer un tableau non dimensionné comme argument unique à une
fonction. • Vous pouvez également passer un tableau à une fonction via un pointeur. Le pointeur
doit contenir l'adresse de début du tableau.
• Vous pouvez passer soit le format non dimensionné d'un tableau multidimensionnel, soit un pointeur
contenant l'adresse de début du tableau multidimensionnel à une fonction. • Une fonction qui
prend un tableau comme argument ne sait pas combien d'éléments se trouvent dans le tableau. Vous
devez également passer le nombre d'éléments comme un autre argument à la fonction.
• Les tableaux de pointeurs sont utiles pour traiter les chaînes de caractères. •
Vous pouvez affecter un pointeur à l'adresse d'une fonction, puis appeler la fonction à l'aide de ce
pointeur.
Questions et réponses
R L'avantage d'utiliser des pointeurs est que vous pouvez déplacer des pointeurs pour accéder à des
données valides qui sont enregistrées dans les emplacements de mémoire référencés par les
pointeurs. Pour ce faire, vous pouvez effectuer une arithmétique de pointeur pour ajouter (ou
soustraire) un entier à (ou à partir) d'un pointeur. Par exemple, si un pointeur de caractère, ptr_str,
contient l'adresse de début d'une chaîne de caractères, l' expression ptr_str+1 se déplace vers
l'emplacement mémoire suivant, qui contient le deuxième caractère de la chaîne.
Machine Translated by Google
A Le compilateur détermine la taille scalaire d'un pointeur par son type de données, qui est spécifié
dans la déclaration. Lorsqu'un entier est ajouté ou soustrait d'un pointeur, la valeur réelle utilisée
par le compilateur est la multiplication de l'entier et de la taille du type pointeur. Par exemple,
étant donné un pointeur int ptr_int, l'expression ptr_int + 1 est interprétée par le compilateur
comme ptr_int + 1 * sizeof(int). Si la taille du type int est de 2 octets, l' expression ptr_int + 1
signifie en réalité se déplacer de 2 octets vers le haut depuis l'emplacement mémoire référencé
par le pointeur ptr_int .
16
Q Comment accéder à un élément d'un tableau à l'aide d'un pointeur ?
A Pour un tableau unidimensionnel, vous pouvez affecter l'adresse de début d'un tableau à un
pointeur du même type, puis déplacez le pointeur vers l'emplacement mémoire qui contient la
valeur d'un élément qui vous intéresse. Ensuite, vous déréférencez le pointeur pour obtenir la
valeur de l'élément. Pour les tableaux multidimensionnels, la méthode est similaire, mais vous
devez penser aux autres dimensions en même temps (voir l'exemple présenté dans le Listing
16.6.)
R Dans de nombreux cas, il est utile d'utiliser des tableaux de pointeurs. Par exemple, il est pratique d'utiliser
un tableau de pointeurs pour pointer vers un ensemble de chaînes de caractères afin de pouvoir accéder
à n'importe laquelle des chaînes référencées par un pointeur correspondant dans le tableau.
Atelier
Pour aider à consolider votre compréhension de la leçon de cette heure, nous vous encourageons à
répondre aux questions du quiz et à terminer les exercices fournis dans l'atelier avant de passer à la
leçon suivante. Les réponses et les conseils aux questions et exercices sont donnés dans l'annexe B,
« Réponses aux questions et exercices du quiz ».
Questionnaire
1. Étant donné un pointeur char , ptr_ch, un pointeur int , ptr_int, et un pointeur flottant ,
ptr_flt, combien d'octets seront ajoutés, respectivement, dans les expressions suivantes sur
votre machine ?
• ptr_ch + 4
• ptr_int + 2
• ptr_flt + 1
• ptr_ch + 12
• ptr_int + 6
• ptr_flt + 3
Machine Translated by Google
278 Heure 16
2. Si l'adresse détenue par un pointeur int , ptr1, est 0x100A et que l'adresse détenue par un
autre pointeur int , ptr2, est 0x1006, qu'obtiendrez vous de la soustraction de ptr1–ptr2 ?
3. Étant donné que la taille du type de données double est de 8 octets et que l'adresse actuelle
détenue par une variable à double pointeur, ptr_db, est 0x0238, quelles sont les adresses
détenues, respectivement, par ptr_db–1 et ptr_db+5 ?
• *(ptr + 3)
• ptr ch
• *(point 1)
• *ptr = 'F'
Des exercices
1. Étant donné une chaîne de caractères, j'aime C !, écrivez un programme pour passer la chaîne à une fonction
tion qui affiche la chaîne à l'écran.
3. Étant donné un tableau de caractères à deux dimensions, str, qui est initialisé comme
écrivez un programme pour passer l'adresse de début de str à une fonction qui imprime le
contenu du tableau de caractères.
4. Réécrivez le programme du Listing 16.7. Cette fois, le tableau de pointeurs est initialisé
avec les chaînes suivantes :
HEURE 17
Allocation de mémoire
Il est tout aussi désagréable d'obtenir plus que ce que vous avez négocié que d'obtenir moins.
—GB Shaw
Jusqu'à présent, vous avez appris à déclarer et à réserver un espace mémoire avant qu'il ne
soit utilisé dans votre programme. Par exemple, vous devez spécifier la taille d'un tableau
dans votre programme (ou le compilateur doit déterminer la taille si vous déclarez un tableau
non dimensionné) avant de lui affecter des données au moment de l'exécution. Dans cette
leçon, vous apprendrez à allouer dynamiquement de l'espace mémoire lorsque votre programme
est en cours d'exécution. Les quatre fonctions d'allocation de mémoire dynamique abordées
dans cette leçon sont
• La fonction malloc()
• La fonction calloc()
• La fonction realloc()
• La fonction libre()