Chapitre – 5
Introduction à la programmation C
Introduction
Le langage de programmation C est l’un des langages de programmation les plus populaires dans le monde informatique moderne. Le langage de programmation C a été conçu et créé par Brian Kernighan et Dennis Ritchie aux Bell Research Labs en 1972.
C est un langage spécifiquement conçu pour permettre au programmeur d'accéder à presque tous les composants internes d'une machine : registres, emplacements d'E/S et adresses absolues. Parallèlement, le langage de programmation « C » permet le traitement des données et la modularisation du texte programmé dans la mesure nécessaire pour réaliser des projets de programmation multiples très complexes de manière organisée et dans les délais.
Bien que le langage ait été conçu à l'origine pour fonctionner sous UNIX, son utilisation sur le système d'exploitation MS-DOS sur les PC IBM et compatibles suscitait un grand intérêt. C'est un excellent langage pour cet environnement en raison de sa simplicité d'expression, de la compacité du code et de son large champ d'applicabilité.
De plus, en raison de la simplicité et de la facilité d'écriture d'un compilateur C, il s'agit généralement du premier langage de haut niveau disponible sur tout nouvel ordinateur, y compris les micro-ordinateurs, les mini-ordinateurs et les mainframes.
Pourquoi utiliser C dans la programmation de récupération de données
Dans le monde actuel de la programmation informatique, de nombreux langages de haut niveau sont disponibles. Ces langages sont bons car ils possèdent de nombreuses fonctionnalités adaptées à la plupart des tâches de programmation. Cependant, il existe plusieurs raisons pour lesquelles C est le premier choix des programmeurs qui souhaitent programmer pour la récupération de données, le système, l'appareil ou le matériel :
- C est un langage populaire et préféré parmi les programmeurs professionnels. Par conséquent, une large gamme de compilateurs C et de modules complémentaires utiles sont disponibles.
- Il existe un langage portable . Un programme C écrit pour un système informatique peut être compilé et exécuté sur un autre système avec peu ou pas de modifications. La portabilité est améliorée par la norme ANSI pour C, un ensemble de règles pour les compilateurs C.
- Le langage de programmation C permet une utilisation étendue des modules. Le code C peut être écrit dans des sous-routines appelées fonctions. Ces fonctions peuvent être réutilisées dans d’autres applications ou programmes. Il n'est pas nécessaire de faire des efforts supplémentaires lors de la programmation d'une nouvelle application pour créer le même formulaire précédemment développé dans une autre application.
Vous pouvez utiliser cette fonctionnalité dans le nouveau programme sans ou avec peu de modifications. Dans le cas de la programmation de récupération de données, vous trouverez cette qualité très utile lorsque vous devez exécuter les mêmes fonctions plusieurs fois dans différentes applications de différents programmes.
- C est un langage puissant et flexible. C'est pourquoi le langage de programmation C est utilisé pour des projets aussi divers que les systèmes d'exploitation, les traitements de texte, les programmes graphiques, les feuilles de calcul et même les compilateurs pour d'autres langages.
- C est un langage composé de quelques mots, c'est-à-dire qu'il ne contient que quelques termes, appelés mots-clés, qui constituent la base sur laquelle sont développées les fonctionnalités du langage. Ces mots-clés, également appelés mots réservés, le rendent plus puissant et offrent un large éventail de possibilités de programmation, permettant au programmeur de se sentir capable de faire tout type de programmation en C.
Supposons que vous ne sachiez rien sur C.
Je suppose que vous ne savez rien de la programmation C et que vous n'avez aucune idée de la programmation. Je commencerai par les concepts les plus basiques du langage C et vous guiderai vers la programmation C de haut niveau, y compris les concepts généralement obscurs des pointeurs, des structures et de l'allocation de mémoire dynamique.
Il faudra beaucoup de temps et d’efforts pour bien comprendre ces concepts car ils ne sont pas faciles à comprendre, mais ce sont des outils très puissants.
La programmation C est une excellente ressource dans les domaines où vous pourriez avoir besoin d'utiliser le langage assembleur mais préférez le garder simple à écrire et à maintenir. Dans ces cas, le temps gagné en programmant en C peut être énorme.
Bien que le langage C fasse du bon travail en portant des programmes d'une implémentation à une autre, il existe certaines différences entre les compilateurs qui deviennent perceptibles chaque fois que vous essayez d'utiliser un autre compilateur.
La plupart des différences deviennent apparentes lors de l'utilisation d'extensions non standard, telles que les appels BIOS DOS lors de l'utilisation de MS-DOS, mais même ces différences peuvent être minimisées par un choix minutieux des structures de programmation.
Lorsqu'il est devenu évident que le langage de programmation C devenait un langage très populaire et disponible sur une large gamme d'ordinateurs, un groupe de personnes intéressées s'est réuni pour proposer un ensemble de règles standard pour l'utilisation du langage de programmation C.
Le groupe représentait tous les secteurs de l'industrie du logiciel et, après de nombreuses réunions et de nombreux projets préliminaires, ils ont finalement rédigé une norme acceptable pour le langage C. Elle a été acceptée par l'American National Standards Institute (ANSI) et l'International Standards Organization (ISO) .
Elle n’est imposée à aucun groupe ni à aucun utilisateur, mais parce qu’elle est si largement acceptée, ce serait un suicide économique pour tout auteur de compilateur de refuser de se conformer à la norme.
Les programmes écrits dans ce livre sont principalement destinés à être utilisés sur un ordinateur IBM-PC ou compatible, mais peuvent être utilisés avec n'importe quel compilateur standard ANSI, à condition qu'il soit strictement conforme à la norme ANSI.
Commençons
Avant de pouvoir faire quoi que ce soit dans n’importe quel langage et commencer à programmer, vous devez savoir comment nommer un identifiant. Un identifiant est utilisé pour toute variable, fonction, définition de données, etc. Dans le langage de programmation C, un identifiant est une combinaison de caractères alphanumériques, le premier étant une lettre de l'alphabet ou un trait de soulignement, et le reste étant n'importe quelle lettre de l'alphabet, n'importe quel chiffre numérique ou le trait de soulignement.
Lors de la dénomination des identifiants, il y a deux règles à garder à l'esprit.
- Le cas des caractères alphabétiques est significatif. Il existe un langage sensible à la casse. Cela signifie que Recovery est différent de recovery et que rEcOveRY est différent des deux mentionnés précédemment.
- Selon la norme ANSI-C, au moins 31 caractères significatifs peuvent être utilisés, qui seront considérés comme significatifs par un compilateur conforme ANSI-C. Si plus de 31 sont utilisés, tous les caractères au-delà du 31e peuvent être ignorés par n'importe quel compilateur.
Mots clés
Il existe 32 mots définis comme mots-clés en C. Ceux-ci ont des utilisations prédéfinies et ne peuvent pas être utilisés à d'autres fins dans un programme C. Ils sont utilisés par le compilateur pour aider à compiler le programme. Ils sont toujours écrits en minuscules. Vous trouverez ci-dessous une liste complète :
voiture |
casser |
cas |
personnage |
constante |
continuer |
défaut |
Faire |
double |
autre |
énumération |
externe |
flottant |
Pour |
aller à |
Si |
interne |
long |
registre |
retour |
court |
signé |
taille de |
statique |
structure |
changer |
définition de type |
union |
non signé |
vide |
volatil |
Alors que |
Ici, nous voyons la magie du C. La merveilleuse collection de seulement 32 mots-clés offre une large utilisation dans différentes applications. Chaque programme informatique doit prendre en compte deux entités : les données et le programme. Ils dépendent fortement l’un de l’autre et une planification minutieuse de la part des deux conduit à un programme bien planifié et bien écrit.
Commençons par un programme C simple :
/* Premier programme pour apprendre le C */
#include <stdio.h>
vide principal()
{
printf("Ceci est un programme C\n"); // imprimer un message
}
Bien que le programme soit très simple, certains points méritent d'être notés. Regardons le programme ci-dessus. Tout ce qui se trouve à l'intérieur de /* et */ est considéré comme un commentaire et sera ignoré par le compilateur. Vous ne devez pas inclure de commentaires à l'intérieur d'autres commentaires, donc quelque chose comme ceci n'est pas autorisé :
/* ceci est un /* commentaire */ à l'intérieur d'un commentaire, ce qui est faux */
Il existe également un moyen de documentation qui fonctionne sur une seule ligne. En utilisant //, nous pouvons ajouter une petite documentation à l'intérieur de cette ligne.
Chaque programme C contient une fonction appelée main. C'est le point de départ du programme. Chaque fonction doit renvoyer une valeur. Dans ce programme, la fonction principale ne renvoie aucune valeur de retour, nous avons donc écrit void main. Nous pourrions également écrire ce programme comme :
/* Premier programme pour apprendre le C */
#include <stdio.h>
principal()
{
printf("Ceci est un programme C\n"); // imprimer un message
retourner 0;
}
Les deux programmes sont identiques et exécutent la même tâche. Le résultat des deux programmes imprimera la sortie suivante à l'écran :
Ceci est un programme C
#include<stdio.h> permet au programme d'interagir avec l'écran, le clavier et le système de fichiers de votre ordinateur. Vous le trouverez au début de presque tous les programmes C.
main() déclare le début de la fonction, tandis que les deux accolades indiquent le début et la fin de la fonction. Les accolades en C sont utilisées pour regrouper des instructions comme dans une fonction ou dans le corps d'une boucle. Ce regroupement est connu sous le nom d’instruction ou de bloc composé.
printf("Ceci est un programme C\n"); imprimez les mots sur l'écran. Le texte à imprimer est placé entre guillemets. Le \n à la fin du texte indique au programme d'imprimer une nouvelle ligne dans le cadre de la sortie. La fonction printf() est utilisée pour afficher la sortie sur le moniteur.
La plupart des programmes C sont en lettres minuscules. Vous trouverez généralement des lettres majuscules utilisées dans les définitions du préprocesseur qui seront abordées plus tard, ou à l'intérieur des guillemets en tant que parties de chaînes de caractères.
Compilation du programme
Disons que le nom de notre programme est CPROG.C. Pour saisir et compiler le programme C, suivez ces étapes :
- Créez le répertoire actif de vos programmes C et démarrez votre éditeur. Vous pouvez utiliser n'importe quel éditeur de texte pour cela, mais la plupart des compilateurs C comme Turbo C++ de Borland disposent d'un environnement de développement intégré (IDE) qui vous permet de saisir, de compiler et de lier vos programmes dans un seul paramètre pratique.
- Écrivez et enregistrez le code source. Vous devez nommer le fichier CPROG.C.
- Remplissez et connectez CPROG.C. Exécutez la commande appropriée spécifiée par les manuels de votre compilateur. Vous devriez recevoir un message indiquant qu’il n’y a aucune erreur ou avertissement.
- Vérifiez les messages du compilateur. Si vous n'obtenez aucune erreur ou avertissement, tout devrait bien se passer. S'il y a une erreur dans la frappe du programme, le compilateur la détectera et affichera un message d'erreur. Corrigez l'erreur affichée dans le message d'erreur.
- Votre premier programme C devrait maintenant être compilé et prêt à être exécuté. Si vous affichez une liste de répertoires de tous les fichiers nommés CPROG, vous obtiendrez les quatre fichiers avec différentes extensions décrites ci-dessous :
- CPROG.C, le fichier de code source
- CPROG.BAK, le fichier de sauvegarde du fichier source créé avec l'éditeur
- CPROG.OBJ, contient le code objet pour CPROG.C
- CPROG.EXE, le programme exécutable créé lorsque vous avez compilé et lié CPROG.C
- Pour exécuter, ou lancer, CPROG.EXE, tapez simplement cprog. Le message Ceci est un programme C apparaît à l’écran.
Examinons maintenant le programme suivant :
/* Premier programme pour apprendre le C */ // 1
// 2
#include <stdio.h> // 3
// 4
main() // 5
{
// 6
printf("Ceci est un programme C\n"); // 7
// 8
retourner 0; // 9
} // 10
Lorsque vous compilez ce programme, le compilateur affiche un message similaire au suivant :
cprog.c(8) : Erreur : `;' attendu
Décomposons ce message d’erreur en plusieurs parties. cprog.c est le nom du fichier dans lequel l'erreur a été trouvée. (8) est le numéro de ligne où l'erreur a été trouvée. Erreur : « ; » attendu est Une description de l'erreur.
Ce message est très instructif et vous indique que sur la ligne 8 de CPROG.C, le compilateur s'attendait à trouver un point-virgule, mais n'en a pas trouvé. Cependant, vous savez que le point-virgule a en fait été omis de la ligne 7, il y a donc une divergence.
Pourquoi le compilateur signale-t-il une erreur à la ligne 8 alors qu'en fait, un point-virgule a été omis à la ligne 7 ? La réponse est que C ne se soucie pas de choses comme les sauts de ligne. Le point-virgule qui suit l'instruction printf() aurait pu être placé sur la ligne suivante, bien que cela serait une mauvaise programmation en pratique.
Ce n'est qu'après avoir rencontré la commande suivante (retour) à la ligne 8 que le compilateur est sûr que le point-virgule est manquant. Par conséquent, le compilateur signale que l’erreur se trouve à la ligne 8.
Il peut y avoir plusieurs possibilités pour différents types d’erreurs. Discutons des messages d’erreur de connexion. Les erreurs de linker sont relativement rares et résultent généralement d'une faute d'orthographe dans le nom d'une fonction de la bibliothèque C. Dans ce cas, vous obtenez un message d'erreur Error: undefined symbols:, suivi du nom mal orthographié. Une fois l’orthographe corrigée, le problème devrait disparaître.
Imprimer des numéros
Voyons l’exemple suivant :
// Comment imprimer des nombres //
#include<stdio.h>
vide principal()
{
entier = 10;
printf(“Le nombre est %d”, num);
}
La sortie du programme sera affichée à l'écran comme suit :
Le nombre est 10
Le signe % est utilisé pour signaler la sortie de nombreux types de variables différents. Le caractère suivant le signe % est ad, qui signale à la routine de sortie d'obtenir une valeur décimale et de la sortir.
Utilisation des variables
En C, une variable doit être déclarée avant de pouvoir être utilisée. Les variables peuvent être déclarées au début de n'importe quel bloc de code, mais la plupart se trouvent au début de chaque fonction. La plupart des variables locales sont créées lorsque la fonction est appelée et sont détruites lorsque cette fonction revient.
Pour utiliser des variables dans les programmes C, vous devez connaître les règles suivantes lors de la dénomination des variables en C :
- Le nom peut contenir des lettres, des chiffres et le trait de soulignement (_).
- Le premier caractère du nom doit être une lettre. Le trait de soulignement est également un premier caractère légal, mais son utilisation n'est pas recommandée.
- Le langage C est sensible à la casse, donc le nom de la variable num est différent de Num.
- Les mots-clés C ne peuvent pas être utilisés comme noms de variables. Un mot-clé est un mot qui fait partie du langage C.
La liste suivante contient quelques exemples de noms de variables C légaux et illégaux :
Nom de la variable |
Légal ou non |
Dans un |
Légal |
Ttpt2_t2p |
Légal |
Point Tt |
Illégal : l'espace n'est pas autorisé |
_1990_taxe |
Légal mais déconseillé |
Jack_téléphone# |
Illégal : contient le caractère non valide # |
Cas |
Illégal : c'est un mot-clé C |
1 livre |
Illégal : Le premier caractère est un chiffre |
La première nouveauté qui attire l’attention est la première ligne du corps de main() :
entier = 10;
Cette ligne définit une variable nommée 'num' de type int et l'initialise avec la valeur 10. Elle aurait également pu être écrite ainsi :
nombre entier; /* définit la variable non initialisée 'num' */
/* et après toutes les définitions de variables : */
nombre = 10; /* affecter la valeur 10 à la variable 'num' */
Les variables peuvent être définies au début d'un bloc (entre accolades {et}) ; Cela se produit généralement au début d'un corps de fonction, mais peut également se produire au début d'un autre type de bloc.
Les variables définies au début d'un bloc ont par défaut l'état « auto ». Cela signifie qu’ils n’existent que pendant l’exécution du bloc. Lorsque la fonction commence à s'exécuter, les variables seront créées mais leur contenu ne sera pas défini. Lorsque la fonction revient, les variables seront détruites. La définition aurait aussi pu être écrite ainsi :
entier automatique = 10;
Étant donné que la définition avec ou sans le mot-clé auto est tout à fait équivalente, le mot-clé auto est évidemment plutôt redondant.
Mais parfois, ce n’est pas ce que vous souhaitez. Supposons que vous souhaitiez qu'une fonction garde une trace du nombre de fois où elle est appelée. Si la variable était détruite à chaque fois que la fonction revenait, cela ne serait pas possible.
Il est donc possible de donner à la variable ce qu'on appelle une durée de vie statique, ce qui signifie qu'elle restera intacte tout au long de l'exécution du programme. Par exemple:
entier statique = 10;
Cela initialise la variable num à 10 au début de l'exécution du programme. À partir de ce moment, la valeur restera intacte ; la variable ne sera pas réinitialisée si la fonction est appelée plusieurs fois.
Parfois, il n'est pas suffisant que la variable soit accessible uniquement par une fonction, ou il peut ne pas être pratique de transmettre la valeur via un paramètre à toutes les autres fonctions qui en ont besoin.
Mais si vous avez besoin d'accéder à la variable à partir de toutes les fonctions de l'ensemble du fichier source, vous pouvez également le faire avec le mot-clé static, mais en plaçant la définition en dehors de toutes les fonctions. Par exemple:
#include <stdio.h>
int statique num = 10; /* sera accessible à partir de l'intégralité du fichier source */
int main(vide)
{
printf("Le nombre est : %d\n", num);
retourner 0;
}
Il existe également des cas où une variable doit être accessible depuis l'ensemble du programme, qui peut être constitué de plusieurs fichiers sources. Ceci est appelé une variable globale et doit être évité lorsqu'elle n'est pas nécessaire.
Ceci est également réalisé en plaçant la définition en dehors de toutes les fonctions, mais sans utiliser le mot-clé static :
#include <stdio.h>
int num = 10; /* sera accessible depuis l'ensemble du programme ! */
int main(vide)
{
printf("Le nombre est : %d\n", num);
retourner 0;
}
Il existe également le mot-clé extern, qui est utilisé pour accéder aux variables globales dans d'autres modules. Il existe également des qualificatifs que vous pouvez ajouter aux définitions de variables. Le plus important d’entre eux est const. Une variable définie comme const ne peut pas être modifiée.
Il existe deux autres modificateurs qui sont moins couramment utilisés. Le modificateur et le registre volatils. Le modificateur volatile exige que le compilateur accède réellement à la variable à chaque fois qu'elle est lue. Il se peut que la variable ne soit pas optimisée en la plaçant dans un registre ou quelque chose du genre. Ceci est principalement utilisé à des fins de multithreading et de traitement des interruptions, etc.
Le modificateur de registre demande au compilateur d'optimiser la variable dans un registre. Ceci n'est possible qu'avec des variables automatiques et dans de nombreux cas, le compilateur peut mieux sélectionner les variables à optimiser dans les registres, ce mot-clé est donc obsolète. La seule conséquence directe de la création d’un registre variable est que son adresse ne peut pas être prise.
Le tableau des variables, présenté sur la page suivante, décrit la classe de stockage de cinq types de classes de stockage.
Dans le tableau, nous voyons que le mot clé extern est positionné sur deux lignes. Le mot clé extern est utilisé dans les fonctions pour déclarer une variable externe statique définie ailleurs.
Types de variables numériques
C fournit plusieurs types de variables numériques car différentes valeurs numériques ont des exigences de stockage de mémoire différentes. Ces types de nombres diffèrent par la facilité avec laquelle certaines opérations mathématiques peuvent être effectuées sur eux.
Les petits entiers nécessitent moins de mémoire pour être stockés et l'ordinateur peut effectuer des opérations mathématiques sur ces nombres très rapidement. Les grands entiers et les valeurs à virgule flottante nécessitent plus d'espace de stockage et plus de temps pour les opérations mathématiques. En utilisant les types de variables appropriés, vous garantissez que votre programme s'exécute aussi efficacement que possible.
Les variables numériques en C se répartissent en deux catégories principales suivantes :
- Variables entières
- Variables à virgule flottante
Dans chacune de ces catégories, il existe deux ou plusieurs types spécifiques de variables. Le tableau suivant indique la quantité de mémoire, en octets, requise pour contenir une seule variable de chaque type.
Le type char peut être équivalent à un char signé ou à un char non signé, mais il s'agit toujours d'un type distinct de l'un ou l'autre.
En C, il n'y a aucune différence entre le stockage de caractères ou de leurs valeurs numériques correspondantes dans une variable, il n'est donc pas nécessaire qu'une fonction effectue une conversion entre un caractère et sa valeur numérique ou vice versa. Pour les autres types d'entiers, si vous omettez signed ou unsigned, la valeur par défaut sera signed, donc par exemple int et signed int sont équivalents.
Le type int doit être supérieur ou égal au type court et inférieur ou égal au type long. Si vous avez simplement besoin de stocker quelques valeurs qui ne sont pas extrêmement grandes, c'est souvent une bonne idée d'utiliser le type int ; Il s’agit généralement de la taille que le processeur peut gérer le plus facilement et donc le plus rapidement.
Avec de nombreux compilateurs, double et long double sont équivalents. Ceci, combiné au fait que la plupart des fonctions mathématiques standard fonctionnent avec le type double, est une bonne raison de toujours utiliser le type double si vous devez travailler avec des nombres fractionnaires.
Le tableau suivant décrit mieux les types de variables :
Types spéciaux couramment utilisés :
Type de variable |
Description |
taille_t |
type non signé utilisé pour stocker la taille des objets en octets |
heure_t |
utilisé pour stocker les résultats de la fonction time() |
horloge_t |
utilisé pour stocker les résultats de la fonction clock() |
DÉPOSER |
utilisé pour accéder à un flux (généralement un fichier ou un périphérique) |
ptrdiff_t |
type signé de la différence entre 2 pointeurs |
division |
utilisé pour stocker les résultats de la fonction div() |
ldiv_t |
utilisé pour stocker les résultats de la fonction ldiv() |
fpos_t |
utilisé pour contenir des informations sur l'emplacement du fichier |
va lister |
utilisé dans la gestion des arguments variables |
personnage_t |
police large (utilisée pour les jeux de caractères larges) |
sig_atomic_t |
utilisé dans les gestionnaires de signaux |
Jmp_buf |
utilisé pour les sauts non locaux |
Pour mieux comprendre ces variables, prenons un exemple :
/* Programme pour indiquer la plage et la taille en octets de la variable C */
#include <stdio.h>
int main()
{
int a; /* type entier simple */
entier long b; /* type entier long */
int court c; /* type entier court */
int non signé d; /* type entier non signé */
char e; /* type de police */
flotteur f; /* type à virgule flottante */
double g; /* virgule flottante double précision */
a = 1023;
b = 2222;
c = 123;
d = 1234;
e = 'X';
= 3,14159;
1.10.000;
printf( "\nUn caractère fait %d octets", sizeof( char ));
printf( "\nUn int fait %d octets", sizeof( int ));
printf( "\nUn short fait %d octets", sizeof( short ));
printf( "\nUn long fait %d octets", sizeof( long ));
printf( "\nUn caractère non signé fait %d octets",
sizeof( caractère non signé ));
printf( "\nUn int non signé fait %d octets",
sizeof( entier non signé ));
printf( "\nUn short non signé fait %d octets",
sizeof(unsigned short));
printf( "\nUn unsigned long est %d octets",
taille de(unsigned long));
printf( "\nUn float fait %d octets", sizeof( float ));
printf( "\nUne valeur double est %d octets\n", sizeof( double ));
printf("a = %d\n", a); /* sortie décimale */
printf("a = %o\n", a); /* sortie octale */
printf("a = %x\n", a); /* sortie hexadécimale */
printf("b = %ld\n", b); /* sortie décimale longue */
printf("c = %d\n", c); /* sortie décimale courte */
printf("d = %u\n", d); /* sortie non signée */
printf("e = %c\n", e); /* caractère de sortie */
printf("f = %f\n", f); /* sortie mobile */
printf("g = %f\n", g); /* sortie avec double float */
imprimer("\n");
printf("a = %d\n", a); /* sortie int simple */
printf("a = %7d\n", a); /* utiliser une largeur de champ de 7 */
printf("a = %-7d\n", a); /* justifié à gauche dans
champ de 7 */
c = 5;
d = 8;
printf("a = %*d\n", c, a); /* utiliser une largeur de champ de 5*/
printf("a = %*d\n", d, a); /* utiliser une largeur de champ de 8 */
imprimer("\n");
printf("f = %f\n", f); /* sortie flottante simple */
printf("f = %12f\n", f); /* utiliser une largeur de champ de 12 */
printf("f = %12.3f\n", f); /* utiliser 3 décimales */
printf("f = %12.5f\n", f); /* utiliser 5 décimales */
printf("f = %-12.5f\n", f); /* justifier à gauche dans le champ */
retourner 0;
}
Le résultat du programme après exécution sera affiché comme suit :
Un char est 1 octet
Un int fait 2 octets
Un court-circuit fait 2 octets
Un long fait 4 octets
Un caractère non signé est de 1 octet
Un int non signé fait 2 octets.
Un short non signé fait 2 octets
Un long non signé fait 4 octets
Un float fait 4 octets
Un double fait 8 octets
un = 1023
un = 1777
a = 3ff
e = 2222
c = 123
d = 1234
e = X
f = 3,141590
g = 3,141593
un = 1023
un = 1023
un = 1023
un = 1023
un = 1023
f = 3,141590
f = 3,141590
f = 3,142
f = 3,14159
f = 3,14159 |
Avant qu'une variable dans un programme C puisse être utilisée, elle doit être déclarée. Une déclaration de variable indique au compilateur le nom et le type d'une variable et initialise éventuellement la variable à une valeur spécifique.
Si votre programme tente d'utiliser une variable qui n'a pas été déclarée, le compilateur génère un message d'erreur. Une déclaration de variable a la forme suivante :
nom type variable nom;
typename spécifie le type de variable et doit être l'un des mots-clés. varname est le nom de la variable. Vous pouvez déclarer plusieurs variables du même type sur une seule ligne en séparant les noms de variables par des virgules :
int count, nombre, début; /* trois variables entières */
pourcentage flottant, total; /* deux variables flottantes */
Le mot clé typedef
Le mot clé typedef est utilisé pour créer un nouveau nom pour un type de données existant. En effet, typedef crée un synonyme. Par exemple, l’éducation
typedef int entier;
ici, nous voyons que typedef crée un entier comme synonyme de int. Vous pouvez ensuite utiliser un entier pour définir des variables de type int, comme dans cet exemple :
comptage d'entiers;
Ainsi, typedef ne crée pas un nouveau type de données, il vous permet uniquement d'utiliser un nom différent pour un type de données prédéfini.
Initialisation des variables numériques
Lorsqu'une variable est déclarée, le compilateur reçoit l'instruction de réserver un espace de stockage pour la variable. Cependant, la valeur stockée dans cet espace, la valeur de la variable, n'est pas définie. Cela pourrait être zéro, ou cela pourrait être une valeur « poubelle » aléatoire. Avant d'utiliser une variable, vous devez toujours l'initialiser à une valeur connue. Prenons cet exemple :
nombre int; /* Réserver un espace de stockage pour le nombre */
compte = 0; /* Stocker 0 dans le compte */
Cette instruction utilise le signe égal (=), qui est l'opérateur d'affectation de C. Vous pouvez également initialiser une variable lorsqu'elle est déclarée. Pour ce faire, suivez le nom de la variable dans l'instruction de déclaration avec un signe égal et la valeur initiale souhaitée :
int nombre = 0;
taux double = 0,01, complexité = 28,5 ;
Veillez à ne pas initialiser une variable avec une valeur en dehors de la plage autorisée. Voici deux exemples d’initialisations hors limites :
int montant = 100000;
entier non signé longueur = -2500;
Le compilateur C ne détecte pas de telles erreurs. Votre programme peut être compilé et lié, mais vous risquez d’obtenir des résultats inattendus lors de l’exécution du programme.
Prenons l’exemple suivant pour calculer le nombre total de secteurs dans un disque :
// Programme modèle pour calculer les secteurs sur un disque //
#include<stdio.h>
#define SECTEUR_PAR_CÔTÉ 63
#define SIDE_PER_CILINDRO 254
vide principal()
{
int cylindre=0;
clrscr();
printf("Entrez le nombre de cylindres dans le disque \n\n\t");
scanf("%d",&cylindre); // Obtenir la valeur de l'utilisateur //
printf("\n\n\t Nombre total de secteurs sur le disque = %ld", (long)SECTOR_PER_SIDE*SIDE_PER_CYLINDER* cylindre);
obtenir();
}
La sortie du programme est la suivante :
Entrez le nombre de cylindres dans le disque
1024
Nombre total de secteurs sur le disque = 16386048
Dans cet exemple, nous voyons trois nouvelles choses à apprendre. #define est utilisé pour utiliser des constantes symboliques dans le programme ou dans certains cas pour gagner du temps en définissant de longs mots dans de petits symboles.
Ici, nous avons défini le nombre de secteurs par côté, qui est de 63, comme SECTOR_PER_SIDE pour rendre le programme facile à comprendre. Le même cas est vrai pour #define SIDE_PER_CYLINDER 254. scanf() est utilisé pour obtenir l'entrée de l'utilisateur.
Ici, nous prenons le nombre de cylindres comme entrée de l'utilisateur. * est utilisé pour multiplier deux ou plusieurs valeurs, comme indiqué dans l'exemple.
La fonction getch() reçoit essentiellement un seul caractère d'entrée du clavier. En tapant getch(); Ici, nous gelons l'écran jusqu'à ce qu'une touche soit appuyée sur le clavier.
Opérateurs
Un opérateur est un symbole qui indique à C d'effectuer une opération, ou une action, sur un ou plusieurs opérandes. Un opérande est quelque chose sur lequel un opérateur agit. En C, tous les opérandes sont des expressions. Les opérateurs C appartiennent aux quatre catégories suivantes :
- L'opérateur d'affectation
- Opérateurs mathématiques
- Opérateurs relationnels
- Opérateurs logiques
Opérateur d'affectation
L'opérateur d'affectation est le signe égal (=). L'utilisation du signe égal en programmation est différente de son utilisation dans les relations mathématiques algébriques normales. Si vous écrivez
x = y;
Dans un programme C, cela ne signifie pas « x est égal à y ». Cela signifie plutôt « attribuer la valeur de y à x ». Dans une instruction d'affectation C, le côté droit peut être n'importe quelle expression et le côté gauche doit être un nom de variable. Donc, la forme est la suivante :
variable = expression;
Lors de l'exécution, l'expression est évaluée et la valeur résultante est affectée à la variable.
Opérateurs mathématiques
Les opérateurs mathématiques de C effectuent des opérations mathématiques telles que l'addition et la soustraction. C possède deux opérateurs mathématiques unaires et cinq opérateurs mathématiques binaires. Les opérateurs mathématiques unaires sont ainsi appelés parce qu'ils prennent un seul opérande. C possède deux opérateurs mathématiques unaires.
Les opérateurs d'incrémentation et de décrémentation ne peuvent être utilisés qu'avec des variables, pas avec des constantes. L'opération effectuée consiste à ajouter un ou à soustraire un de l'opérande. En d'autres termes, les instructions ++x; et --y; sont l'équivalent de ces instructions :
x = x + 1;
y = y - 1;
Les opérateurs mathématiques binaires prennent deux opérandes. Les quatre premiers opérateurs binaires, qui incluent les opérations mathématiques courantes trouvées sur une calculatrice (+, -, *, /), vous sont familiers. Le cinquième opérateur Modulo renvoie le reste lorsque le premier opérande est divisé par le deuxième opérande. Par exemple, 11 modulo 4 est égal à 3 (11 est divisé par 4, deux fois et il reste 3).
Opérateurs relationnels
Les opérateurs relationnels C sont utilisés pour comparer des expressions. Une expression contenant un opérateur relationnel est évaluée à vrai (1) ou faux (0). C possède six opérateurs relationnels.
Opérateurs logiques
Les opérateurs logiques C vous permettent de combiner deux ou plusieurs expressions relationnelles en une seule expression qui est évaluée à vrai ou à faux. Les opérateurs logiques renvoient vrai ou faux, selon que leurs opérandes sont vrais ou faux.
Si x est une variable entière, les expressions utilisant des opérateurs logiques peuvent être écrites de la manière suivante :
(x > 1) et (x < 5)
(x >= 2) et (x <= 4)
Opérateur |
Symbole |
Description |
Exemple |
Opérateurs d'affectation |
même |
= |
attribuer la valeur de yax |
x = y |
Opérateurs mathématiques |
Augmenter |
++ |
Incrémenter l'opérande d'un |
++x, x++ |
Diminuer |
-- |
Décrémente l'opérande d'une unité |
--x, x-- |
Ajout |
+ |
Ajoute deux opérandes |
x + y |
Soustraction |
- |
Soustrait le deuxième opérande du premier |
xe |
Multiplication |
* |
Multiplier deux opérandes |
x * e |
Division |
/ |
Diviser le premier opérande par le deuxième opérande |
x / e |
Module |
% |
Renvoie le reste lorsque le premier opérande est divisé par le deuxième opérande |
x % et |
Opérateurs relationnels |
Même |
= = |
Égalité |
x = = et |
Plus grand que |
> |
Plus grand que |
x > e |
Moins que |
< |
Moins que |
x < y |
Supérieur ou égal à |
>= |
Supérieur ou égal à |
x >= y |
Inférieur ou égal à |
<= |
Inférieur ou égal à |
x <= e |
Pas le même |
!= |
Pas la même chose que |
x != y |
Opérateurs logiques |
ET |
&& |
Vrai (1) seulement si exp1 et exp2 sont tous deux vrais ; faux (0) sinon |
exp1 et exp2 |
OU |
|| |
Vrai (1) si exp1 ou exp2 est vrai ; faux (0) seulement si les deux sont faux |
exp1 || exp2 |
PAS |
! |
Faux (0) si exp1 est vrai ; vrai (1) si exp1 est faux |
!esp1 |
Choses à retenir sur les expressions logiques
x * = y |
c'est égal à |
x = x * y |
y - = z + 1 |
c'est égal à |
y = y - z + 1 |
a / = b |
c'est égal à |
a = a / b |
x + = y / 8 |
c'est égal à |
x = x + y / 8 |
et % = 3 |
c'est égal à |
y = y % 3 |
L'opérateur virgule
La virgule est souvent utilisée en C comme simple signe de ponctuation, pour séparer les déclarations de variables, les arguments de fonction, etc. Dans certaines situations, la virgule agit comme un opérateur.
Vous pouvez former une expression en séparant deux sous-expressions par une virgule. Le résultat est le suivant :
- Les deux expressions sont évaluées, l’expression de gauche étant évaluée en premier.
- L'expression entière est évaluée comme la valeur de l'expression correcte.
Par exemple, l'instruction suivante affecte la valeur de bax, puis incrémente a, puis incrémente b : x = (a++, b++);
Priorité des opérateurs C (Résumé des opérateurs C)
Rang et associativité |
Opérateurs |
1 (de gauche à droite) |
() [] -> . |
2 (de droite à gauche) |
! ~ ++ -- * (indirection) & (adresse-de) (type) sizeof + (unaire) - (unaire) |
3 (de gauche à droite) |
* (multiplication) / % |
4 (de gauche à droite) |
+ - |
5 (de gauche à droite) |
<< >> |
6 (de gauche à droite) |
< <= > >= |
7 (de gauche à droite) |
= = != |
8 (de gauche à droite) |
& ( ET au niveau du bit ) |
9 (de gauche à droite) |
^ |
10 (de gauche à droite) |
| |
11 (de gauche à droite) |
&& |
12 (de gauche à droite) |
|| |
13 (de droite à gauche) |
?: |
14 (de droite à gauche) |
= += -= *= /= %= &= ^= |= <<= >>= |
15 (de gauche à droite) |
, |
() est l'opérateur de fonction ; [] est l'opérateur du tableau. |
|
Prenons un exemple d’utilisation des opérateurs :
/* Utilisation des opérateurs */
int main()
{
si le nombre est entier x = 0, y = 2, z = 1025 ;
nombre décimal a = 0,0, b = 3,14159, c = -37,234 ;
/* incrémentation */
x = x + 1; /* Ceci incrémente x */
x++; /* Ceci incrémente x */
++x; /* Ceci incrémente x */
z = y++; /* z = 2, y = 3 */
z = ++y; /* z = 4, y = 4 */
/* décrémenter */
y = y - 1; /* Ceci décrémente y */
y--; /* Ceci décrémente y */
--y; /* Ceci décrémente y */
y = 3;
z = y--; /* z = 3, y = 2 */
z = --y; /* z = 1, y = 1 */
/* opération arithmétique */
a = a + 12; /* Ceci ajoute 12 à un */
un += 12; /* Cela ajoute 12 autres à un */
un *= 3,2; /* Ceci multiplie a par 3,2 */
a -= b; /* Ceci soustrait b de a */
un /= 10,0; /* Ceci divise a par 10,0 */
/* expression conditionnelle */
a = (b >= 3,0 ? 2,0 : 10,5 ); /* Cette expression */
si (b >= 3.0) /* Et cette expression */
a = 2,0; /* ils sont tous les deux identiques */
sinon /* provoquera le même problème */
a = 10,5; /* résultat. */
c = (a > b ? a : b); /* c aura le maximum de a ou b */
c = (a > b ? b : a); /* c aura le minimum de a ou b */
printf("x=%d, y=%d, z= %d\n", x, y, z);
printf("a=%f, b=%f, c= %f", a, b, c);
retourner 0;
}
et le résultat de ce programme sera affiché sur l'écran comme :
x=3, y=1, z=1
a=2,000000, b=3,141590, c=2,000000
En savoir plus sur printf() et Scanf()
Considérez les deux instructions printf suivantes
printf(“\t %d\n”, num);
printf(“%5.2f”, fraction);
dans la première instruction printf, _t nécessite de déplacer l'onglet sur l'écran, l'argument %d indique au compilateur que la valeur de num doit être imprimée sous la forme d'un entier décimal. \n provoque le démarrage d'une nouvelle sortie sur une nouvelle ligne.
Dans la deuxième instruction printf, %5.2f indique au compilateur que la sortie doit être à virgule flottante, avec cinq chiffres au total et deux chiffres à droite de la virgule décimale. Vous trouverez plus d'informations sur le caractère barre oblique inverse dans le tableau suivant :
Constante |
Sens |
'\UN' |
Avertissement sonore (cloche) |
'\B' |
En arrière |
'\F' |
Progression de la forme |
'\N' |
Nouvelle ligne |
'\R' |
Retour à la tête |
'\T' |
Carte horizontale |
'\v' |
Carte verticale |
'\'' |
Citation simple |
'\"' |
Guillemets doubles |
'\?' |
Point d'interrogation |
'\\' |
Barre oblique inverse |
'\0' |
Rien |
Considérez l’instruction scanf suivante
scanf(“%d”, &num);
Les données du clavier sont reçues par la fonction scanf. Dans le format ci-dessus, le symbole & (esperluette) avant chaque nom de variable est un opérateur qui spécifie l'adresse du nom de la variable.
Ce faisant, l’exécution s’arrête et attend que la valeur de la variable num soit saisie. Lorsque la valeur entière est saisie et que la touche Entrée est enfoncée, l'ordinateur passe à l'instruction suivante. Les codes de format scanf et printf sont répertoriés dans le tableau suivant :
Code |
Loi... |
%C |
Caractère unique |
%D |
Nombre entier décimal |
%ET |
Valeur à virgule flottante |
%F |
Valeur à virgule flottante |
%G |
Valeur à virgule flottante |
%H |
Entier court |
%JE |
Entier décimal, hexadécimal ou octal |
%LE |
Entier octal |
%S |
Corde |
%Dans |
Entier décimal non signé |
%X |
Entier hexadécimal |
Déclarations de contrôle
Un programme se compose d’un certain nombre d’instructions qui sont généralement exécutées en séquence. Les programmes peuvent être beaucoup plus puissants si nous pouvons contrôler l’ordre dans lequel les instructions sont exécutées.
Les déclarations se répartissent en trois types généraux :
- Affectation dans laquelle des valeurs, généralement les résultats de calculs, sont stockées dans des variables.
- Entrée/Sortie, les données sont lues ou imprimées.
- Contrôle : Le programme décide ce qu'il faut faire ensuite.
Cette section traitera de l'utilisation des instructions de contrôle en C. Nous montrerons comment elles peuvent être utilisées pour écrire des programmes puissants en :
- Répétition de sections importantes du programme.
- Sélection entre les sections optionnelles d'un programme.
L'instruction if else
Il est utilisé pour décider de faire quelque chose à un moment précis ou pour choisir entre deux plans d'action.
Le test suivant détermine si un étudiant a réussi un examen avec une note de passage de 45
si (résultat >= 45)
printf("Pass\n");
autre
printf("Erreur\n");
Vous pouvez utiliser la partie if sans le else.
si (température < 0)
print("Congelé\n");
Chaque version se compose d'un test, l'instruction entre parenthèses suivant l'instruction if. Si le test est vrai, alors l’instruction suivante est respectée. Si elle est fausse, alors l'instruction suivant l'instruction else, si elle est présente, est respectée. Après cela, le reste du programme continue normalement.
Si nous voulons que plusieurs instructions suivent if ou else, elles doivent être regroupées entre accolades. Un tel regroupement est appelé instruction ou bloc composé.
si (résultat >= 45)
{ printf("Réussi\n");
printf("Félicitations\n");
}
autre
{ printf("Échec\n");
printf("Meilleure chance la prochaine fois\n");
}
Parfois, nous souhaitons prendre une décision à plusieurs niveaux en fonction de plusieurs conditions. La manière la plus générale de procéder est d’utiliser la variante else if dans l’instruction if.
Cela fonctionne en cascade de plusieurs comparaisons. Dès que l’un d’entre eux renvoie un résultat vrai, l’instruction ou le bloc suivant est exécuté et aucune autre comparaison n’est effectuée. Dans l’exemple suivant, nous attribuons des notes en fonction du résultat de l’examen.
si (résultat <=100 et résultat >= 75)
printf("Réussi : Note A\n");
sinon si (résultat >= 60)
printf("Réussi : note B\n");
sinon si (résultat >= 45)
printf("Réussi : note C\n");
autre
printf("Échec\n");
Dans cet exemple, toutes les comparaisons testent une seule variable appelée résultat. Dans d’autres cas, chaque test peut impliquer une variable différente ou une combinaison de tests. Le même modèle peut être utilisé avec plus ou moins de clauses else if, et la dernière clause else seule peut être omise.
Il appartient au programmeur de concevoir la structure appropriée pour chaque problème de programmation. Pour mieux comprendre l'utilisation de if else, voyons l'exemple
#include <stdio.h>
int main()
{
entier;
pour(nombre = 0; nombre < 10; nombre = nombre + 1)
{
si (nombre == 2)
printf("num est maintenant égal à %d\n", num);
si (nombre < 5)
printf("num est maintenant %d, ce qui est inférieur à 5\n", num);
autre
printf("num est maintenant %d, ce qui est supérieur à 4\n", num);
} /* fin de la boucle for */
retourner 0;
}
Résultat du programme
num est maintenant 0, ce qui est inférieur à 5
num est maintenant 1, ce qui est inférieur à 5
num est maintenant égal à 2
num est maintenant 2, ce qui est inférieur à 5
num est maintenant 3, ce qui est inférieur à 5
num est maintenant 4, ce qui est inférieur à 5
num est maintenant 5, ce qui est supérieur à 4
num est maintenant 6, ce qui est supérieur à 4
num est maintenant 7, ce qui est supérieur à 4
num est maintenant 8, ce qui est supérieur à 4
num est maintenant 9, ce qui est supérieur à 4
L'instruction switch
Il s’agit d’une autre forme de prise de décision à plusieurs niveaux. Il est bien structuré, mais ne peut être utilisé que dans certains cas où :
- Une seule variable est testée, toutes les branches doivent dépendre de la valeur de cette variable. La variable doit être de type intégral. (int, long, court ou char).
- Chaque valeur possible de la variable peut contrôler une seule branche. Une branche finale par défaut peut éventuellement être utilisée pour intercepter tous les cas non spécifiés.
L'exemple ci-dessous clarifiera les choses. Il s'agit d'une fonction qui convertit un entier en une description vague. Cela est utile lorsque nous souhaitons seulement mesurer une quantité lorsqu'elle est assez petite.
estimation(nombre)
entier;
/* Estimez un nombre comme aucun, un, deux, plusieurs, beaucoup */
{ switch(numéro) {
cas 0:
printf("Aucun\n");
casser;
cas 1:
printf("Un\n");
casser;
cas 2:
printf("Deux\n");
casser;
cas 3:
cas 4:
cas 5:
printf("Différent\n");
casser;
défaut :
printf("Plusieurs\n");
casser;
}
}
Chaque cas intéressant est répertorié avec une action correspondante. L'instruction break empêche l'exécution d'autres instructions en quittant le commutateur. Étant donné que les cas 3 et 4 n'ont pas de pauses ultérieures, ils continuent à permettre la même action pour des valeurs numériques différentes.
Les instructions if et switch permettent au programmeur de choisir parmi un certain nombre d'actions possibles. Voyons un exemple :
#include <stdio.h>
int main()
{
entier;
pour (num = 3 ; num < 13 ; num = num + 1)
{
commutateur (num)
{
cas 3:
printf("La valeur est trois\n");
casser;
cas 4:
printf("La valeur est quatre\n");
casser;
cas 5:
cas 6:
cas 7:
cas 8:
printf("La valeur est comprise entre 5 et 8\n");
casser;
cas 11:
printf("La valeur est onze\n");
casser;
défaut :
printf("C'est l'une des valeurs non définies\n");
casser;
} /* fin du commutateur */
} /* fin de la boucle for */
retourner 0;
}
La sortie du programme sera
La valeur est trois
La valeur est quatre
La valeur est comprise entre 5 et 8
La valeur est comprise entre 5 et 8
La valeur est comprise entre 5 et 8
La valeur est comprise entre 5 et 8
C'est l'une des valeurs indéfinies
C'est l'une des valeurs indéfinies
La valeur est onze
C'est l'une des valeurs indéfinies
La déclaration d'interruption
Nous avons déjà rencontré une rupture dans la discussion de l’instruction switch. Il est utilisé pour sortir d'une boucle ou d'un commutateur, en passant le contrôle à la première instruction au-delà de la boucle ou du commutateur.
Avec les boucles, break peut être utilisé pour forcer une sortie anticipée de la boucle, ou pour implémenter une boucle avec un test de sortie au milieu du corps de la boucle. Une rupture à l'intérieur d'une boucle doit toujours être incluse dans une instruction if qui fournit le test pour vérifier la condition de sortie.
La déclaration continue
C'est similaire au break mais on le rencontre moins fréquemment. Cela ne fonctionne qu'à l'intérieur des boucles où son effet est de forcer un saut immédiat vers l'instruction de contrôle de boucle.
- Dans une boucle while, passez à l'instruction de test.
- Dans une boucle do while, accédez à l'instruction de test.
- Dans une boucle for, passez au test et itérez.
Comme une pause, continuer doit être protégé par une instruction if. Il est peu probable que vous l’utilisiez très souvent. Pour mieux comprendre l'utilisation de break et continue, examinons le programme suivant :
#include <stdio.h>
int main()
{
valeur entière;
pour(valeur = 5 ; valeur < 15 ; valeur = valeur + 1)
{
si (valeur == 8)
casser;
printf("Dans la boucle d'interruption, la valeur est maintenant %d\n", valeur);
}
pour(valeur = 5 ; valeur < 15 ; valeur = valeur + 1)
{
si (valeur == 8)
continuer;
printf("Dans la boucle continue, la valeur est maintenant %d\n", valeur);
}
retourner 0;
}
Le résultat du programme sera le suivant :
Dans le cycle d'interruption, la valeur est désormais 5
Dans le cycle d'interruption, la valeur est désormais 6
Dans le cycle d'interruption, la valeur est désormais 7
Dans la boucle continue, la valeur est maintenant 5
Dans la boucle continue, la valeur est maintenant 6
Dans la boucle continue, la valeur est maintenant 7
Dans la boucle continue, la valeur est maintenant 9
Dans la boucle continue, la valeur est maintenant 10
Dans la boucle continue, la valeur est maintenant 11
Dans la boucle continue, la valeur est maintenant 12
Dans la boucle continue, la valeur est maintenant 13
Dans la boucle continue, la valeur est maintenant 14
Anneaux
L’autre type principal d’instruction de contrôle est la boucle. Les boucles vous permettent de répéter une instruction ou un bloc d'instructions. Les ordinateurs sont très doués pour répéter des tâches simples encore et encore. Le cycle est la manière dont C atteint cet objectif.
Le langage C propose trois types de boucles parmi lesquelles choisir : while, do-while et for.
- La boucle while continue de répéter une action jusqu'à ce qu'un test associé renvoie faux. Ceci est utile lorsque le programmeur ne sait pas à l’avance combien de fois la boucle sera parcourue.
- La boucle do while est similaire, mais le test se produit après l’exécution du corps de la boucle. Cela garantit que le corps de la boucle est exécuté au moins une fois.
- La boucle for est fréquemment utilisée, généralement lorsque la boucle doit être parcourue un nombre fixe de fois. Il est très flexible et les programmeurs novices doivent veiller à ne pas abuser de la puissance qu'il offre.
La boucle while
La boucle while répète une instruction jusqu'à ce que le test en haut soit évalué à faux. A titre d'exemple, voici une fonction permettant de renvoyer la longueur d'une chaîne. N'oubliez pas que la chaîne est représentée comme un tableau de caractères terminé par un caractère nul '\0'.
int chaîne_longueur(chaîne de caractères[])
{ int i = 0;
tandis que (chaîne[s] != '\0')
je++;
retour(s);
}
La chaîne est transmise à la fonction en tant qu'argument. La taille du tableau n'est pas spécifiée, la fonction fonctionnera pour une chaîne de n'importe quelle taille.
La boucle while est utilisée pour examiner les caractères de la chaîne un par un jusqu'à ce que le caractère nul soit trouvé. Ensuite, la boucle est rompue et l’index du null est renvoyé.
Tant que le caractère n'est pas nul, l'index est incrémenté et le test est répété. Nous approfondirons les tableaux plus tard. Voyons un exemple de boucle for while :
#include <stdio.h>
int main()
{
nombre int;
compte = 0;
pendant que (compte < 6)
{
printf("La valeur de count est %d\n", count);
compter = compter + 1;
}
retourner 0;
}
et le résultat s'affiche comme suit :
La valeur du comptage est 0
La valeur du compte est 1
La valeur du compte est 2
La valeur du compte est 3
La valeur du compte est 4
La valeur du compte est 5
La boucle do while
Ceci est très similaire à la boucle while, sauf que le test se produit à la fin du corps de la boucle. Cela garantit que la boucle s'exécute au moins une fois avant de continuer.
Une telle configuration est fréquemment utilisée lorsque des données doivent être lues. Le test vérifie ensuite les données et revient les relire si elles ne sont pas acceptables.
Faire
{
printf("Entrez 1 pour oui, 0 pour non :");
scanf("%d", &valeur_d'entrée);
} while (valeur_entrée != 1 && valeur_entrée != 0)
Pour mieux comprendre la boucle do while, regardons l'exemple suivant :
#include <stdio.h>
int main()
{
int je;
je = 0;
Faire
{
printf("La valeur de i est maintenant %d\n", i);
Je = Je + 1;
} tant que (i < 5);
retourner 0;
}
Le résultat du programme est affiché comme suit :
La valeur de i est maintenant 0
La valeur de i est maintenant 1
La valeur de i est maintenant 2
La valeur de i est maintenant 3
La valeur de i est maintenant 4
Le cycle pour
La boucle for fonctionne bien lorsque le nombre d'itérations de la boucle est connu avant d'entrer dans la boucle. La tête de boucle est composée de trois parties séparées par des points-virgules.
- Le premier est exécuté avant le démarrage du cycle. Il s’agit généralement de l’initialisation de la variable de boucle.
- Le deuxième est un test : la boucle est rompue lorsqu'elle renvoie faux.
- La troisième est une instruction à exécuter chaque fois que le corps de la boucle est terminé. Il s’agit généralement d’une augmentation du compteur de cycles.
L'exemple est une fonction qui calcule la moyenne des nombres stockés dans un tableau. La fonction prend le tableau et le nombre d'éléments comme arguments.
float media(tableau flottant[], int count)
{
total flottant = 0,0 ;
int je;
pour(i = 0; i < compte; i++)
total += tableau[i];
retour(total / nombre);
}
La boucle for garantit que le nombre correct d'éléments du tableau est ajouté avant de calculer la moyenne.
Les trois instructions au début d'une boucle for ne font généralement qu'une seule chose chacune, mais n'importe laquelle d'entre elles peut être laissée vide. Une première ou dernière instruction vide signifie qu'aucune initialisation ou incrémentation n'est en cours d'exécution. Une instruction de comparaison vide sera toujours considérée comme vraie. Cela entraînera l'exécution indéfinie de la boucle, à moins qu'elle ne soit interrompue par un autre moyen. Il pourrait s'agir d'une instruction de retour ou de pause.
Il est également possible de compresser plusieurs instructions en première ou troisième position, en les séparant par des virgules. Cela permet une boucle avec plus d'une variable de contrôle. L'exemple suivant illustre la définition d'une telle boucle, avec les variables hi et lo commençant respectivement à 100 et 0 et convergeant.
La boucle for fournit une variété de raccourcis à utiliser en son sein. Faites attention à l’expression suivante, dans cette expression, la boucle unique contient deux boucles for à l’intérieur. Ici hi-- est égal à hi = hi - 1 et lo++ est égal à lo = lo + 1,
pour(salut = 100, lo = 0; salut >= lo; salut--, lo++)
La boucle for est extrêmement flexible et vous permet de spécifier rapidement et facilement de nombreux types de comportement de programme. Voyons un exemple de boucle for
#include <stdio.h>
int main()
{
int indice;
pour(index = 0 ; index < 6 ; index = index + 1)
printf("La valeur de l'index est %d\n", index);
retourner 0;
}
Le résultat du programme est affiché comme suit :
La valeur de l'index est 0
La valeur de l'index est 1
La valeur de l'indice est 2
La valeur de l'indice est 3
La valeur de l'indice est 4
La valeur de l'indice est 5
L'instruction goto
C dispose d'une instruction goto qui vous permet de faire des sauts non structurés. Pour utiliser une instruction goto, utilisez simplement le mot clé réservé goto suivi du nom symbolique vers lequel vous souhaitez accéder. Le nom est ensuite inséré n'importe où dans le programme suivi de deux points. Vous pouvez sauter presque n'importe où dans une fonction, mais vous n'êtes pas autorisé à sauter dans une boucle, bien que vous soyez autorisé à sauter hors d'une boucle.
Ce programme particulier est un véritable désastre, mais c'est un bon exemple de la raison pour laquelle les auteurs de logiciels tentent d'éliminer autant que possible l'utilisation de l'instruction goto. Le seul endroit dans ce programme où il est logique d'utiliser goto est là où le programme sort de trois boucles imbriquées lors d'un saut. Dans ce cas, il serait assez fastidieux de définir une variable et de sortir successivement de chacune des trois boucles imbriquées, mais une instruction goto vous permet de sortir des trois de manière très concise.
Certaines personnes disent que l’instruction goto ne devrait jamais être utilisée en aucune circonstance, mais c’est une façon de penser étroite. S'il y a un endroit où un goto effectuera clairement un flux de contrôle plus ordonné qu'une autre construction, n'hésitez pas à l'utiliser, de toute façon, comme dans le reste du programme sur votre moniteur. Voyons un exemple :
#include <stdio.h>
int main()
{
int chien, chat, cochon;
aller à real_start;
quelque part:
printf("Ceci est une autre ligne du désordre.\n");
aller à stop_it;
/* la section suivante est la seule section avec un goto utilisable */
démarrage_réel :
pour(chien = 1 ; chien < 6 ; chien = chien + 1)
{
pour(chat = 1 ; chat < 6 ; chat = chat + 1)
{
pour(cochon = 1 ; cochon < 4 ; cochon = cochon + 1)
{
printf("Chien = %d Chat = %d Cochon = %d\n", chien, chat, cochon);
si ((chien + chat + cochon) > 8 ) aller à assez ;
}
}
}
assez : printf("Il y a assez d'animaux pour l'instant.\n");
/* ceci est la fin de la section avec une instruction goto utilisable */
printf("\nCeci est la première ligne du code.\n");
vas-y;
Où:
printf("Ceci est la troisième ligne du code.\n");
aller quelque part;
Là:
printf("Ceci est la deuxième ligne du code.\n");
aller où;
arrête ça:
printf("Ceci est la dernière ligne de ce désordre.\n");
retourner 0;
}
Voyons les résultats affichés
Chien = 1 Chat = 1 Cochon = 1
Chien = 1 Chat = 1 Cochon = 2
Chien = 1 Chat = 1 Cochon = 3
Chien = 1 Chat = 2 Cochon = 1
Chien = 1 Chat = 2 Cochon = 2
Chien = 1 Chat = 2 Cochon = 3
Chien = 1 Chat = 3 Cochon = 1
Chien = 1 Chat = 3 Cochon = 2
Chien = 1 Chat = 3 Cochon = 3
Chien = 1 Chat = 4 Cochon = 1
Chien = 1 Chat = 4 Cochon = 2
Chien = 1 Chat = 4 Cochon = 3
Chien = 1 Chat = 5 Cochon = 1
Chien = 1 Chat = 5 Cochon = 2
Chien = 1 Chat = 5 Cochon = 3
Assez parlé des animaux pour l’instant.
Ceci est la première ligne du code.
Ceci est la deuxième ligne du code.
Ceci est la troisième ligne du code.
C'est une autre ligne du désordre.
C'est la dernière ligne de ce désordre.
Pointeurs
Parfois, nous voulons savoir où se trouve une variable en mémoire. Un pointeur contient l'adresse d'une variable qui a une valeur spécifique. Lors de la déclaration d'un pointeur, un astérisque est placé immédiatement avant le nom du pointeur.
L'adresse de l'emplacement mémoire où la variable est stockée peut être trouvée en plaçant une esperluette devant le nom de la variable.
nombre entier; /* Variable entière normale */
int *numPtr; /* Pointeur vers une variable entière */
L'exemple suivant imprime la valeur de la variable et l'adresse mémoire de cette variable.
printf("La valeur %d est stockée à l'adresse %X\n", num, &num);
Pour affecter l'adresse de la variable num au pointeur numPtr, vous affectez l'adresse de la variable num, comme dans l'exemple suivant :
numPtr = #
Pour savoir ce qui est stocké à l'adresse pointée par numPtr, la variable doit être déréférencée. Le déréférencement est réalisé avec l'astérisque avec lequel le pointeur a été déclaré.
printf("La valeur %d est stockée à l'adresse %X\n", *numPtr, numPtr);
Toutes les variables d’un programme résident en mémoire. Les instructions ci-dessous nécessitent que le compilateur réserve 4 octets de mémoire sur un ordinateur 32 bits pour la variable à virgule flottante x, puis y entre la valeur 6,5.
flotteur x;
x = 6,5;
Étant donné que l'emplacement de l'adresse mémoire de toute variable est obtenu en plaçant l'opérateur & avant son nom, alors &x est l'adresse de x. C nous permet d'aller plus loin et de définir une variable, appelée pointeur, qui contient l'adresse d'autres variables. On peut plutôt dire que le pointeur pointe vers d’autres variables. Par exemple:
flotteur x;
nombre décimal* px;
x = 6,5;
px = &x;
définit px comme un pointeur vers des objets de type float et le définit égal à l'adresse de x. Ainsi, *px fait référence à la valeur de x :

Examinons les affirmations suivantes :
int var_x;
int* ptrX;
où_x = 6;
ptrX = &var_x;
*ptrX = 12;
printf("valeur de x : %d", var_x);
La première ligne oblige le compilateur à réserver de l'espace en mémoire pour un entier. La deuxième ligne indique au compilateur de réserver de l'espace pour stocker un pointeur.
Un pointeur est un emplacement de stockage pour une adresse. La troisième ligne devrait vous rappeler les instructions scanf. L'opérateur d'adresse « & » indique au compilateur d'aller à l'endroit où il a stocké var_x, puis de donner l'adresse de l'emplacement de stockage à ptrX.
L'astérisque * devant une variable indique au compilateur de déréférencer le pointeur et d'aller en mémoire. Vous pouvez ensuite effectuer des affectations à la variable stockée à cet emplacement. Vous pouvez référencer une variable et accéder à ses données via un pointeur. Voyons un exemple de pointeurs :
/* illustration de l'utilisation du pointeur */
#include <stdio.h>
int main()
{
int index, *pt1, *pt2;
indice = 39; /* toute valeur numérique */
pt1 = &index; /* l'adresse de l'index */
point2 = point1;
printf("La valeur est %d %d %d\n", index, *pt1, *pt2);
*pt1 = 13; /* ceci modifie la valeur de l'index */
printf("La valeur est %d %d %d\n", index, *pt1, *pt2);
retourner 0;
}
La sortie du programme sera affichée comme suit :
La valeur est 39 39 39
La valeur est 13 13 13
Voyons un autre exemple pour mieux comprendre l’utilisation des pointeurs :
#include <stdio.h>
#include <chaîne.h>
int main()
{
char strg[40], *là, un, deux ;
int *pt, liste[100], index;
strcpy(strg, "Ceci est une chaîne de caractères.");
/* La fonction strcpy() est utilisée pour copier une chaîne dans une autre. Nous en saurons plus sur la fonction strcpy() dans la section String */.
un = strg[0]; /* un et deux sont identiques */
deux = *ctrl;
printf("La première sortie est %c %c\n", un, deux);
un = strg[8]; /* un et deux sont identiques */
deux = *(ctrl+8);
printf("La deuxième sortie est %c %c\n", un, deux);
là = ctrl+10; /* strg+10 est identique à &strg[10] */
printf("La troisième sortie est %c\n", strg[10]);
printf("La quatrième sortie est %c\n", *là);
pour (index = 0 ; index < 100 ; index++)
liste[index] = index + 100;
pt = liste + 27;
printf("La cinquième sortie est %d\n", list[27]);
printf("La sixième sortie est %d\n", *pt);
retourner 0;
}
La sortie du programme ressemblera à ceci :
La première sortie est TT
La deuxième sortie est aa
La troisième sortie est c
La quatrième sortie est c
La cinquième sortie est 127
La sixième sortie est 127
Matrices
Un tableau est une collection de variables du même type. Les éléments individuels du tableau sont identifiés par un index entier. En C, l'index commence à zéro et est toujours écrit entre crochets.
Nous avons déjà rencontré des tableaux unidimensionnels déclarés de cette manière.
int résultats[20];
Les tableaux peuvent avoir plusieurs dimensions, auquel cas ils peuvent être déclarés comme
int résultats_2d[20][5];
int résultats_3d[20][5][3];
Chaque index possède son propre ensemble de crochets. Un tableau est déclaré dans la fonction principale, incluant généralement les détails de taille. Vous pouvez utiliser un autre type appelé pointeur au lieu d'un tableau. Cela signifie que la taille n'est pas fixée immédiatement, mais que l'espace peut être alloué selon les besoins. Il s’agit d’une technique avancée qui n’est requise que dans certains programmes spécialisés.
À titre d’exemple, voici une fonction simple permettant de sommer tous les entiers d’un tableau unidimensionnel.
int add_array(int tableau[], int taille)
{
int je;
int total = 0;
pour(i = 0; i < taille; i++)
total += tableau[i];
retour(total);
}
Le programme ci-dessous créera une chaîne, accédera à certaines données qu'elle contient et l'imprimera. Il y accédera à nouveau via des pointeurs, puis imprimera la chaîne. Il devrait afficher « Bonjour ! » et "012345678" sur des lignes différentes. Voyons le codage du programme :
#include <stdio.h>
#define STR_LENGTH 10
vide principal()
{
caractère Str[STR_LENGTH];
caractère* pStr;
int je;
Str[0] = 'H';
Str[1] = 'i';
Str[2] = '!';
Str[3] = '\0'; // caractère spécial de fin de chaîne NULL
printf("La chaîne dans Str est : %s\n", Str);
pStr = &Str[0];
pour (i = 0; i < STRLEN; i++)
{
*pStr = '0'+i;
; ...
}
Str[STR_LENGTH-1] = '\0';
printf("La chaîne dans Str est : %s\n", Str);
}
[] (crochets) sont utilisés pour déclarer le tableau. La ligne de programme char Str[STR_LENGTH]; déclare un tableau de dix caractères. Il s’agit de dix caractères individuels, tous rassemblés en mémoire au même endroit. Nous pouvons y accéder via notre nom de variable Str avec [n] où n est le numéro de l'élément.
Il est toujours important de garder à l'esprit lorsque l'on parle de tableaux que lorsque C déclare un tableau de dix, les éléments accessibles sont numérotés de 0 à 9. L'accès au premier élément correspond à l'accès à l'élément 0. Ainsi, dans le cas des tableaux, vous comptez toujours de 0 à la taille du tableau - 1.
Ensuite, remarquez que nous avons inséré les lettres « Bonjour ! » dans le tableau, mais ensuite nous avons inséré un '\0', vous vous demandez probablement ce que c'est. "\0" signifie NULL et représente la fin de la chaîne. Toutes les chaînes de caractères doivent se terminer par ce caractère spécial '\0'. S'ils ne le font pas, et que quelqu'un appelle printf sur la chaîne, alors printf démarrera à l'emplacement mémoire de votre chaîne et continuera l'impression, en disant qu'il rencontre '\0' et vous vous retrouverez alors avec un tas de déchets à la fin de votre chaîne. Assurez-vous donc de terminer vos chaînes correctement.
Tableau de caractères
Une chaîne constante, comme
"Je suis une corde"
C'est un tableau de caractères. Il est représenté en interne en C par les caractères ASCII de la chaîne, c'est-à-dire « I », blanc, « a », « m », ... ou la chaîne ci-dessus, et terminé par le caractère nul spécial « \0 » afin que les programmes puissent trouver la fin de la chaîne.
Les constantes de chaîne sont souvent utilisées pour rendre la sortie du code utilisant printf compréhensible :
printf("Bonjour, tout le monde\n");
printf("La valeur de a est : %f\n", a);
Les constantes de chaîne peuvent être associées à des variables. C fournit la variable de type de caractère, qui peut contenir un caractère (1 octet) à la fois. Une chaîne de caractères est stockée dans un tableau de caractères, un caractère ASCII par position.
N'oubliez jamais que puisque les chaînes sont traditionnellement terminées par le caractère nul « \0 », un stockage supplémentaire est nécessaire dans le tableau.
C ne fournit aucun opérateur permettant de manipuler des chaînes entières à la fois. Les chaînes sont manipulées via des pointeurs ou via des routines spéciales disponibles dans la bibliothèque de chaînes standard string.h.
L'utilisation de pointeurs de caractères est relativement simple puisqu'un nom de tableau n'est qu'un pointeur vers son premier élément. Considérez le programme ci-dessous :
#include<stdio.h>
vide principal()
{
caractère texte_1[100], texte_2[100], texte_3[100];
caractère *ta, *tb;
int je;
/* définir le message sous forme de tableau */
/* de caractères ; initialisez-le */
/* à la chaîne constante "..." */
/* laisser le compilateur décider */
/* sa taille en utilisant [] */
char message[] = "Bonjour, je suis une chaîne ; que suis-je ?
Toi?";
printf("Message d'origine : %s\n", message);
/* copier le message dans text_1 */
i=0;
tandis que ( (texte_1[i] = message[i]) != '\0' )
je++;
printf("Texte_1 : %s\n", texte_1);
/* utiliser une arithmétique de pointeur explicite */
votre=message;
tb=texte_2;
tandis que ( ( *tb++ = *ta++ ) != '\0' )
;
printf("Texte_2 : %s\n", texte_2);
}
Le résultat du programme sera le suivant :
Message d'origine : Salut, je suis une chaîne ; qu'est-ce que tu es?
Texte_1 : Bonjour, je suis une chaîne ; qu'est-ce que tu es?
Texte_2 : Bonjour, je suis une chaîne ; qu'est-ce que tu es?
La bibliothèque standard « string » contient de nombreuses fonctions utiles pour manipuler des chaînes, que nous découvrirons plus tard dans la section sur les chaînes.
Accès aux éléments
Pour accéder à un seul élément du tableau, le numéro d'index suit le nom de la variable entre crochets. La variable peut alors être traitée comme n'importe quelle autre variable en C. L'exemple suivant attribue une valeur au premier élément du tableau.
x[0] = 16;
L'exemple suivant imprime la valeur du troisième élément d'un tableau.
printf("%d\n", x[2]);
L'exemple suivant utilise la fonction scanf pour lire une valeur du clavier dans le dernier élément d'un tableau de dix éléments.
scanf("%d", &x[9]);
Initialisation des éléments du tableau
Les tableaux peuvent être initialisés comme n'importe quelle autre variable par affectation. Étant donné qu’un tableau contient plusieurs valeurs, les valeurs individuelles sont placées entre accolades et séparées par des virgules. L'exemple suivant initialise un tableau à dix dimensions avec les dix premières valeurs de la table de trois.
int x[10] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30};
Cela évite de devoir attribuer des valeurs individuellement, comme dans l’exemple suivant.
entier x[10];
x[0] = 3;
x[1] = 6;
x[2] = 9;
x[3] = 12;
x[4] = 15;
x[5] = 18;
x[6] = 21;
x[7] = 24;
x[8] = 27;
x[9] = 30;
Boucle à travers un tableau
Étant donné que le tableau est indexé séquentiellement, nous pouvons utiliser la boucle for pour afficher toutes les valeurs d'un tableau. L'exemple suivant affiche toutes les valeurs d'un tableau :
#include <stdio.h>
int main()
{
entier x[10];
compteur int;
/* Randomiser le générateur de nombres aléatoires */
srand((non signé)heure(NULL));
/* Affecter des valeurs aléatoires à la variable */
pour (compteur=0; compteur<10; compteur++)
x[compteur] = rand();
/* Afficher le contenu du tableau */
pour (compteur=0; compteur<10; compteur++)
printf("l'élément %d a la valeur %d\n", compteur, x[compteur]);
retourner 0;
}
Bien que la sortie imprime des valeurs différentes à chaque fois, le résultat ressemblera à ceci :
l'élément 0 a la valeur 17132
l'élément 1 a la valeur 24904
l'élément 2 a la valeur 13466
l'élément 3 a la valeur 3147
l'élément 4 a la valeur 22006
l'élément 5 a la valeur 10397
l'élément 6 a la valeur 28114
l'élément 7 a la valeur 19817
l'élément 8 a la valeur 27430
l'élément 9 a la valeur 22136
Tableaux multidimensionnels
Un tableau peut avoir plusieurs dimensions. Permettre au tableau d'avoir plus d'une dimension offre une plus grande flexibilité. Par exemple, les feuilles de calcul sont construites sur un tableau bidimensionnel ; un tableau pour les lignes et un tableau pour les colonnes.
L'exemple suivant utilise un tableau bidimensionnel avec deux lignes, chacune contenant cinq colonnes :
#include <stdio.h>
int main()
{
/* Déclarer un tableau multidimensionnel 2 x 5 */
entier x[2][5] = { {1, 2, 3, 4, 5},
{2, 4, 6, 8, 10}};
int ligne, colonne;
/* Afficher les lignes */
pour (ligne=0; ligne<2; ligne++)
{
/* Afficher les colonnes */
pour (colonne=0; colonne<5; colonne++)
printf("%d\t", x[ligne][colonne]);
{NS} = "Pointer le doigt sur le clavier";
}
retourner 0;
}
La sortie de ce programme sera affichée comme suit :
1 2 3 4 5
2 4 6 8 10
Cordes
Une chaîne est un groupe de caractères, généralement des lettres de l'alphabet, qui vous permet de formater votre affichage d'impression afin qu'il soit beau, qu'il ait des noms et des titres significatifs et qu'il soit esthétiquement agréable pour vous et les personnes qui utilisent la sortie de votre programme.
En fait, vous avez déjà utilisé des chaînes dans les exemples des sujets précédents. Mais ce n’est pas l’introduction complète des cordes. Il existe de nombreux cas possibles en programmation, où l'utilisation de chaînes formatées aide le programmeur à éviter trop de complications dans le programme et trop de bugs, bien sûr.
Une définition de chaîne complète est un tableau de données de caractères terminé par un caractère nul ('\0').
Lorsque le langage C doit utiliser une chaîne de données d'une manière ou d'une autre, pour la comparer à une autre chaîne, pour la générer, pour la copier dans une autre chaîne, ou autre, les fonctions sont configurées pour faire ce pour quoi elles ont été appelées jusqu'à ce qu'une valeur nulle soit rencontrée.
Il n’existe pas de type de données de base pour une chaîne en C. Au lieu de cela ; Les chaînes en C sont implémentées sous la forme d'un tableau de caractères. Par exemple, pour stocker un nom, vous pouvez déclarer un tableau de caractères suffisamment grand pour stocker le nom, puis utiliser les fonctions de bibliothèque appropriées pour manipuler le nom.
L'exemple suivant affiche la chaîne saisie par l'utilisateur à l'écran :
#include <stdio.h>
int main()
{
nom de caractère[80]; /* Crée un tableau de caractères
appelé nom */
printf("Entrez votre nom : ");
obtient(nom);
printf("Le nom que vous avez entré était %s\n", name);
retourner 0;
}
L'exécution du programme sera :
Entrez votre nom : Tarun Tyagi
Le nom que vous avez entré était Tarun Tyagi
Quelques fonctions de chaîne courantes
La bibliothèque standard string.h contient de nombreuses fonctions utiles pour manipuler des chaînes. Certaines des fonctionnalités les plus utiles ont été illustrées ici.
La fonction strlen
La fonction strlen est utilisée pour déterminer la longueur d'une chaîne. Apprenons à utiliser strlen avec un exemple :
#include <stdio.h>
#include <chaîne.h>
int main()
{
nom du personnage[80];
pleine longueur;
printf("Entrez votre nom : ");
obtient(nom);
longueur = strlen(nom);
printf("Votre nom contient %d caractères\n", longueur);
retourner 0;
}
Et l'exécution du programme sera la suivante :
Entrez votre nom : Tarun Subhash Tyagi
Votre nom comporte 19 caractères
Entrez votre nom : Preeti Tarun
Votre nom comporte 12 caractères
La fonction strcpy
La fonction strcpy est utilisée pour copier une chaîne vers une autre. Apprenons à utiliser cette fonction avec un exemple :
#include <stdio.h>
#include <chaîne.h>
int main()
{
premier caractère[80];
char second[80];
printf("Entrez la première chaîne : ");
obtient(premier);
printf("Entrez la deuxième chaîne : ");
obtient(seconde);
printf("premier : %s, et deuxième : %s Avant strcpy()\n "
, premier, deuxième);
strcpy(second, premier);
printf("premier : %s, et deuxième : %s après strcpy()\n",
premier, deuxième);
retourner 0;
}
et la sortie du programme sera :
Entrez la première chaîne : Tarun
Entrez la deuxième chaîne : Tyagi
première : Tarun et deuxième : Tyagi Avant strcpy()
premier : Tarun et deuxième : Tarun Après strcpy()
La fonction strcmp
La fonction strcmp est utilisée pour comparer deux chaînes ensemble. Le nom d'une variable de tableau pointe vers l'adresse de base de ce tableau. Donc, si nous essayons de comparer deux chaînes en utilisant ce qui suit, nous comparerons deux adresses, qui bien sûr ne seront jamais les mêmes puisque deux valeurs ne peuvent pas être stockées au même endroit.
si (premier == deuxième) /* Les chaînes ne peuvent jamais être comparées */
L'exemple suivant utilise la fonction strcmp pour comparer deux chaînes :
#include <chaîne.h>
int main()
{
char premier[80], second[80];
int t;
pour(t=1;t<=2;t++)
{
printf("\nEntrez une chaîne : ");
obtient(premier);
printf("Entrez une autre chaîne : ");
obtient(seconde);
si (strcmp(premier, deuxième) == 0)
puts("Les deux chaînes sont égales");
autre
puts("Les deux chaînes ne sont pas égales");
}
retourner 0;
}
Et l'exécution du programme sera la suivante :
Entrez une chaîne : Tarun
Entrez une autre chaîne : tarun
Les deux cordes ne sont pas identiques
Entrez une chaîne : Tarun
Entrez une autre chaîne : Tarun
Les deux chaînes sont égales
La fonction strcat
La fonction strcat est utilisée pour joindre une chaîne à une autre. Voyons comment ? A l'aide d'un exemple :
#include <chaîne.h>
int main()
{
char premier[80], second[80];
printf("Entrez une chaîne : ");
obtient(premier);
printf("Entrez une autre chaîne : ");
obtient(seconde);
strcat(premier, deuxième);
printf("Les deux chaînes jointes : %s\n",
D'abord);
retourner 0;
}
Et l'exécution du programme sera la suivante :
Entrez une chaîne : Données
Entrez une autre chaîne : Récupération
Les deux chaînes jointes : DonnéesRécupération
La fonction strtok
La fonction strtok est utilisée pour trouver le prochain jeton dans une chaîne. Le jeton est spécifié par une liste de délimiteurs possibles.
L'exemple suivant lit une ligne de texte à partir d'un fichier et détermine un mot à l'aide des délimiteurs, de l'espace, de la tabulation et de la nouvelle ligne. Chaque mot est ensuite affiché sur une ligne distincte :
#include <stdio.h>
#include <chaîne.h>
int main()
{
FICHIER *dans;
ligne de caractère[80];
char *délimiteurs = " \t\n";
caractère *jeton;
si ((in = fopen("C:\texte.txt", "r")) == NULL)
{
puts("Impossible d'ouvrir le fichier d'entrée");
retourner 0;
}
/* Lire chaque ligne une à la fois */
tandis que(!feof(dans))
{
/* Obtenir une ligne */
fgets(ligne, 80, dans);
si (!feof(dans))
{
/* Diviser la ligne en mots */
token = strtok(ligne, délimiteurs);
tant que (jeton != NULL)
{
mettre(jeton);
/* Obtenir le mot suivant */
token = strtok(NULL, délimiteurs);
}
}
}
fclose(dans);
retourner 0;
}
Le programme ci-dessus, dans = fopen("C:\\text.txt", "r"), ouvre un fichier existant C:\\text.txt. S'il n'existe pas dans le chemin spécifié ou si pour une raison quelconque le fichier ne peut pas être ouvert, un message d'erreur apparaît à l'écran.
Considérez l’exemple suivant, qui utilise certaines de ces fonctions :
#include <stdio.h>
#include <chaîne.h>
vide principal()
{
char line[100], *sous-texte;
/* initialiser la chaîne */
strcpy(line,"bonjour, je suis une chaîne;");
printf("Ligne : %s\n", ligne);
/* ajouter à la fin de la chaîne */
strcat(ligne,"qu'est-ce que tu es ?");
printf("Ligne : %s\n", ligne);
/* trouver la longueur de la chaîne */
/* strlen ramène */
/* longueur comme type size_t */
printf("Longueur de la ligne : %d\n", (int)strlen(line));
/* rechercher l'occurrence des sous-chaînes */
si ( (sous-texte = strchr ( ligne, 'W' ) )!= NULL )
printf("Chaîne commençant par \"W\" ->%s\n",
sous_texte);
si ( ( sous_texte = strchr ( ligne, 'w' ) )!= NULL )
printf("Chaîne commençant par \"w\" ->%s\n",
sous_texte);
si ( ( sous_texte = strchr ( sous_texte, 'u' ) ) != NULL )
printf("Chaîne commençant par \"w\" ->%s\n",
sous_texte);
}
La sortie du programme sera affichée comme suit :
Ligne : Salut, je suis une chaîne ;
Ligne : bonjour, je suis une corde ; qu'est-ce que tu es?
Longueur de la ligne : 35
Chaîne commençant par "w" -> qui êtes-vous ?
Chaîne commençant par « w » ->u ?
Fonctions
La meilleure façon de développer et de maintenir un programme de grande envergure est de le construire à partir de parties plus petites, chacune étant plus facile à gérer (une technique parfois appelée diviser pour mieux régner). Les fonctions permettent au programmeur de modulariser le programme.
Les fonctions vous permettent de diviser des programmes complexes en petits blocs, chacun étant plus facile à écrire, à lire et à gérer. Nous avons déjà rencontré la fonction principale et utilisé printf de la bibliothèque standard. Nous pouvons bien sûr créer nos propres fonctions et fichiers d'en-tête. Une fonction a la disposition suivante :
type de retour nom de fonction (liste d'arguments si nécessaire)
{
déclarations locales;
déclarations ;
retourner valeur-retournée;
}
Si le type de retour est omis, la valeur par défaut de C est int. La valeur de retour doit être du type déclaré. Toutes les variables déclarées à l'intérieur des fonctions sont appelées variables locales, car elles ne sont connues que de la fonction pour laquelle elles ont été définies.
Certaines fonctions disposent d'une liste de paramètres qui fournit une méthode de communication entre la fonction et le module qui a appelé la fonction. Les paramètres sont également des variables locales, car ils ne sont pas disponibles en dehors de la fonction. Les programmes discutés jusqu'à présent ont tous un main, qui est une fonction.
Une fonction peut simplement effectuer une tâche sans renvoyer aucune valeur, auquel cas elle présente la disposition suivante :
void function-name (liste d'arguments si nécessaire)
{
instructions locales ;
déclarations;
}
Les arguments sont toujours passés par valeur dans les appels de fonction C. Cela signifie que des copies locales des valeurs des arguments sont transmises aux routines. Toutes les modifications apportées aux arguments à l’intérieur de la fonction sont apportées uniquement aux copies locales des arguments.
Pour modifier ou définir un argument dans la liste d'arguments, cet argument doit être passé sous forme d'adresse. Les variables régulières sont utilisées si la fonction ne modifie pas les valeurs de ces arguments. Vous DEVEZ utiliser des pointeurs si la fonction modifie les valeurs de ces arguments.
Apprenons avec quelques exemples :
#include <stdio.h>
échange vide (int *a, int *b)
{
température interne;
température = *a;
*a = *b;
*b = température;
printf("À partir de la fonction d'échange : ");
printf("a = %d, b = %d\n", *a, *b);
}
vide principal()
{
à l'intérieur de a, b;
a = 5;
e = 7;
printf("Depuis le fichier principal : a = %d, b = %d\n", a, b);
échanger(&a, &b);
printf("Retour au menu principal : ");
printf("a = %d, b = %d\n", a, b);
}
Et la sortie de ce programme sera affichée comme suit :
Depuis le principal : a = 5, b = 7
À partir de la fonction d'échange : a = 7, b = 5
Retour au menu principal : a = 7, b = 5
Voyons un autre exemple. L'exemple suivant utilise une fonction appelée square qui imprime le carré des nombres compris entre 1 et 10.
#include <stdio.h>
int carré(int x); /* Prototype de fonction */
int main()
{
compteur int;
pour (compteur=1; compteur<=10; compteur++)
printf("Le carré de %d est %d\n", compteur, carré(compteur));
retourner 0;
}
/* Définir la fonction 'carré' */
int carré(int x)
{
retourner x * x;
}
La sortie de ce programme sera affichée comme suit :
Le carré de 1 est 1
Le carré de 2 est 4
Le carré de 3 est 9
Le carré de 4 est 16
Le carré de 5 est 25
Le carré de 6 est 36
Le carré de 7 est 49
Le carré de 8 est 64
Le carré de 9 est 81
Le carré de 10 est 100
Le prototype de fonction carrée déclare une fonction qui prend un paramètre entier et renvoie un entier. Lorsque le compilateur atteint l'appel de fonction à square dans le programme principal, il est en mesure de vérifier l'appel de fonction par rapport à la définition de fonction.
Lorsque le programme atteint la ligne qui appelle la fonction carrée, le programme saute vers la fonction et exécute cette fonction avant de reprendre son chemin à travers le programme principal. Les programmes qui n'ont pas de type de retour doivent être déclarés en utilisant void. Ainsi, les paramètres de fonction peuvent être transmis par valeur ou par référence.
Une fonction récursive est une fonction qui s'appelle elle-même. Et ce processus est appelé récursivité.
Fonctions de passage par valeur
Les paramètres de la fonction carrée dans l'exemple précédent sont passés par valeur. Cela signifie qu'une seule copie de la variable a été transmise à la fonction. Toute modification de la valeur ne sera pas reflétée dans la fonction appelante.
L'exemple suivant utilise le passage par valeur et modifie la valeur du paramètre passé, ce qui n'a aucun effet sur la fonction appelante. La fonction count_down a été déclarée comme void car il n'y a pas de type de retour.
#include <stdio.h>
void compte_à_rebours(int x);
int main()
{
compteur int;
pour (compteur=1; compteur<=10; compteur++)
count_down(compteur);
retourner 0;
}
compte à rebours vide (int x)
{
compteur int;
pour (compteur = x; compteur > 0; compteur--)
{
printf("%d ", x);
X--;
}
{NS} = "Pointer le doigt sur le clavier";
}
La sortie du programme sera affichée comme suit :
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
Voyons un autre exemple de C Pass By Value pour mieux le comprendre. L'exemple suivant convertit un nombre compris entre 1 et 30 000 saisi par l'utilisateur en mots.
#include <stdio.h>
void do_units(int num);
void do_tens(int num);
void do_teens(int num);
int main()
{
int num, reste;
Faire
{
printf("Entrez un nombre entre 1 et 30 000 : ");
{NS} = "%d";
} tant que (num < 1 || num > 30000);
reste = nombre;
printf("%d en mots = ", num);
do_tens(résiduel/1000);
si (num >= 1000)
printf("mille");
résidu %= 1000;
do_units(résiduel/100);
si (résidu >= 100)
{
printf("cent ");
}
si (num > 100 && num%100 > 0)
printf("et ");
résidu %=100;
do_tens(résidu);
{NS} = "Pointer le doigt sur le clavier";
retourner 0;
}
vide do_units(int num)
{
commutateur(numéro)
{
cas 1:
printf("un ");
casser;
cas 2:
printf("deux ");
casser;
cas 3:
printf("trois ");
casser;
cas 4:
printf("quatre ");
casser;
cas 5:
printf("cinq ");
casser;
cas 6:
printf("tu es ");
casser;
cas 7:
printf("sept ");
casser;
cas 8:
printf("huit ");
casser;
cas 9:
printf("neuf ");
}
}
vide do_tens(int num)
{
commutateur(num/10)
{
cas 1:
do_teens(nombre);
casser;
cas 2:
printf("vingt ");
casser;
cas 3:
printf("trente ");
casser;
cas 4:
printf("quarante ");
casser;
cas 5:
printf("cinquante ");
casser;
cas 6:
printf("soixante ");
casser;
cas 7:
printf("soixante-dix ");
casser;
cas 8:
printf("quatre-vingts ");
casser;
cas 9:
printf("quatre-vingt-dix ");
}
si (num/10 != 1)
do_units(num%10);
}
vide do_teens(int num)
{
commutateur(numéro)
{
cas 10:
printf("dix ");
casser;
cas 11:
printf("onze ");
casser;
cas 12:
printf("douze ");
casser;
cas 13:
printf("treize ");
casser;
cas 14:
printf("quatorze ");
casser;
cas 15:
printf("quinze ");
casser;
cas 16:
printf("seize ");
casser;
cas 17:
printf("dix-sept ");
casser;
cas 18:
printf("dix-huit ");
casser;
cas 19:
printf("dix-neuf ");
}
}
et la sortie du programme sera la suivante :
Entrez un nombre entre 1 et 30 000 : 12345
12345 en lettres = douze mille trois cent quarante-cinq
Appel à référence
Pour effectuer un appel de fonction par référence, au lieu de passer la variable elle-même, passez l'adresse de la variable. L'adresse de la variable peut être prise en utilisant l'opérateur &. Ce qui suit appelle une fonction d'échange passant l'adresse des variables au lieu des valeurs réelles.
échanger(&x, &y);
Déréférencement
Le problème que nous avons maintenant est que la fonction d'échange a reçu l'adresse au lieu de la variable, nous devons donc déréférencer les variables pour prendre en compte les valeurs réelles plutôt que les adresses des variables afin de les échanger.
Le déréférencement est réalisé en C en utilisant la notation de pointeur (*). En termes simples, cela signifie mettre un * avant chaque variable avant de l'utiliser afin qu'il fasse référence à la valeur de la variable plutôt qu'à son adresse. Le programme suivant illustre le passage par référence pour échanger deux valeurs.
#include <stdio.h>
= ...
int main()
{
entier x=6, y=10;
printf("Avant la fonction d'échange, x = %d et y =
{NS} = "x, y";
échanger(&x, &y);
printf("Après la fonction d'échange, x = %d et y =
{NS} = "x, y";
retourner 0;
}
échanger(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = température;
}
Voyons le résultat du programme :
Avant l'échange de fonctions, x = 6 et y = 10
Après l'échange de fonctions, x = 10 et y = 6
Les fonctions peuvent être récursives, c'est-à-dire qu'une fonction peut s'appeler elle-même. Chaque appel à lui-même nécessite que l'état actuel de la fonction soit poussé sur la pile. Il est important de se rappeler ce fait, car il est facile de créer un débordement de pile, c'est-à-dire que la pile n'a plus d'espace pour insérer plus de données.
L'exemple suivant calcule la factorielle d'un nombre en utilisant la récursivité. Une factorielle est un nombre multiplié par tout autre entier inférieur à lui, jusqu'à 1. Par exemple, la factorielle du nombre 6 est :
Factorielle 6 = 6 * 5 * 4 * 3 * 2 * 1
Par conséquent, la factorielle de 6 est 720. D'après l'exemple précédent, vous pouvez voir que la factorielle 6 = 6 * factorielle 5. De même, la factorielle 5 = 5 * factorielle 4, et ainsi de suite.
Voici la règle générale pour le calcul des nombres factoriels.
factorielle(n) = n * factorielle(n-1)
La règle ci-dessus se termine lorsque n = 1, puisque la factorielle de 1 est 1. Essayons de mieux la comprendre à l'aide d'un exemple :
#include <stdio.h>
long int factoriel(int num);
int main()
{
entier;
entier long f;
printf("Entrez un nombre : ");
{NS} = "%d";
f = factorielle(num);
printf("la factorielle de %d est %ld\n", num, f);
retourner 0;
}
long int factoriel(int num)
{
si (nombre == 1)
retour 1;
autre
retourner num * factorielle(num-1);
}
Voyons le résultat de l’exécution de ce programme :
Entrez un nombre : 7
factorielle de 7 est 5040
Allocation de mémoire en C
Le compilateur C dispose d'une bibliothèque d'allocation de mémoire, définie dans malloc.h. La mémoire est réservée via la fonction malloc et renvoie un pointeur vers l'adresse. Il prend un paramètre, la taille de la mémoire demandée en octets.
L'exemple suivant alloue de l'espace pour la chaîne « hello world ».
ptr = (char *)malloc(strlen("Bonjour tout le monde") + 1);
L'octet supplémentaire est nécessaire pour tenir compte du terminateur de chaîne, '\0'. Le (char *) est appelé un cast et force le type de retour à être char *.
Étant donné que les types de données ont des tailles différentes et que malloc renvoie de l'espace en octets, pour des raisons de portabilité, il est recommandé d'utiliser l'opérateur sizeof lors de la spécification d'une taille à allouer.
L'exemple suivant lit une chaîne dans le tampon du tableau de caractères, puis alloue la quantité exacte de mémoire demandée et la copie dans une variable nommée « ptr ».
#include <chaîne.h>
#include <malloc.h>
int main()
{
caractère *ptr, buffer[80];
printf("Entrez une chaîne : ");
obtenir(tampon);
ptr = (char *)malloc((strlen(tampon) + 1) *
taille(police));
strcpy(ptr, tampon);
printf("Vous avez entré : %s\n", ptr);
retourner 0;
}
Le résultat du programme sera le suivant :
Entrez une chaîne : L'Inde est la meilleure
Vous avez entré : L'Inde est la meilleure
Réallocation de mémoire
Il est possible que vous souhaitiez à plusieurs reprises, au cours de la programmation, réaffecter de la mémoire. Cela se fait avec la fonction realloc. La fonction realloc prend deux paramètres, l'adresse de base de la mémoire que vous souhaitez redimensionner et la quantité d'espace que vous souhaitez réserver, et renvoie un pointeur vers l'adresse de base.
Supposons que nous ayons un espace réservé pour un pointeur appelé msg et que nous souhaitions réaffecter l'espace à la quantité d'espace qu'il occupe déjà, plus la longueur d'une autre chaîne, auquel cas nous pourrions utiliser ce qui suit.
msg = (char *)realloc(msg, (strlen(msg) + strlen(tampon) + 1)*sizeof(char));
Le programme suivant illustre l'utilisation de malloc, realloc et free. L'utilisateur entre une série de chaînes qui sont jointes ensemble. Le programme arrête de lire les chaînes lorsqu'une chaîne vide est saisie.
#include <chaîne.h>
#include <malloc.h>
int main()
{
tampon de caractères[80], *msg;
int première fois=0;
Faire
{
printf("\nEntrez une phrase : ");
obtenir(tampon);
si (!première fois)
{
message = (char *)malloc((strlen(tampon) + 1) *
taille(police));
strcpy(msg, tampon);
première fois = 1;
}
autre
{
msg = (char *)realloc(msg, (strlen(msg) +
strlen(tampon) + 1) * sizeof(char));
strcat(msg, tampon);
}
mettre(message);
} while(strcmp(tampon, ""));
gratuit(msg);
retourner 0;
}
Le résultat du programme sera le suivant :
Entrez une phrase : Il était une fois Il
était une fois
Entrez une phrase : il était une fois un roi
Il était une fois il y avait un roi
Entrez une phrase : le roi était Il était
une fois il y avait un roi le roi était
Entrez une phrase :
Il était une fois un roi, le roi était
Libérer la mémoire
Lorsque vous avez terminé avec la mémoire qui a été allouée, vous ne devez jamais oublier de libérer la mémoire car cela libérera des ressources et améliorera la vitesse. Pour libérer la mémoire allouée, utilisez la fonction free.
libre(ptr);
Structures
En plus des types de données de base, C dispose d'un mécanisme de structure qui permet de regrouper les éléments de données associés sous un nom commun. C'est ce qu'on appelle communément un type défini par l'utilisateur.
Le mot-clé struct démarre la définition de la structure et une balise fournit le nom unique de la structure. Les types de données et les noms de variables ajoutés à la structure sont des membres de la structure. Le résultat est un modèle de structure qui peut être utilisé comme spécificateur de type. Ce qui suit est une structure avec une balise de mois.
mois de la structure
{
nom du personnage[10];
caractère abrégé[4];
int jours;
};
Un type de structure est généralement défini au début d'un fichier à l'aide d'une instruction typedef. typedef définit et nomme un nouveau type, lui permettant d'être utilisé dans tout le programme. typedef se trouve généralement immédiatement après les instructions #define et #include dans un fichier.
Le mot-clé typedef peut être utilisé pour définir un mot faisant référence à la structure au lieu de spécifier le mot-clé struct avec le nom de la structure. Habituellement, typedef est nommé en majuscules. Voici quelques exemples de définitions de structures.
structure de typedef {
nom du personnage[64];
char[128] cours;
majeur;
année interne;
} étudiant;
Ceci définit un nouveau type de variable étudiante de type étudiant qui peut être déclaré comme suit.
étudiant st_rec;
Remarquez à quel point cela est similaire à la déclaration d’un int ou d’un float. Le nom de la variable est st_rec, elle a des membres appelés nom, cours, âge et année. De même,
élément de type struct
{
données de caractère;
élément de structure *suivant;
} ÉLÉMENT DE PILE ;
Une variable d’élément de structure de type définie par l’utilisateur peut désormais être déclarée comme suit.
ÉLÉMENTSPILE *pile;
Considérez la structure suivante :
étudiant structuré
{
personnage *nom;
degré int;
};
Un pointeur vers la structure de l’étudiant peut être défini comme suit.
structure étudiant *hnc;
Lors de l'accès à un pointeur vers une structure, l'opérateur de pointeur de membre, ->, est utilisé à la place de l'opérateur point. Pour ajouter une note à une propriété,
s.degré = 50;
Vous pouvez évaluer la propriété comme suit.
s->degré = 50;
Comme pour les types de données de base, si vous souhaitez que les modifications apportées aux paramètres passés dans une fonction persistent, vous devez passer par référence (passer l'adresse). Le mécanisme est exactement le même que pour les types de données de base. Transmettez l'adresse et référencez la variable à l'aide de la notation de pointeur.
Après avoir défini la structure, vous pouvez déclarer une instance de celle-ci et attribuer des valeurs à ses membres à l'aide de la notation par points. L'exemple suivant illustre l'utilisation de la structure du mois.
#include <stdio.h>
#include <chaîne.h>
mois de la structure
{
nom du personnage[10];
abréviation de caractère[4];
int jours;
};
int main()
{
struct mois m;
strcpy(m.name, "Janvier");
strcpy(m.abbreviation, "janvier");
m.jours = 31;
printf("%s est abrégé en %s et a %d jours\n", m.name, m.abbreviation, m.days);
retourner 0;
}
Le résultat du programme sera le suivant :
Janvier est abrégé en Jan et compte 31 jours.
Tous les compilateurs ANSI C vous permettent d'attribuer une structure à une autre, en effectuant une copie membre par membre. Si nous avions des structures de mois appelées m1 et m2, nous pourrions attribuer les valeurs de m1 à m2 comme suit :
- Structure avec membres pointeurs.
- La structure est initialisée.
- Passer une structure à une fonction.
- Pointeurs et structures.
Structures avec membres pointeurs en C
Conserver des chaînes dans un tableau de taille fixe est une utilisation inefficace de la mémoire. Une approche plus efficace serait d’utiliser des pointeurs. Les pointeurs sont utilisés dans les structures exactement de la même manière qu'ils sont utilisés dans les définitions de pointeurs normales. Voyons un exemple :
#include <chaîne.h>
#include <malloc.h>
mois de la structure
{
personnage *nom;
char *abréviation;
int jours;
};
int main()
{
struct mois m;
m.name = (char *)malloc((strlen("Janvier")+1) *
taille(police));
strcpy(m.name, "Janvier");
m.abréviation = (char *)malloc((strlen("Jan")+1) *
taille(police));
strcpy(m.abbreviation, "janvier");
m.jours = 31;
printf("%s est abrégé en %s et a %d jours\n",
m.nom, m.abréviation, m.jours);
retourner 0;
}
Le résultat du programme sera le suivant :
Janvier est abrégé en Jan et compte 31 jours.
Initialiseurs de structure en C
Pour fournir un ensemble de valeurs initiales pour la structure, des initialiseurs peuvent être ajoutés à l'instruction de déclaration. Étant donné que les mois commencent à 1, mais que les tableaux commencent à zéro en C, un élément supplémentaire à la position zéro appelé junk a été utilisé dans l'exemple suivant.
#include <stdio.h>
#include <chaîne.h>
mois de la structure
{
personnage *nom;
char *abréviation;
int jours;
} mois_détails[] =
{
"Déchets", "Déchets", 0,
"Janvier", "Janvier", 31,
"Février", "Février", 28,
"Mars", "Mar", 31,
"Avril", "Avr", 30,
"Mai", "Mai", 31,
"Juin", "Juin", 30,
"Juillet", "Juillet", 31,
"Août", "Août", 31,
"Septembre", "Set", 30,
"Octobre", "Oct", 31,
"Novembre", "Nov", 30,
"Décembre", "Décembre", 31
};
int main()
{
compteur int;
pour (compteur=1; compteur<=12; compteur++)
printf("%s est abrégé en %s et a %d jours\n",
mois_détails[compteur].nom,
mois_détails[compteur].abréviation,
mois_détails[compteur].jours);
retourner 0;
}
Et le résultat sera affiché comme suit :
Janvier est abrégé en Jan et compte 31 jours.
Février est abrégé en Feb et compte 28 jours.
Mars est abrégé en Mar et compte 31 jours.
Avril est abrégé en Apr et compte 30 jours.
Mai est abrégé en mai et compte 31 jours.
Juin est abrégé en Jun et compte 30 jours.
Juillet est abrégé en Jul et compte 31 jours.
Août est abrégé en Aug et compte 31 jours.
Septembre est abrégé en Sep et compte 30 jours.
Octobre est abrégé en Oct et compte 31 jours.
Novembre est abrégé en Nov et compte 30 jours
Décembre est abrégé en Dec et compte 31 jours.
Passer des structures aux fonctions en C
Les structures peuvent être transmises en tant que paramètre à une fonction, comme n'importe quel type de données de base. L'exemple suivant utilise une structure appelée date qui est transmise à une fonction isLeapYear pour déterminer si l'année est une année bissextile.
Normalement, vous ne transmettriez que la valeur du jour, mais la structure entière est transmise pour illustrer la transmission de structures aux fonctions.
#include <stdio.h>
#include <chaîne.h>
mois de la structure
{
personnage *nom;
char *abréviation;
int jours;
} mois_détails[] =
{
"Déchets", "Déchets", 0,
"Janvier", "Janvier", 31,
"Février", "Février", 28,
"Mars", "Mar", 31,
"Avril", "Avr", 30,
"Mai", "Mai", 31,
"Juin", "Juin", 30,
"Juillet", "Juillet", 31,
"Août", "Août", 31,
"Septembre", "Set", 30,
"Octobre", "Oct", 31,
"Novembre", "Nov", 30,
"Décembre", "Décembre", 31
};
Date de la structure
{
int jour;
int mois;
année interne;
};
int isLeapYear(struct données d);
int main()
{
date de la structure d;
printf("Entrez la date (par exemple : 11/11/1980) : ");
scanf("%d/%d/%d", &d.jour, &d.mois, &d.année);
printf("La date %d %s %d est ", d.day,
mois_détails[j.mois].nom, j.année);
si (isLeapYear(d) == 0)
printf("pas ");
puts("une année bissextile");
retourner 0;
}
int isLeapYear(struct données d)
{
si ((j.année % 4 == 0 && j.année % 100 != 0) ||
d.année % 400 == 0)
retour 1;
retourner 0;
}
Et l'exécution du programme sera la suivante :
Entrez la date (par exemple : 11/11/1980) : 9/12/1980
La date du 9 décembre 1980 est une année bissextile
L'exemple suivant alloue dynamiquement un tableau de structures pour stocker les noms et les notes des étudiants. Les votes sont ensuite affichés à l’utilisateur par ordre croissant.
#include <chaîne.h>
#include <malloc.h>
étudiant structuré
{
personnage *nom;
degré int;
};
void swap(struct étudiant *x, struct étudiant *y);
int main()
{
structure étudiant *groupe;
tampon de caractères[80];
int faux;
int interne, externe;
int compteur, numÉtudiants;
printf("Combien d'étudiants y a-t-il dans le groupe : ");
scanf("%d", &numÉtudiants);
groupe = (struct étudiant *)malloc(numÉtudiants *
sizeof(struct étudiant));
pour (compteur=0; compteur<numEtudiants; compteur++)
{
parasite = getchar();
printf("Entrez le nom de l'étudiant : ");
obtenir(tampon);
groupe[compteur].nom = (char *)malloc((strlen(buffer)+1) * sizeof(char));
strcpy(groupe[compteur].nom, tampon);
printf("Entrez votre note : ");
scanf("%d", &group[compteur].grade);
}
pour (externe=0; externe<numEtudiants; externe++)
pour (intérieur=0; intérieur<extérieur; intérieur++)
si (groupe[externe].degré <
groupe[interne].degré)
échanger(&groupe[extérieur], &groupe[intérieur]);
puts("Le groupe dans l'ordre croissant des votes...");
pour (compteur=0; compteur<numEtudiants; compteur++)
printf("%s a atteint la note %d \n",
groupe[compteur].nom,
groupe[compteur].degré);
retourner 0;
}
void swap(struct étudiant *x, struct étudiant *y)
{
structure étudiante temporaire;
temp.name = (char *)malloc((strlen(x->name)+1) *
taille(police));
strcpy(temp.nom, x->nom);
temp.degré = x->degré;
x->degré = y->degré;
x->nom = (char *)malloc((strlen(y->nom)+1) *
taille(police));
strcpy(x->nom, y->nom);
y->degré = temp.degré;
y->nom = (char *)malloc((strlen(temp.nom)+1) *
taille(police));
strcpy(y->nom, temp.nom);
}
L'exécution de la sortie sera la suivante :
Combien d'étudiants y a-t-il dans le groupe : 4
Entrez le nom de l'étudiant : Anuraaj
Entrez la note : 7
Entrez le nom de l'étudiant : Honey
Entrez la note : 2
Entrez le nom de l'étudiant : Meetushi
Entrez la note : 1
Entrez le nom de l'étudiant : Deepti
Entrez la note : 4
Le groupe par ordre croissant de votes...
Meetushi a obtenu le rang 1,
Honey a obtenu le rang 2,
Deepti a obtenu le rang 4,
Anuraaj a obtenu le rang 7
Union
Une union vous permet de regarder les mêmes données avec des types différents ou d'utiliser les mêmes données avec des noms différents. Les syndicats s’apparentent à des structures. Une union est déclarée et utilisée de la même manière qu'une structure.
Un syndicat diffère d’une structure en ce sens qu’un seul de ses membres peut être utilisé à la fois. La raison est simple. Tous les membres d’un syndicat occupent la même zone mémoire. Ils sont disposés les uns au dessus des autres.
Les syndicats sont définis et déclarés de la même manière que les structures. La seule différence dans les déclarations est que le mot-clé union est utilisé à la place de struct. Pour définir une union simple d'une variable char et d'une variable entière, vous écririez ce qui suit :
union partagée {
caractère c;
int je;
};
Cette union partagée peut être utilisée pour créer des instances d'une union pouvant contenir une valeur de caractère c ou une valeur entière i. Il s'agit d'une condition OU. Contrairement à une structure qui contiendrait les deux valeurs, une union ne peut contenir qu'une seule valeur à la fois.
Une union peut être initialisée dès sa déclaration. Puisqu'un seul membre peut être utilisé à la fois et qu'un seul peut être initialisé. Pour éviter toute confusion, seul le premier membre de l'union peut être initialisé. Le code suivant montre une instance de l’union partagée en cours de déclaration et d’initialisation :
union partagée variable_générique = {`@'};
Notez que l'union generic_variable a été initialisée exactement comme le premier membre d'une structure serait initialisé.
Les membres individuels du syndicat peuvent être utilisés de la même manière que les membres de la structure peuvent être utilisés via l'opérateur membre (.). Il existe cependant une différence importante dans l’accès aux membres des syndicats.
L’accès ne devrait être autorisé qu’à un seul membre du syndicat à la fois. Étant donné qu’un syndicat stocke ses membres les uns sur les autres, il est important de n’accéder qu’à un seul membre à la fois.
Le mot clé de l'union
balise syndicale {
membre(s) du syndicat;
/* des déclarations supplémentaires peuvent être insérées ici */
}exemple;
Le mot clé union est utilisé pour déclarer des unions. Une union est un ensemble d'une ou plusieurs variables (union_members) qui ont été regroupées sous un seul nom. De plus, chacun de ces membres du syndicat occupe la même zone mémoire.
Le mot clé union identifie le début d'une définition d'union. Il est suivi d'une balise qui est le nom donné au syndicat. Après l'étiquette se trouvent les membres du syndicat placés entre accolades.
Une instance, la déclaration réelle d’une union, peut également être définie. Si vous définissez la structure sans l'instance, il s'agit simplement d'un modèle qui peut être utilisé ultérieurement dans un programme pour déclarer des structures. Vous trouverez ci-dessous le format d'un modèle :
balise syndicale {
membre(s) du syndicat;
/* des déclarations supplémentaires peuvent être insérées ici */
};
Pour utiliser le modèle, vous devez utiliser le format suivant : instance tag union ;
Pour utiliser ce format, vous devez avoir préalablement déclaré une union avec la balise spécifiée.
/* Déclarer un modèle d'union appelé tag */
balise syndicale {
entier;
Alpes salées;
}
/* Utiliser le modèle d'union */
balise d'union à variable mixte ;
/* Déclarer une union et une instance ensemble */
union générique_type_tag {
caractère c;
int je;
flotteur f;
double d;
} générique;
/* Initialise une union. */
données_union {
caractère complete_date[9];
structure de la balise part_date_tag {
caractère du mois[2];
caractère break_value1;
char jour[2];
caractère break_value2;
année char[2];
} partie_données;
}données = {"09/12/80"};
Essayons de mieux le comprendre à l’aide de quelques exemples :
#include <stdio.h>
int main()
{
union
{
valeur int; /* Ceci est la première partie de l'union */
structure
{
prénom; /* Ces deux valeurs constituent la deuxième partie */
deuxième personnage;
} moitié;
} nombre;
indice long;
pour (index = 12 ; index < 300000L ; index += 35231L)
{
nombre.valeur = index;
printf("%8x %6x %6x\n", nombre.valeur,
nombre.demi.premier,
nombre.demi.seconde);
}
retourner 0;
}
Et la sortie du programme sera affichée comme suit :
copie 0
89ab fabuleux ff89
134a 4a 13
9ce9 ffe9 ff9c
2688 ff88 26
b027 27 ffb0
39c6 ffc6 39
c365 65 ffc3
4g04 4 4g
Utilisation pratique d'un syndicat dans la récupération de données
Voyons maintenant une utilisation pratique de l'union dans la programmation de récupération de données. Prenons un petit exemple. Le programme suivant est le petit modèle de programme d'analyse des secteurs défectueux pour lecteur de disquette (a: ), mais il ne s'agit pas du modèle complet de logiciel d'analyse des secteurs défectueux.
Regardons le programme :
#include<dos.h>
#include<conio.h>
int main()
{
int rp, tête, piste, secteur, état ;
caractère *buf;
Union REGS entrée, sortie ;
construire des SREGS ;
clrscr();
/* Réinitialiser le système de disque pour l'initialiser sur le disque */
printf("\n Réinitialisation du système de disque....");
pour(rp=0;rp<=2;rp++)
{
dans.h.ah = 0;
dans.h.dl = 0x00;
int86(0x13,&intérieur,&extérieur);
}
printf("\n\n\n Maintenant, testons le disque pour détecter les secteurs défectueux....");
/* rechercher les secteurs défectueux */
pour(piste=0;piste<=79;piste++)
{
pour(tête=0;tête<=1;tête++)
{
pour(secteur=1;secteur<=18;secteur++)
{
dans.h.ah = 0x04;
en.al. = 1;
dans.h.dl = 0x00;
dans.h.ch = trace;
in.h.dh = tête;
in.h.cl = secteur;
dans.x.bx = FP_OFF(buf);
s.es = FP_SEG(buf);
int86x(0x13,&entrée,&sortie,&s);
si(out.x.cflag)
{
statut=out.h.ah;
printf("\n piste :%d Tête :%d Secteur :%d État ==0x%X",piste,tête,secteur,état);
}
}
}
}
printf("\n\n\nTerminé");
retourner 0;
}
Voyons maintenant à quoi ressemblera sa sortie s'il y a des secteurs défectueux sur la disquette :
Réinitialisation du système de disque....
Testons maintenant le disque pour détecter les secteurs défectueux...
piste:0 Tête:0 Secteur:4 État ==0xA
piste:0 Tête:0 Secteur:5 État ==0xA
piste:1 Tête:0 Secteur:4 État ==0xA
piste:1 Tête:0 Secteur:5 État ==0xA
piste:1 Tête:0 Secteur:6 État ==0xA
piste:1 Tête:0 Secteur:7 État ==0xA
piste:1 Tête:0 Secteur:8 État ==0xA
piste:1 Tête:0 Secteur:11 État ==0xA
piste:1 Tête:0 Secteur:12 État ==0xA
piste:1 Tête:0 Secteur:13 État ==0xA
piste:1 Tête:0 Secteur:14 État ==0xA
piste:1 Tête:0 Secteur:15 État ==0xA
piste:1 Tête:0 Secteur:16 État ==0xA
piste:1 Tête:0 Secteur:17 État ==0xA
piste:1 Tête:0 Secteur:18 État ==0xA
piste:1 Tête:1 Secteur:5 État ==0xA
piste:1 Tête:1 Secteur:6 État ==0xA
piste:1 Tête:1 Secteur:7 État ==0xA
piste:1 Tête:1 Secteur:8 État ==0xA
piste:1 Tête:1 Secteur:9 État ==0xA
piste:1 Tête:1 Secteur:10 État ==0xA
piste:1 Tête:1 Secteur:11 État ==0xA
piste:1 Tête:1 Secteur:12 État ==0xA
piste:1 Tête:1 Secteur:13 État ==0xA
piste:1 Tête:1 Secteur:14 État ==0xA
piste:1 Tête:1 Secteur:15 État ==0xA
piste:1 Tête:1 Secteur:16 État ==0xA
piste:1 Tête:1 Secteur:17 État ==0xA
piste:1 Tête:1 Secteur:18 État ==0xA
piste:2 Tête:0 Secteur:4 État ==0xA
piste:2 Tête:0 Secteur:5 État ==0xA
piste:14 Tête:0 Secteur:6 État ==0xA
Fait
Il peut être un peu difficile de comprendre les fonctions et les interruptions utilisées dans ce programme pour vérifier les secteurs défectueux sur le disque et réinitialiser le système de disque, etc., mais ne vous inquiétez pas, nous apprendrons tout cela dans les sections de programmation du BIOS et des interruptions plus tard dans les prochains chapitres.
Gestion de fichiers en C
L'accès aux fichiers en C s'effectue en associant un flux à un fichier. C communique avec les fichiers à l'aide d'un nouveau type de données appelé pointeur de fichier. Ce type est défini dans stdio.h et écrit comme FILE *. Un pointeur de fichier appelé output_file est déclaré dans une instruction comme
FICHIER *fichier_de_sortie;
Les modes de fichier de la fonction fopen
Votre programme doit ouvrir un fichier avant que vous puissiez y accéder. Cela se fait à l'aide de la fonction fopen, qui renvoie le pointeur vers le fichier demandé. Si le fichier ne peut pas être ouvert pour une raison quelconque, NULL sera renvoyé. Vous utiliserez généralement fopen comme suit
si ((file_output = fopen("file_output", "w")) == NULL)
fprintf(stderr, "Impossible d'ouvrir %s\n",
"fichier de sortie");
fopen prend deux arguments, tous deux des chaînes : le premier est le nom du fichier à ouvrir, le second est un caractère d'accès, qui est généralement r, aow etc. Les fichiers peuvent être ouverts dans différents modes, comme indiqué dans le tableau suivant.
Mode fichier |
R |
Ouvrir un fichier texte pour le lire. |
Dans |
Créer un fichier texte pour l'écriture. Si le fichier existe, il est écrasé. |
UN |
Ouvre un fichier texte en mode ajout. Le texte est ajouté à la fin du fichier. |
rb |
Ouvrir un fichier binaire pour la lecture. |
blanc cassé |
Créer un fichier binaire pour l'écriture. Si le fichier existe, il est écrasé. |
depuis |
Ouvre un fichier binaire en mode ajout. Les données sont ajoutées à la fin du fichier. |
e+ |
Ouvrir un fichier texte pour la lecture et l'écriture. |
en+ |
Créez un fichier texte pour la lecture et l'écriture. Si le fichier existe, il est écrasé. |
un+ |
Enfin, ouvrez un fichier texte pour la lecture et l’écriture. |
r+b ou rb+ |
Ouvre le fichier binaire pour la lecture et l'écriture. |
w+b ou wb+ |
Créez un fichier binaire pour la lecture et l'écriture. Si le fichier existe, il est écrasé. |
a+b ou ab+ |
Enfin, ouvrez un fichier texte pour la lecture et l’écriture. |
Les modes de rafraîchissement sont utilisés avec les fonctions fseek, fsetpos et rewind. La fonction fopen renvoie un pointeur de fichier, ou NULL si une erreur se produit.
L'exemple suivant ouvre un fichier, tarun.txt en mode lecture seule. C'est une bonne pratique de programmation de tester l'existence du fichier.
si ((dans = fopen("tarun.txt", "r")) == NULL)
{
puts("Impossible d'ouvrir le fichier");
retourner 0;
}
Fermeture des dossiers
Les fichiers sont fermés à l'aide de la fonction fclose. La syntaxe est la suivante :
fclose(dans);
Lecture de fichiers
La fonction feof est utilisée pour tester la fin du fichier. Les fonctions fgetc, fscanf et fgets sont utilisées pour lire les données du fichier.
L'exemple suivant répertorie le contenu d'un fichier à l'écran, en utilisant fgetc pour lire le fichier un caractère à la fois.
#include <stdio.h>
int main()
{
FICHIER *dans;
touche int;
si ((dans = fopen("tarun.txt", "r")) == NULL)
{
puts("Impossible d'ouvrir le fichier");
retourner 0;
}
tandis que (!feof(dans))
{
clé = fgetc(dans);
/* Le dernier caractère lu est le marqueur de fin de fichier, donc ne l'imprimez pas */
si (!feof(dans))
putchar(clé);
}
fclose(dans);
retourner 0;
}
La fonction fscanf peut être utilisée pour lire différents types de données du fichier, comme dans l'exemple suivant, à condition que les données du fichier soient au format de la chaîne de format utilisée avec fscanf.
fscanf(dans, "%d/%d/%d", &jour, &mois, &année);
La fonction fgets permet de lire un certain nombre de caractères d'un fichier. stdin est le flux de fichiers d'entrée standard et la fonction fgets peut être utilisée pour contrôler l'entrée.
Écriture dans un fichier
Les données peuvent être écrites dans le fichier à l'aide de fputc et fprintf. L'exemple suivant utilise les fonctions fgetc et fputc pour faire une copie d'un fichier texte.
#include <stdio.h>
int main()
{
FICHIER *à l'intérieur, *à l'extérieur ;
touche int;
si ((dans = fopen("tarun.txt", "r")) == NULL)
{
puts("Impossible d'ouvrir le fichier");
retourner 0;
}
out = fopen("copie.txt", "w");
tandis que (!feof(dans))
{
clé = fgetc(dans);
si (!feof(dans))
fputc(clé, sortie);
}
fclose(dans);
fclose(extérieur);
retourner 0;
}
La fonction fprintf peut être utilisée pour écrire des données formatées dans un fichier.
fprintf(sortie, "Date : %02d/%02d/%02d\n",
(jour, mois, année) ;
Arguments de ligne de commande avec C
La définition ANSI C pour déclarer la fonction main() est :
int main() ou int main(int argc, char **argv)
La deuxième version permet de passer des arguments depuis la ligne de commande. Le paramètre argc est un compteur d'arguments et contient le nombre de paramètres passés depuis la ligne de commande. Le paramètre argv est le vecteur d'arguments qui est un tableau de pointeurs vers des chaînes représentant les paramètres réels passés.
L'exemple suivant vous permet de passer n'importe quel nombre d'arguments depuis la ligne de commande et de les imprimer. argv[0] est le programme réel. Le programme doit être exécuté à partir d'une invite de commande.
#include <stdio.h>
int main(int argument, caractère **argument)
{
compteur int;
puts("Les arguments du programme sont :");
pour (compteur=0; compteur<argc; compteur++)
met(argv[compteur]);
retourner 0;
}
Si le nom du programme était count.c, il pourrait être appelé comme suit à partir de la ligne de commande.
compte 3
OU
compte 7
OU
compte 192 etc.
L'exemple suivant utilise des routines de gestion de fichiers pour copier un fichier texte dans un nouveau fichier. Par exemple, l'argument de la ligne de commande pourrait être appelé comme :
txtcpy un.txt deux.txt
#include <stdio.h>
int main(int argument, caractère **argument)
{
FICHIER *à l'intérieur, *à l'extérieur ;
touche int;
si (argument < 3)
{
puts("Utilisation : txtcpy source destination\n");
puts("La source doit être un fichier existant");
puts("Si le fichier de destination existe, il sera
"écrasé");
retourner 0;
}
si ((in = fopen(argv[1], "r")) == NULL)
{
puts("Impossible d'ouvrir le fichier à copier");
retourner 0;
}
si ((out = fopen(argv[2], "w")) == NULL)
{
puts("Impossible d'ouvrir le fichier de sortie");
retourner 0;
}
tandis que (!feof(dans))
{
clé = fgetc(dans);
si (!feof(dans))
fputc(clé, sortie);
}
fclose(dans);
fclose(extérieur);
retourner 0;
}
Manipulateurs petit à petit
Au niveau matériel, les données sont représentées sous forme de nombres binaires. La représentation binaire du nombre 59 est 111011. Le bit 0 est le bit le moins significatif et, dans ce cas, le bit 5 est le bit le plus significatif.
Chaque ensemble de bits est calculé comme 2 à la puissance de l'ensemble de bits. Les opérateurs au niveau du bit vous permettent de manipuler des variables entières au niveau du bit. Ce qui suit montre la représentation binaire du nombre 59.
représentation binaire du nombre 59 |
pièce 5 4 3 2 1 0 |
2ème puissance n 32 16 8 4 2 1 |
ensemble 1 1 1 0 1 1 |
Avec trois bits, il est possible de représenter les nombres de 0 à 7. Le tableau suivant montre les nombres de 0 à 7 sous leur forme binaire.
Chiffres binaires |
000 |
0 |
001 |
1 |
010 |
2 |
011 |
3 |
100 |
4 |
101 |
5 |
110 |
6 |
111 |
7 |
Le tableau suivant répertorie les opérateurs binaires qui peuvent être utilisés pour manipuler des nombres binaires.
Chiffres binaires |
Et |
ET petit à petit |
| |
OU petit à petit |
^ |
OU exclusif au niveau du bit |
~ |
Complément au niveau du bit |
<< |
Décalage binaire vers la gauche |
>> |
Décalage binaire vers la droite |
ET petit à petit
L'opérateur AND au niveau du bit est vrai uniquement si les deux bits sont définis. L'exemple suivant montre le résultat d'un AND au niveau du bit sur les nombres 23 et 12.
10111 (23)
01100 (12) E
Italien: ____________________
00100 (résultat = 4) |
Vous pouvez utiliser une valeur de masque pour vérifier si certains bits ont été définis. Si nous voulions vérifier si les bits 1 et 3 étaient définis, nous pourrions masquer le nombre avec 10 (la valeur des bits 1 et 3) et tester le résultat par rapport au masque.
#include <stdio.h>
int main()
{
int num, masque = 10;
printf("Entrez un nombre : ");
{NS} = "%d";
si ((num & masque) == masque)
puts("Les bits 1 et 3 sont définis");
autre
puts("Les bits 1 et 3 ne sont pas définis");
retourner 0;
}
OU petit à petit
L'opérateur OU au niveau du bit est vrai si l'un des bits est défini. Le résultat d'un OU binaire sur les nombres 23 et 12 est affiché ci-dessous.
10111 (23)
01100 (12) OU
Italien: ______________________
11111 (résultat = 31) |
Un masque peut être utilisé pour garantir qu'un ou plusieurs bits ont été définis. L'exemple suivant garantit que le bit 2 est défini.
#include <stdio.h>
int main()
{
int num, masque = 4;
printf("Entrez un nombre : ");
{NS} = "%d";
num |= masque;
printf("Après avoir vérifié que le bit 2 est défini : %d\n", num);
retourner 0;
}
OU exclusif au niveau du bit
Le OU exclusif au niveau du bit est vrai si l'un des deux bits est défini, mais pas les deux. Ce qui suit montre le résultat d'un OU exclusif au niveau du bit sur les nombres 23 et 12.
10111 (23)
01100 (12) OU exclusif (XOR)
Italien: _____________________________
11011 (résultat = 27) |
L'OR exclusif possède quelques propriétés intéressantes. Si vous faites le OU exclusif d'un nombre par lui-même, il le met à zéro puisque les zéros resteront zéro et les uns ne peuvent pas être tous les deux définis, ils sont donc mis à zéro.
Par conséquent, si vous effectuez un OU exclusif entre un nombre et un autre nombre, puis un OU exclusif du résultat avec l'autre nombre à nouveau, le résultat est le nombre d'origine. Vous pouvez essayer avec les nombres utilisés dans l'exemple précédent.
23 OU 12 = 27
27 ou 12 = 23
27 OU 23 = 12
Cette fonctionnalité peut être utilisée pour le cryptage. Le programme suivant utilise une clé de cryptage de 23 pour démontrer la propriété d'un numéro saisi par l'utilisateur.
#include <stdio.h>
int main()
{
int num, clé = 23;
printf("Entrez un nombre : ");
{NS} = "%d";
touche numérique ^=;
printf("OU exclusif avec %d renvoie %d\n", clé, num);
touche numérique ^=;
printf("OU exclusif avec %d renvoie %d\n", clé, num);
retourner 0;
}
Complimenter petit à petit
Le complément binaire est un opérateur de complément à un qui bascule le bit. Si c'est 1, il sera mis à 0, si c'est 0, il sera mis à 1.
#include <stdio.h>
int main()
{
entier = 0xFFFF;
printf("Le complément de %X est %X\n", num, ~num);
retourner 0;
}
Décalage binaire vers la gauche
L'opérateur Bitwise Shift Left décale le nombre vers la gauche. Les bits les plus significatifs sont perdus lorsque le nombre se décale vers la gauche et les bits les moins significatifs laissés libres sont nuls. La représentation binaire de 43 est présentée ci-dessous.
0101011 (décimal 43)
En décalant les bits vers la gauche, nous perdons le bit le plus significatif (dans ce cas, un zéro) et le nombre est complété par un zéro dans le bit le moins significatif. Voici le nombre résultant.
1010110 (décimal 86)
Décalage binaire vers la droite
L'opérateur Bitwise Shift Right décale le nombre vers la droite. Un zéro est introduit dans les bits les plus significatifs libérés et les bits les moins significatifs libérés sont perdus. Ce qui suit montre la représentation binaire du nombre 43.
0101011 (décimal 43)
En décalant les bits vers la droite, nous perdons le bit le moins significatif (dans ce cas, un) et le nombre est complété par un zéro dans le bit le plus significatif. Voici le nombre résultant.
0010101 (décimal 21)
Le programme suivant utilise Bitwise Shift Right et Bitwise AND pour afficher un nombre sous forme de nombre binaire 16 bits. Le nombre est décalé vers la droite successivement de 16 à zéro et combiné au niveau du bit avec 1 pour voir si le bit est défini. Une méthode alternative serait d'utiliser des masques successifs avec l'opérateur OR au niveau du bit.
#include <stdio.h>
int main()
{
int compteur, num;
printf("Entrez un nombre : ");
{NS} = "%d";
printf("%d est binaire : ", num);
pour (compteur=15; compteur>=0; compteur--)
printf("%d", (num >> compteur) & 1);
{NS} = "Pointer le doigt sur le clavier";
retourner 0;
}
Fonctions de conversion binaire-décimal
Les deux fonctions fournies ci-dessous sont destinées à la conversion binaire en décimal et décimal en binaire. La fonction fournie ci-dessous pour convertir un nombre décimal en nombre binaire correspondant prend en charge jusqu'à 32 bits de nombres binaires. Vous pouvez utiliser ce programme ou le programme fourni précédemment pour la conversion selon vos besoins.
Fonction de conversion décimale en binaire :
void Décimal_en_Binaire(void)
{
int entrée = 0;
int je;
int nombre = 0;
int binaire [32]; /* 32 bits, MAXIMUM 32 éléments */
printf ("Entrez le nombre décimal à convertir en
Pistes :");
scanf ("%d", &input);
Faire
{
i = entrée%2; /* MOD 2 pour obtenir 1 ou 0*/
binaire[compte] = i; /* Charger les éléments dans un tableau binaire */
entrée = entrée/2; /* Divisez l'entrée par 2 pour décrémenter via binaire */
compter++; /* Comptez combien d'éléments sont nécessaires*/
}while (entrée > 0);
/* Inverser et renvoyer des chiffres binaires */
printf("La représentation binaire est : ");
Faire
{
printf ("%d", binaire[compte - 1]);
compter--;
} tandis que (compte > 0);
imprimer("\n");
}
Fonction pour convertir du binaire en décimal :
La fonction suivante est utilisée pour convertir n'importe quel nombre binaire en son nombre décimal correspondant :
void Binaire_en_Décimal(void)
{
caractère binairehold[512];
char *binaire;
int i=0;
int déc = 0;
entier z;
printf("Entrez des chiffres binaires.\n");
printf("Les chiffres binaires ne sont que 0 ou 1 ");
printf("Entrée binaire : ");
binaire = obtient(binaryhold);
i=strlen(binaire);
pour (z=0; z<i; ++z)
{
déc=déc*2+(binaire[z]=='1'? 1:0); /* si Binary[z] est
égal à 1,
alors 1 sinon 0 */
}
imprimer("\n");
printf ("La valeur décimale de %s est %d",
piste, déc);
imprimer("\n");
}
Débogage et test
Erreurs de syntaxe
La syntaxe fait référence à la grammaire, à la structure et à l’ordre des éléments d’une instruction. Une erreur de syntaxe se produit lorsque vous enfreignez les règles, par exemple en oubliant de terminer une instruction par un point-virgule. Lorsque vous compilez votre programme, le compilateur produira une liste de toutes les erreurs de syntaxe qu'il pourrait rencontrer.
Un bon compilateur produira la liste avec une description de l’erreur et pourra fournir une solution possible. La correction des erreurs peut entraîner l'apparition d'erreurs supplémentaires lors de la recompilation. La raison est que les erreurs précédentes ont modifié la structure du programme, ce qui signifie que d’autres erreurs ont été supprimées lors de la compilation d’origine.
De même, une seule erreur peut entraîner plusieurs erreurs. Essayez de mettre un point-virgule à la fin de la fonction principale d'un programme qui se compile et s'exécute correctement. Lorsque vous le recompilez, vous obtenez une énorme liste d'erreurs, et pourtant ce n'est qu'un point-virgule mal placé.
En plus des erreurs de syntaxe, les compilateurs peuvent également émettre des avertissements. Un avertissement n'est pas une erreur, mais il peut provoquer des problèmes lors de l'exécution du programme. Par exemple, l’attribution d’un nombre à virgule flottante double précision à un nombre à virgule flottante simple précision peut entraîner une perte de précision. Ce n’est pas une erreur de syntaxe, mais cela pourrait causer des problèmes. Dans cet exemple particulier, vous pouvez démontrer l’intention en convertissant la variable au type de données approprié.
Considérez l’exemple suivant où x est un nombre à virgule flottante simple précision et y est un nombre à virgule flottante double précision. y est explicitement converti en float lors de l'affectation, ce qui supprimerait tous les avertissements du compilateur.
x = (virgule flottante)y;
Erreurs logiques
Les erreurs logiques se produisent lorsqu’il y a une erreur dans la logique. Par exemple, vous pouvez tester qu'un nombre est inférieur à 4 et supérieur à 8. Cela ne sera peut-être jamais vrai, mais si la syntaxe est correcte, le programme sera compilé correctement. Considérez l’exemple suivant :
si (x < 4 && x > 8)
puts("Cela n'arrivera jamais !");
La syntaxe est correcte, donc le programme sera compilé, mais l'instruction puts ne s'imprimera jamais puisque la valeur de x ne peut pas être inférieure à quatre et supérieure à huit en même temps.
La plupart des erreurs logiques sont découvertes lors des tests initiaux du programme. Lorsque cela ne se comporte pas comme prévu, nous examinons de plus près les instructions logiques et les corrigeons. Ceci ne s’applique qu’aux erreurs logiques évidentes. Plus le programme est grand, plus il y a de chemins à l'intérieur, plus il devient difficile de vérifier que le programme se comporte comme prévu.
Procès
Dans le processus de développement logiciel, des erreurs peuvent être injectées à n’importe quelle étape du développement. Cela est dû au fait que les méthodes de vérification des phases précédentes du développement du logiciel sont manuelles. Ainsi, le code développé au cours de l’activité de codage est susceptible de contenir des erreurs d’exigences et des erreurs de conception, en plus des erreurs introduites au cours de l’activité de codage. Lors des tests, le programme testé est exécuté sur un ensemble de cas de test, et la sortie du programme pour les cas de test est évaluée pour déterminer si la programmation fonctionne comme prévu.
Ainsi, les tests sont le processus d’analyse d’un élément logiciel pour détecter la différence entre les conditions existantes et requises (par exemple, les bugs) et pour évaluer la fonctionnalité des éléments logiciels. Ainsi, les tests sont le processus d’analyse d’un programme dans le but de trouver des erreurs.
Quelques principes de test
- Les tests ne peuvent pas prouver l’absence de défauts, seulement leur présence.
- Plus une erreur est commise tôt, plus elle sera coûteuse.
- Plus une erreur est détectée tard, plus elle sera coûteuse.
Parlons maintenant de quelques techniques de test :
Tests en boîte blanche
Le test de boîte blanche est une technique dans laquelle tous les chemins à travers le programme sont testés avec toutes les valeurs possibles. Cette approche nécessite une certaine connaissance de la manière dont le programme doit se comporter. Par exemple, si votre programme accepte une valeur entière comprise entre 1 et 50, les tests en boîte blanche testeraient le programme avec les 50 valeurs pour s'assurer qu'elles sont correctes pour chacune d'elles, puis testeraient toutes les autres valeurs possibles qu'un entier peut prendre et vérifieraient qu'il se comporte comme prévu. Étant donné le nombre d’éléments de données qu’un programme typique peut avoir, les permutations possibles rendent les tests de boîte blanche extrêmement difficiles pour les grands programmes.
Les tests de boîte blanche peuvent être appliqués aux fonctions critiques pour la sécurité d'un grand programme, et une grande partie du reste est testée à l'aide de tests de boîte noire, décrits ci-dessous. En raison du nombre de permutations, les tests en boîte blanche sont généralement effectués à l'aide d'un harnais de test, où les plages de valeurs sont rapidement introduites dans le programme via un programme spécial, enregistrant les exceptions au comportement attendu. Le test de la boîte blanche est parfois appelé test structurel, transparent ou de la boîte ouverte.
Test de la boîte noire
Les tests de la boîte noire sont similaires aux tests de la boîte blanche, sauf qu'au lieu de tester toutes les valeurs possibles, les valeurs sélectionnées sont testées. Dans ce type de test, le testeur connaît les entrées et les résultats attendus, mais pas nécessairement comment le programme y est parvenu. Les tests de boîte noire sont parfois appelés tests fonctionnels.
Les cas de test pour les tests de boîte noire sont généralement développés peu de temps après l'achèvement de la spécification du programme. Les cas de test sont basés sur des classes d’équivalence.
Classes d'équivalence
Pour chaque entrée, une classe d'équivalence définit les états valides et non valides. Lors de la définition des classes d’équivalence, vous devez généralement prévoir trois scénarios.
Si les données d'entrée spécifient une plage ou une valeur spécifique, un état valide et deux états non valides seront définis. Par exemple, si un nombre doit être compris entre 1 et 20, l'état valide sera compris entre 1 et 20, il y aura un état invalide pour les valeurs inférieures à 1, et un état invalide pour les valeurs supérieures à 20.
Si les données d'entrée excluent une plage ou une valeur spécifique, deux états valides et un état non valide seront définis. Par exemple, si un nombre ne doit pas être compris entre 1 et 20, les états valides seront inférieurs à 1 et supérieurs à 20, tandis que les états non valides seront compris entre 1 et 20.
Si l'entrée spécifie une valeur booléenne, il n'y aura que deux états : un valide et un non valide.
Analyse des valeurs limites
L’analyse des valeurs limites considère uniquement les valeurs à la limite des données d’entrée. Par exemple, dans le cas d’un nombre de 1 à 20, les cas de test pourraient être 1, 20, 0 et 21. L’idée est que si le programme fonctionne comme prévu avec ces valeurs, d’autres valeurs fonctionneront également comme prévu.
Le tableau suivant fournit un aperçu des limites typiques que vous souhaiterez peut-être définir.
Intervalles de test |
Type d'entrée |
Valeurs de test |
Aligner |
- x[limite_inférieure]-1
- x[limite_inférieure]
- x[limite_supérieure]
- x[limite_supérieure]+1
|
Booléen |
|
Élaboration d'un plan de test
Définir les classes d’équivalence et déterminer les limites pour chaque classe. Après avoir défini les limites de la classe, écrivez une liste de valeurs acceptables et inacceptables à la limite et quel devrait être le comportement attendu. Le testeur peut ensuite exécuter le programme avec les valeurs limites et indiquer ce qui s'est passé lorsque la valeur limite a été testée par rapport au résultat requis.
Vous trouverez ci-dessous un plan de test typique utilisé pour valider les âges d’entrée, où les valeurs acceptables varient de 10 à 110.
Classe d'équivalence |
Valide |
Pas correct |
Entre 10 et 110 |
> 110 |
|
< 10 |
Après avoir déterminé notre classe d’équivalence, nous pouvons maintenant élaborer un plan de tests basé sur l’âge.
Plan de test |
Valeur |
État |
Résultat attendu |
Résultat réel |
10 |
Valide |
Continuez à courir pour obtenir le nom |
|
110 |
Valide |
Continuez à courir pour obtenir le nom |
|
9 |
Pas correct |
Demander à nouveau l'âge |
|
111 |
Pas correct |
Demander à nouveau l'âge |
|
La colonne « Résultat réel » est laissée vide car elle sera remplie pendant le test. Si le résultat est conforme aux attentes, la colonne sera vérifiée. Sinon, vous devriez poster un commentaire indiquant ce qui s’est passé.