Chapitre – 5
Introduction à la programmation C
Introduction
Le « C » est l'un des langages informatiques les plus populaires dans le monde informatique d'aujourd'hui. Le langage de programmation "C" a été conçu et développé par Brian Kernighan et Dennis Ritchie aux Bell Research Labs en 1972.
'C' est un langage spécialement créé pour permettre au programmeur d'accéder à presque tous les éléments internes de la machine - registres, emplacements d'E/S et adresses absolues. Dans le même temps, "C" permet autant de traitement de données et de modularisation de texte programmé que nécessaire pour permettre la construction de projets multi-programmeurs très complexes de manière organisée et en temps opportun.
Bien que ce langage ait été initialement prévu pour fonctionner sous UNIX, il y a eu un grand intérêt à l'exécuter sous le système d'exploitation MS-DOS sur IBM PC et compatibles. C'est un excellent langage pour cet environnement en raison de la simplicité d'expression, de la compacité du code et du large éventail 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 avec de nombreuses fonctionnalités adaptées à la plupart des tâches de programmation. Pourtant, il y a plusieurs raisons pour lesquelles C est le premier choix des programmeurs qui sont prêts à faire de la programmation pour la récupération de données, la programmation système, la programmation d'appareils ou la programmation matérielle :
- C est un langage populaire préféré par les programmeurs professionnels. En conséquence, une grande variété de compilateurs C et d'accessoires utiles sont disponibles.
- C est 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 modification. La portabilité est améliorée par la norme ANSI pour C, l'ensemble de règles pour les compilateurs C.
- Le C permet une large utilisation des modules dans la programmation. Le code C peut être écrit dans des routines appelées fonctions. Ces fonctions peuvent être réutilisées dans d'autres applications ou programmes. Vous n'avez pas besoin de faire des efforts supplémentaires dans la programmation d'une nouvelle application pour créer le même module que vous avez développé dans une autre programmation d'application auparavant.
Vous pouvez utiliser cette fonction dans un nouveau programme sans aucune modification ou quelques modifications mineures. En cas de programmation de récupération de données, vous trouverez cette qualité très utile lorsque vous avez besoin d'exécuter plusieurs fois les mêmes fonctions dans différentes applications de différents programmes.
- C est un langage puissant et flexible. C'est la raison pour laquelle C est utilisé pour des projets aussi divers que des systèmes d'exploitation, des traitements de texte, des graphiques, des feuilles de calcul et même des compilateurs pour d'autres langages.
- C est un langage de peu de mots, contenant seulement une poignée de termes, appelés mots-clés, qui servent de base sur laquelle la fonctionnalité du langage est construite. Ces mots-clés, également appelés mots réservés, le rendent plus puissant et donnent le large domaine de programmation et donnent au programmeur l'impression de faire n'importe quel type de programmation en C.
Let moi supposons que vous ne savez rien en C
Je suppose que vous ne connaissez rien à la programmation C et que vous n'avez aucune idée de la programmation. Je commencerai par les concepts les plus élémentaires du C et vous amènerai au niveau supérieur de la programmation en C, y compris les concepts généralement intimidants de pointeurs, de structures et d'allocation dynamique.
Pour bien comprendre ces concepts, il faudra un bon peu de temps et de travail de votre part car ils ne sont pas particulièrement faciles à appréhender, mais ce sont des outils très puissants.
La programmation en C est un atout considérable dans les domaines où vous devrez peut-être utiliser le langage d'assemblage, mais préférez en faire un programme simple à écrire et facile à entretenir. Le temps gagné dans le codage du C peut être énorme dans de tels cas.
Même si le langage C bénéficie d'un bon bilan lorsque les programmes sont transportés d'une implémentation à une autre, il existe des différences dans les compilateurs que vous trouverez chaque fois que vous essayez d'utiliser un autre compilateur.
La plupart des différences deviennent apparentes lorsque vous utilisez des extensions non standard telles que des appels au BIOS DOS lors de l'utilisation de MS-DOS, mais même ces différences peuvent être minimisées par un choix judicieux des constructions de programmation.
Lorsqu'il est devenu évident que le langage de programmation C devenait un langage très populaire disponible sur une large gamme d'ordinateurs, un groupe de personnes concernées s'est réuni pour proposer un ensemble standard de règles 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 avant-projets, ils ont finalement écrit une norme acceptable pour le langage C. Elle a été acceptée par l'American National Standards Institute (ANSI), et par l'Organisation internationale de normalisation (ISO).
Il n'est imposé à aucun groupe ou utilisateur, mais comme il est si largement accepté, ce serait un suicide économique pour tout compilateur de refuser de se conformer à la norme.
Les programmes écrits dans ce livre sont principalement destinés à être utilisés sur un IBM-PC ou un ordinateur compatible, mais peuvent être utilisés avec n'importe quel compilateur standard ANSI car il est si étroitement 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 nommer un identifiant. Un identificateur est utilisé pour toute variable, fonction, définition de données, etc. Dans le langage de programmation C, un identificateur 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. l'alphabet, n'importe quel chiffre ou le soulignement.
Deux règles doivent être gardées à l'esprit lors de la dénomination des identifiants.
- La casse des caractères alphabétiques est significative. C est 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 et seront considérés comme significatifs par un compilateur ANSI-C conforme. Si plus de 31 sont utilisés, tous les caractères au-delà du 31 peuvent être ignorés par un compilateur donné.
Mots clés
Il y a 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 comme une aide à la compilation du programme. Ils sont toujours écrits en minuscules. Une liste complète suit :
auto |
break |
case |
char |
const |
continue |
default |
do |
double |
else |
enum |
extern |
float |
for |
goto |
if |
int |
long |
register |
return |
short |
signed |
sizeof |
static |
struct |
switch |
typedef |
union |
unsigned |
void |
volatile |
while |
Ici, nous voyons la magie de C. La merveilleuse collection de seulement 32 mots-clés donne une large utilisation dans différentes applications. Tout programme informatique a deux entités à considérer, les données et le programme. Ils dépendent fortement les uns des autres et une planification minutieuse des deux conduit à un programme bien planifié et bien écrit.
Commençons par un simple programme en C :
/* First Program to learn C */
#include <stdio.h>
void main()
{
printf("This is a C program\n"); // printing a message
}
Bien que le programme soit très simple, quelques points méritent d'être notés. Examinons le programme ci-dessus. Tout ce qui se trouve entre /* et */ est considéré comme un commentaire et sera ignoré par le compilateur. Vous ne devez pas inclure de commentaires dans 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 ligne. En utilisant // nous pouvons ajouter une petite documentation dans 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 main 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>
main()
{
printf("This is a C program\n"); // printing a message
return 0;
}
Les deux programmes sont identiques et effectuent la même tâche. Le résultat des deux programmes imprimera la sortie suivante à l'écran :
Ceci est un programme en 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. Un tel regroupement est connu sous le nom d'instruction composée ou de bloc.
printf("Ceci est un programme C\n"); imprime les mots à l'écran. Le texte à imprimer est entouré de guillemets doubles. 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 l'affichage de 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 de préprocesseur qui seront discutées plus tard, ou entre guillemets comme parties de chaînes de caractères.
Compilation du programme
Laissez le nom de notre programme est CPROG.C. Pour saisir et compiler le programme C, procédez comme suit :
- Créez le répertoire actif de vos programmes C et démarrez votre éditeur. Pour cela, n'importe quel éditeur de texte peut être utilisé, mais la plupart des compilateurs C tels que Turbo C++ de Borland disposent d'un environnement de développement intégré (IDE) qui vous permet d'entrer, de compiler et de lier vos programmes dans un cadre pratique.
- Écrivez et enregistrez le code source. Vous devez nommer le fichier CPROG.C.
- Compiler et lier 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 pas eu d'erreurs ou d'avertissements.
- Vérifiez les messages du compilateur. Si vous ne recevez aucune erreur ou avertissement, tout devrait bien se passer. S'il y a une erreur dans la saisie du programme, le compilateur l'attrapera 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 une extension différente décrits comme suit :
- CPROG.C, le fichier de code source
- CPROG.BAK, le fichier de sauvegarde du fichier source que vous avez 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 exécuter CPROG.EXE, entrez simplement cprog. Le message Ceci est un programme C s'affiche à l'écran.
Examinons maintenant le programme suivant :
/* First Program to learn C */ // 1
// 2
#include <stdio.h> // 3
// 4
main() // 5
{
// 6
printf("This is a C program\n"); // 7
// 8
return 0; // 9
} // 10
Lorsque vous compilez ce programme, le compilateur affiche un message semblable au suivant :
cprog.c(8) : Erreur : ';' attendu
décomposons ce message d'erreur en plusieurs parties. cprog.c est le nom du fichier où l'erreur a été trouvée. (8) est le numéro de la ligne où l'erreur a été trouvée. Erreur : ';' attendu est une description de l'erreur.
Ce message est assez informatif et vous indique qu'à la ligne 8 de CPROG.C le compilateur s'attendait à trouver un point-virgule mais ne l'a pas fait. Cependant, vous savez que le point-virgule a en fait été omis à la ligne 7, il y a donc une différence.
Pourquoi le compilateur signale une erreur à la ligne 8 alors qu'en fait, un point-virgule a été omis à la ligne 7. La réponse réside dans le fait que C ne se soucie pas de choses comme les sauts entre les lignes. Le point-virgule qui appartient après l'instruction printf() aurait pu être placé sur la ligne suivante, mais 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 un certain nombre de possibilités de différents types d'erreurs. Discutons des messages d'erreur de liaison. Les erreurs de l'éditeur de liens 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 Erreur : symboles non définis : suivi du nom mal orthographié. Une fois que vous avez corrigé l'orthographe, le problème devrait disparaître.
Imprimer des numéros
Voyons l'exemple suivant :
// Comment imprimer les chiffres //
#include<stdio.h>
void main()
{
int num = 10;
printf(“ The Number Is %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 un d, qui signale à la routine de sortie d'obtenir une valeur décimale et de la sortir.
Utilisation de 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 au retour de cette fonction.
Pour utiliser des variables dans vos programmes C, vous devez connaître les règles suivantes lorsque vous donnez le nom aux variables en C :
- Le nom peut contenir des lettres, des chiffres et le caractère 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.
- 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 variable. 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 :
Variable Name |
Legal or Not |
Num |
Legal |
Ttpt2_t2p |
Legal |
Tt pt |
Illegal: Space is not allowed |
_1990_tax |
Legal but not advised |
Jack_phone# |
Illegal: Contains the illegal character # |
Case |
Illegal: Is a C keyword |
1book |
Illegal: First character is a digit |
La première nouveauté qui ressort est la première ligne du corps de main() :
nombre entier = 10 ;
Cette ligne définit une variable nommée 'num' de type int et l'initialise avec la valeur 10. Cela pourrait aussi avoir été écrit comme :
int num; /* define uninitialized variable 'num' */
/* and after all variable definitions: */
num = 10; /* assigns value 10 to variable 'num' */
Les variables peuvent être définies au début d'un bloc (entre les accolades {et}), généralement c'est au début d'un corps de fonction, mais cela peut aussi être au début d'un autre type de bloc.
Les variables définies au début d'un bloc ont par défaut le statut 'auto'. Cela signifie qu'ils n'existent que pendant l'exécution du bloc. Lorsque l'exécution de la fonction commence, les variables seront créées mais leur contenu sera indéfini. Au retour de la fonction, les variables seront détruites. La définition aurait pu aussi s'écrire :
numéro entier automatique = 10 ;
Puisque la définition avec ou sans le mot-clé auto est complètement équivalente, le mot-clé auto est évidemment plutôt redondant.
Cependant, parfois ce n'est pas ce que vous voulez. Supposons que vous vouliez qu'une fonction compte le nombre de fois qu'elle est appelée. Si la variable était détruite à chaque retour de la fonction, cela ne serait pas possible.
Il est donc possible de donner à la variable ce qu'on appelle une durée statique, c'est-à-dire qu'elle restera intacte pendant toute l'exécution du programme. Par exemple :
nombre entier statique = 10 ;
Cela initialise la variable num à 10 au début de l'exécution du programme. Dès lors, la valeur restera intacte ; la variable ne sera pas réinitialisée si la fonction est appelée plusieurs fois.
Parfois, il ne suffit pas que la variable soit accessible à partir d'une seule 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 du fichier source entier, cela peut également être fait avec le mot-clé static, mais en plaçant la définition en dehors de toutes les fonctions. Par exemple :
#include <stdio.h>
static int num = 10; /* will be accessible from entire source file */
int main(void)
{
printf("The Number Is: %d\n", num);
return 0;
}
Et il existe également des cas où une variable doit être accessible depuis l'ensemble du programme, qui peut être composé de plusieurs fichiers source. C'est ce qu'on appelle une variable globale et doit être évitée lorsqu'elle n'est pas requise.
Cela se fait également 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; /* will be accessible from entire program! */
int main(void)
{
printf("The Number Is: %d\n", num);
return 0;
}
Il y a aussi le mot-clé extern, qui est utilisé pour accéder aux variables globales dans d'autres modules. Il existe également quelques 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 volatil et registre. Le modificateur volatile oblige le compilateur à accéder à la variable à chaque fois qu'elle est lue. Il se peut qu'il n'optimise pas la variable en la mettant dans un registre ou autre. 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 les 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, donné à 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 placé sur deux lignes. Le mot-clé extern est utilisé dans les fonctions pour déclarer une variable externe statique qui est définie ailleurs.
Types de variables numériques
C fournit plusieurs types différents de variables numériques car différentes valeurs numériques ont des exigences de stockage en mémoire variables. Ces types numériques diffèrent par la facilité avec laquelle certaines opérations mathématiques peuvent être effectuées sur eux.
Les petits nombres entiers nécessitent moins de mémoire pour être stockés et votre ordinateur peut effectuer très rapidement des opérations mathématiques avec de tels nombres. Les grands nombres 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 vous assurez que votre programme s'exécute aussi efficacement que possible.
Les variables numériques de C appartiennent aux deux catégories principales suivantes :
- Variables entières
- Variables à virgule flottante
Dans chacune de ces catégories se trouvent au moins deux types de variables spécifiques. Le tableau ci-dessous indique la quantité de mémoire, en octets, nécessaire pour contenir une seule variable de chaque type.
Le type char peut être équivalent à char signé ou à 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 stocker des caractères ou leurs valeurs numériques correspondantes dans une variable, il n'y a donc pas non plus besoin d'une fonction pour convertir entre un caractère et sa valeur numérique ou vice versa. Pour les autres types d'entiers, si vous omettez signé ou non signé, la valeur par défaut sera signée, donc par ex. int et signé int sont équivalents.
Le type int doit être supérieur ou égal au type short et inférieur ou égal au type long. Si vous avez simplement besoin de stocker des valeurs qui ne sont pas très grandes, c'est souvent une bonne idée d'utiliser le type int ; c'est généralement la taille que le processeur peut gérer le plus facilement, et donc la plus rapide.
Avec plusieurs compilateurs double et long double sont équivalents. Cela, 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 permet de mieux décrire les types de variables :
Types à usage spécial couramment utilisés :
Variable Type |
Description |
size_t |
unsigned type used for storing the sizes of objects in bytes |
time_t |
used to store results of the time() function |
clock_t |
used to store results of the clock() function |
FILE |
used for accessing a stream (usually a file or device) |
ptrdiff_t |
signed type of the difference between 2 pointers |
div_t |
used to store results of the div() function |
ldiv_t |
used to store results of ldiv() function |
fpos_t |
used to hold file position information |
va_list |
used in variable argument handling |
wchar_t |
wide character type (used for extended character sets) |
sig_atomic_t |
used in signal handlers |
Jmp_buf |
used for non-local jumps |
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; /* simple integer type */
long int b; /* long integer type */
short int c; /* short integer type */
unsigned int d; /* unsigned integer type */
char e; /* character type */
float f; /* floating point type */
double g; /* double precision floating point */
a = 1023;
b = 2222;
c = 123;
d = 1234;
e = 'X';
f = 3.14159;
g = 3.1415926535898;
printf( "\nA char is %d bytes", sizeof( char ));
printf( "\nAn int is %d bytes", sizeof( int ));
printf( "\nA short is %d bytes", sizeof( short ));
printf( "\nA long is %d bytes", sizeof( long ));
printf( "\nAn unsigned char is %d bytes",
sizeof( unsigned char ));
printf( "\nAn unsigned int is %d bytes",
sizeof( unsigned int ));
printf( "\nAn unsigned short is %d bytes",
sizeof( unsigned short ));
printf( "\nAn unsigned long is %d bytes",
sizeof( unsigned long ));
printf( "\nA float is %d bytes", sizeof( float ));
printf( "\nA double is %d bytes\n", sizeof( double ));
printf("a = %d\n", a); /* decimal output */
printf("a = %o\n", a); /* octal output */
printf("a = %x\n", a); /* hexadecimal output */
printf("b = %ld\n", b); /* decimal long output */
printf("c = %d\n", c); /* decimal short output */
printf("d = %u\n", d); /* unsigned output */
printf("e = %c\n", e); /* character output */
printf("f = %f\n", f); /* floating output */
printf("g = %f\n", g); /* double float output */
printf("\n");
printf("a = %d\n", a); /* simple int output */
printf("a = %7d\n", a); /* use a field width of 7 */
printf("a = %-7d\n", a); /* left justify in
field of 7 */
c = 5;
d = 8;
printf("a = %*d\n", c, a); /* use a field width of 5*/
printf("a = %*d\n", d, a); /* use a field width of 8 */
printf("\n");
printf("f = %f\n", f); /* simple float output */
printf("f = %12f\n", f); /* use field width of 12 */
printf("f = %12.3f\n", f); /* use 3 decimal places */
printf("f = %12.5f\n", f); /* use 5 decimal places */
printf("f = %-12.5f\n", f); /* left justify in field */
return 0;
}
Le résultat du programme après l'exécution sera affiché comme :
A char is 1 bytes
An int is 2 bytes
A short is 2 bytes
A long is 4 bytes
An unsigned char is 1 bytes
An unsigned int is 2 bytes
An unsigned short is 2 bytes
An unsigned long is 4 bytes
A float is 4 bytes
A double is 8 bytes
a = 1023
a = 1777
a = 3ff
b = 2222
c = 123
d = 1234
e = X
f = 3.141590
g = 3.141593
a = 1023
a = 1023
a = 1023
a = 1023
a = 1023
f = 3.141590
f = 3.141590
f = 3.142
f = 3.14159
f = 3.14159 |
Avant son utilisation, une variable dans un programme C, 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 :
typename varname ;
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 des variables par des virgules :
int count, number, start; /* three integer variables */
float percent, total; /* two float variables */
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, la déclaration
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 :
nombre entier ;
Ainsi, typedef ne crée pas de 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 est chargé de réserver de l'espace de stockage pour la variable. Cependant, la valeur stockée dans cet espace, la valeur de la variable, n'est pas définie. Il peut s'agir de zéro ou d'un "déchet" aléatoire. évaluer. Avant d'utiliser une variable, vous devez toujours l'initialiser à une valeur connue. Prenons cet exemple :
int count; /* Set aside storage space for count */
count = 0; /* Store 0 in count */
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, faites suivre le nom de la variable dans l'instruction de déclaration d'un signe égal et de la valeur initiale souhaitée :
int count = 0;
double rate = 0.01, complexity = 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 amount = 100000;
unsigned int length = -2500;
Le compilateur C n'intercepte pas de telles erreurs. Votre programme peut être compilé et lié, mais vous pouvez 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 d'un disque //
#include<stdio.h>
#define SECTOR_PER_SIDE 63
#define SIDE_PER_CYLINDER 254
void main()
{
int cylinder=0;
clrscr();
printf("Enter The No. of Cylinders in the Disk \n\n\t");
scanf("%d",&cylinder); // Get the value from the user //
printf("\n\n\t Total Number of Sectors in the disk = %ld", (long)SECTOR_PER_SIDE*SIDE_PER_CYLINDER* cylinder);
getch();
}
La sortie du programme est la suivante :
Enter The No. of Cylinders in the Disk
1024
Total Number of Sectors in the disk = 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 des mots longs 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 valeurs ou plus, comme indiqué dans l'exemple.
La fonction getch () obtient essentiellement une entrée de caractère unique à partir du clavier. En tapant getch(); ici, nous arrêtons l'écran jusqu'à ce qu'une touche soit appuyée sur le clavier.
Les opérateurs
Un opérateur est un symbole qui demande à 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'assignation
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 algébriques mathématiques régulières. Si vous écrivez
x = y ;
Dans un programme C, cela ne signifie pas "x est égal à y". Au lieu de cela, cela signifie "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. Ainsi, le formulaire est le suivant :
variable = expression ;
Pendant 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 a deux opérateurs mathématiques unaires et cinq opérateurs mathématiques binaires. Les opérateurs mathématiques unaires sont ainsi nommés car ils prennent un seul opérande. C a 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 est d'ajouter ou de soustraire un à l'opérande. En d'autres termes, les instructions ++x; Andy; sont les équivalents de ces déclarations :
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 Modulus renvoie le reste lorsque le premier opérande est divisé par le deuxième opérande. Par exemple, 11 module 4 est égal à 3 (11 est divisé par 4, deux fois et il reste 3).
Opérateurs relationnels
Les opérateurs relationnels de C sont utilisés pour comparer des expressions. Une expression contenant un opérateur relationnel prend la valeur true (1) ou false (0). C a six opérateurs relationnels.
Opérateurs logiques
Les opérateurs logiques de C vous permettent de combiner deux ou plusieurs expressions relationnelles en une seule expression qui prend la valeur true ou false. Les opérateurs logiques prennent la valeur true ou false, selon la valeur true ou false de leurs opérandes.
Si x est une variable entière, les expressions utilisant des opérateurs logiques peuvent être écrites comme suit :
(x > 1) && (x < 5)
(x >= 2) && (x <= 4)
Operator |
Symbol |
Description |
Example |
Assignment operators |
equal |
= |
assign the value of y to x |
x = y |
Mathematical operators |
Increment |
++ |
Increments the operand by one |
++x, x++ |
Decrement |
-- |
Decrements the operand by one |
--x, x-- |
Addition |
+ |
Adds two operands |
x + y |
Subtraction |
- |
Subtracts the second operand from the first |
x - y |
Multiplication |
* |
Multiplies two operands |
x * y |
Division |
/ |
Divides the first operand by the second operand |
x / y |
Modulus |
% |
Gives the remainder when the first operand is divided by the second operand |
x % y |
Relational operators |
Equal |
= = |
Equality |
x = = y |
Greater than |
> |
Greater than |
x > y |
Less than |
< |
Less than |
x < y |
Greater than or equal to |
>= |
Greater than or equal to |
x >= y |
Less than or equal to |
<= |
Less than or equal to |
x <= y |
Not equal |
!= |
Not equal to |
x != y |
Logical operators |
AND |
&& |
True (1) only if both exp1 and exp2 are true; false (0) otherwise |
exp1 && exp2 |
OR |
|| |
True (1) if either exp1 or exp2 is true; false (0) only if both are false |
exp1 || exp2 |
NOT |
! |
False (0) if exp1 is true; true (1) if exp1 is false |
!exp1 |
Éléments à retenir concernant les expressions logiques
x * = y |
is same as |
x = x * y |
y - = z + 1 |
is same as |
y = y - z + 1 |
a / = b |
is same as |
a = a / b |
x + = y / 8 |
is same as |
x = x + y / 8 |
y % = 3 |
is same as |
y = y % 3 |
L'opérateur virgule
La virgule est fréquemment utilisée en C comme un 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 à la valeur de la bonne expression.
Par exemple, l'instruction suivante attribue la valeur de b à x, puis incrémente a, puis incrémente b :
x = (a++, b++);
Priorité des opérateurs C (Résumé des opérateurs C)
Rank and Associativity |
Operators |
1(left to right) |
() [] -> . |
2(right to left) |
! ~ ++ -- * (indirection) & (address-of) (type)
sizeof + (unary) - (unary) |
3(left to right) |
* (multiplication) / % |
4(left to right) |
+ - |
5(left to right) |
<< >> |
6(left to right) |
< <= > >= |
7(left to right) |
= = != |
8(left to right) |
& (bitwise AND) |
9(left to right) |
^ |
10(left to right) |
| |
11(left to right) |
&& |
12(left to right) |
|| |
13(right to left) |
?: |
14(right to left) |
= += -= *= /= %= &= ^= |= <<= >>= |
15(left to right) |
, |
() is the function operator; [] is the array operator. |
|
Prenons un exemple d'utilisation des opérateurs :
/* Utilisation des opérateurs */
int main()
{
int x = 0, y = 2, z = 1025;
float a = 0.0, b = 3.14159, c = -37.234;
/* incrementing */
x = x + 1; /* This increments x */
x++; /* This increments x */
++x; /* This increments x */
z = y++; /* z = 2, y = 3 */
z = ++y; /* z = 4, y = 4 */
/* decrementing */
y = y - 1; /* This decrements y */
y--; /* This decrements y */
--y; /* This decrements y */
y = 3;
z = y--; /* z = 3, y = 2 */
z = --y; /* z = 1, y = 1 */
/* arithmetic op */
a = a + 12; /* This adds 12 to a */
a += 12; /* This adds 12 more to a */
a *= 3.2; /* This multiplies a by 3.2 */
a -= b; /* This subtracts b from a */
a /= 10.0; /* This divides a by 10.0 */
/* conditional expression */
a = (b >= 3.0 ? 2.0 : 10.5 ); /* This expression */
if (b >= 3.0) /* And this expression */
a = 2.0; /* are identical, both */
else /* will cause the same */
a = 10.5; /* result. */
c = (a > b ? a : b); /* c will have the max of a or b */
c = (a > b ? b : a); /* c will have the min of a or b */
printf("x=%d, y=%d, z= %d\n", x, y, z);
printf("a=%f, b=%f, c= %f", a, b, c);
return 0;
}
et le résultat de ce programme sera affiché à l'écran comme :
x=3, y=1, z=1
a=2.000000, b=3.141590, c=2.000000
Quelque chose de plus sur printf() et Scanf()
Considérez les deux déclarations printf suivantes
printf(“\t %d\n”, num);
printf(“%5.2f”, fract);
dans la première instruction printf \t demande le déplacement de la tabulation à l'écran, l'argument %d indique au compilateur que la valeur de num doit être imprimée sous forme d'entier décimal. \n fait démarrer la nouvelle sortie à partir d'une nouvelle ligne.
Dans la deuxième instruction printf %5.2f indique au compilateur que la sortie doit être en virgule flottante, avec cinq chiffres en tout et deux chiffres à droite de la virgule décimale. Plus d'informations sur le caractère barre oblique inverse ont été présentées dans le tableau suivant :
Constant |
Meaning |
‘\a’ |
Audible alert (bell) |
‘\b’ |
Backspace |
‘\f’ |
Form feed |
‘\n’ |
New line |
‘\r’ |
Carriage return |
‘\t’ |
Horizontal tab |
‘\v’ |
Vertical tab |
‘\’’ |
Single quote |
‘\”’ |
Double quote |
‘\?’ |
Question mark |
‘\\’ |
Backslash |
‘\0’ |
Null |
Considérons 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 & Le symbole (esperluette) avant chaque nom de variable est un opérateur qui spécifie l'adresse du nom de la variable.
En faisant cela, l'exécution s'arrête et attend que la valeur de la variable num soit saisie. Lorsque la valeur entière est entrée et que la touche de retour 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 |
Reads... |
%c |
Single character |
%d |
Decimal integer |
%e |
Floating point value |
%f |
Floating point value |
%g |
Floating point value |
%h |
Short integer |
%i |
Decimal, hexadecimal or octal integer |
%o |
Octal integer |
%s |
String |
%u |
Unsigned decimal integer |
%x |
Hexadecimal integer |
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, où les 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 prend une décision sur ce qu'il faut faire ensuite.
Cette section discutera 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éter des sections importantes du programme.
- Sélection entre les sections facultatives d'un programme.
L'instruction if else
Ceci est utilisé pour décider s'il faut faire quelque chose à un point particulier, ou pour décider 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
if (result >= 45)
printf("Pass\n");
else
printf("Fail\n");
It is possible to use the if part without the else.
if (temperature < 0)
print("Frozen\n");
Chaque version consiste en un test, dans l'instruction entre crochets suivant le if. Si le test est vrai, l'instruction suivante est obéie. S'il est faux, l'instruction suivant le else est obéie si elle est présente. Après cela, le reste du programme continue normalement.
Si nous souhaitons avoir plus d'une instruction après le if ou le else, elles doivent être regroupées entre accolades. Un tel regroupement est appelé une instruction composée ou un bloc.
if (result >= 45)
{ printf("Passed\n");
printf("Congratulations\n");
}
else
{ printf("Failed\n");
printf("Better Luck Next Time\n");
}
Parfois, nous souhaitons prendre une décision multidirectionnelle basée sur plusieurs conditions. La manière la plus générale de procéder consiste à utiliser la variante else if de l'instruction if.
Cela fonctionne en cascade plusieurs comparaisons. Dès que l'un d'entre eux donne 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.
if (result <=100 && result >= 75)
printf("Passed: Grade A\n");
else if (result >= 60)
printf("Passed: Grade B\n");
else if (result >= 45)
printf("Passed: Grade C\n");
else
printf("Failed\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 else if, et seul le else final peut être omis.
Il appartient au programmeur de concevoir la structure correcte pour chaque problème de programmation. Pour mieux comprendre l'utilisation de if else, voyons l'exemple
#include <stdio.h>
int main()
{
int num;
for(num = 0 ; num < 10 ; num = num + 1)
{
if (num == 2)
printf("num is now equal to %d\n", num);
if (num < 5)
printf("num is now %d, which is less than 5\n", num);
else
printf("num is now %d, which is greater than 4\n", num);
} /* end of for loop */
return 0;
}
Résultat du programme
num is now 0, which is less than 5
num is now 1, which is less than 5
num is now equal to 2
num is now 2, which is less than 5
num is now 3, which is less than 5
num is now 4, which is less than 5
num is now 5, which is greater than 4
num is now 6, which is greater than 4
num is now 7, which is greater than 4
num is now 8, which is greater than 4
num is now 9, which is greater than 4
La déclaration switch
Il s'agit d'une autre forme de décision multidirectionnelle. 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 un type intégral. (entier, long, court ou char).
- Chaque valeur possible de la variable peut contrôler une seule branche. Une dernière branche fourre-tout par défaut peut éventuellement être utilisée pour piéger 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. Il est utile lorsque nous ne sommes concernés que par la mesure d'une quantité lorsqu'elle est assez petite.
estimate(number)
int number;
/* Estimate a number as none, one, two, several, many */
{ switch(number) {
case 0 :
printf("None\n");
break;
case 1 :
printf("One\n");
break;
case 2 :
printf("Two\n");
break;
case 3 :
case 4 :
case 5 :
printf("Several\n");
break;
default :
printf("Many\n");
break;
}
}
Chaque cas intéressant est répertorié avec une action correspondante. L'instruction break empêche toute autre instruction d'être exécutée en quittant le commutateur. Puisque le cas 3 et le cas 4 n'ont pas de rupture suivante, ils continuent à autoriser la même action pour plusieurs valeurs de nombre.
Les constructions if et switch permettent au programmeur de faire une sélection parmi un certain nombre d'actions possibles. Voyons un exemple :
#include <stdio.h>
int main()
{
int num;
for (num = 3 ; num < 13 ; num = num + 1)
{
switch (num)
{
case 3 :
printf("The value is three\n");
break;
case 4 :
printf("The value is four\n");
break;
case 5 :
case 6 :
case 7 :
case 8 :
printf("The value is between 5 and 8\n");
break;
case 11 :
printf("The value is eleven\n");
break;
default :
printf("It is one of the undefined values\n");
break;
} /* end of switch */
} /* end of for loop */
return 0;
}
La sortie du programme sera
The value is three
The value is four
The value is between 5 and 8
The value is between 5 and 8
The value is between 5 and 8
The value is between 5 and 8
It is one of the undefined values
It is one of the undefined values
The value is eleven
It is one of the undefined values
La déclaration de rupture
Nous avons déjà rencontré break dans la discussion de l'instruction switch. Il est utilisé pour sortir d'une boucle ou d'un switch, le contrôle passant à la première instruction au-delà de la boucle ou d'un switch.
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 pour sortir au milieu du corps de la boucle. Une rupture dans une boucle doit toujours être protégée dans une instruction if qui fournit le test pour contrôler la condition de sortie.
La déclaration continue
Ceci est similaire à break mais se rencontre moins fréquemment. Cela ne fonctionne que dans les 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, passez à l'instruction de test.
- Dans une boucle for, passez au test et effectuez l'itération.
Comme une pause, continue 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 and continue examinons le programme suivant :
#include <stdio.h>
int main()
{
int value;
for(value = 5 ; value < 15 ; value = value + 1)
{
if (value == 8)
break;
printf("In the break loop, value is now %d\n", value);
}
for(value = 5 ; value < 15 ; value = value + 1)
{
if (value == 8)
continue;
printf("In the continue loop, value is now %d\n", value);
}
return 0;
}
Le résultat du programme sera le suivant :
In the break loop, value is now 5
In the break loop, value is now 6
In the break loop, value is now 7
In the continue loop, value is now 5
In the continue loop, value is now 6
In the continue loop, value is now 7
In the continue loop, value is now 9
In the continue loop, value is now 10
In the continue loop, value is now 11
In the continue loop, value is now 12
In the continue loop, value is now 13
In the continue loop, value is now 14
Boucles
L'autre type principal d'instruction de contrôle est la boucle. Les boucles permettent de répéter une instruction ou un bloc d'instructions. Les ordinateurs sont très bons pour répéter plusieurs fois des tâches simples. La boucle est le moyen utilisé par C pour y parvenir.
C vous donne le choix entre trois types de boucles, 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.
- Les boucles do while sont similaires, 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 là où la boucle sera 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 du haut se révèle faux. A titre d'exemple, voici une fonction pour retourner la longueur d'une chaîne. N'oubliez pas que la chaîne est représentée sous la forme d'un tableau de caractères terminé par un caractère nul '\0'.
int string_length(char string[])
{ int i = 0;
while (string[i] != '\0')
i++;
return(i);
}
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 regarder les caractères de la chaîne un par un jusqu'à ce que le caractère nul soit trouvé. Ensuite, la boucle est quittée et l'index de la valeur nulle 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 pour la boucle while :
#include <stdio.h>
int main()
{
int count;
count = 0;
while (count < 6)
{
printf("The value of count is %d\n", count);
count = count + 1;
}
return 0;
}
et le résultat s'affiche comme suit :
The value of count is 0
The value of count is 1
The value of count is 2
The value of count is 3
The value of count is 4
The value of count is 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 est exécutée 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 effectue une boucle pour lire à nouveau si elles étaient inacceptables.
do
{
printf("Enter 1 for yes, 0 for no :");
scanf("%d", &input_value);
} while (input_value != 1 && input_value != 0)
Pour mieux comprendre la boucle do while, voyons l'exemple suivant :
#include <stdio.h>
int main()
{
int i;
i = 0;
do
{
printf("The value of i is now %d\n", i);
i = i + 1;
} while (i < 5);
return 0;
}
Le résultat du programme s'affiche comme suit :
The value of i is now 0
The value of i is now 1
The value of i is now 2
The value of i is now 3
The value of i is now 4
Tlui pour Loop
La boucle for fonctionne bien lorsque le nombre d'itérations de la boucle est connu avant que la boucle ne soit entrée. La tête de la boucle se compose de trois parties séparées par des points-virgules.
- Le premier est exécuté avant l'entrée dans la boucle. Il s'agit généralement de l'initialisation de la variable de boucle.
- Le second est un test, la boucle est quittée lorsque cela 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'un incrément du compteur de boucle.
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 average(float array[], int count)
{
float total = 0.0;
int i;
for(i = 0; i < count; i++)
total += array[i];
return(total / count);
}
La boucle for garantit que le nombre correct d'éléments de tableau est additionné avant de calculer la moyenne.
Les trois instructions en tête d'une boucle for ne font généralement qu'une seule chose chacune, mais chacune d'entre elles peut être laissée vide. Une première ou une dernière instruction vide signifie qu'il n'y a pas d'initialisation ou d'incrément 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 d'autres moyens. Il peut s'agir d'une instruction return ou break.
Il est également possible de presser plusieurs déclarations 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 ci-dessous illustre la définition d'une telle boucle, avec des variables hi et lo commençant respectivement à 100 et 0 et convergeant.
La boucle for donne une variété de raccourcis à utiliser. Faites attention à l'expression suivante, dans cette expression, la boucle unique contient deux boucles for. Ici hi-- est identique à hi = hi - 1 et lo++ est identique à lo = lo + 1,
for(hi = 100, lo = 0; hi >= lo; hi--, lo++)
La boucle for est extrêmement flexible et permet de spécifier simplement et rapidement de nombreux types de comportement de programme. Voyons un exemple de boucle for
#include <stdio.h>
int main()
{
int index;
for(index = 0 ; index < 6 ; index = index + 1)
printf("The value of the index is %d\n", index);
return 0;
}
Le résultat du programme est affiché comme suit :
The value of the index is 0
The value of the index is 1
The value of the index is 2
The value of the index is 3
The value of the index is 4
The value of the index is 5
La déclaration goto
C a une instruction goto qui permet d'effectuer des sauts non structurés. Pour utiliser une instruction goto, vous utilisez simplement le mot réservé goto suivi du nom symbolique auquel vous souhaitez accéder. Le nom est alors placé 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 vraiment un gâchis mais c'est un bon exemple de la raison pour laquelle les auteurs de logiciels essaient d'éliminer autant que possible l'utilisation de l'instruction goto. Le seul endroit dans ce programme où il est raisonnable d'utiliser le goto est celui où le programme saute des trois boucles imbriquées en un seul saut. Dans ce cas, il serait plutôt compliqué de configurer une variable et de sauter successivement hors de chacune des trois boucles imbriquées, mais une instruction goto vous fait sortir des trois de manière très concise.
Certaines personnes disent que l'instruction goto ne doit en aucun cas être utilisée, mais c'est une pensée étroite. S'il y a un endroit où un goto fera clairement un flux de contrôle plus net qu'une autre construction, n'hésitez pas à l'utiliser, cependant, comme c'est le cas dans le reste du programme sur votre moniteur. Voyons l'exemple :
#include <stdio.h>
int main()
{
int dog, cat, pig;
goto real_start;
some_where:
printf("This is another line of the mess.\n");
goto stop_it;
/* the following section is the only section with a useable goto */
real_start:
for(dog = 1 ; dog < 6 ; dog = dog + 1)
{
for(cat = 1 ; cat < 6 ; cat = cat + 1)
{
for(pig = 1 ; pig < 4 ; pig = pig + 1)
{
printf("Dog = %d Cat = %d Pig = %d\n", dog, cat, pig);
if ((dog + cat + pig) > 8 ) goto enough;
}
}
}
enough: printf("Those are enough animals for now.\n");
/* this is the end of the section with a useable goto statement */
printf("\nThis is the first line of the code.\n");
goto there;
where:
printf("This is the third line of the code.\n");
goto some_where;
there:
printf("This is the second line of the code.\n");
goto where;
stop_it:
printf("This is the last line of this mess.\n");
return 0;
}
Laissez-nous voir les résultats affichés
Dog = 1 Cat = 1 Pig = 1
Dog = 1 Cat = 1 Pig = 2
Dog = 1 Cat = 1 Pig = 3
Dog = 1 Cat = 2 Pig = 1
Dog = 1 Cat = 2 Pig = 2
Dog = 1 Cat = 2 Pig = 3
Dog = 1 Cat = 3 Pig = 1
Dog = 1 Cat = 3 Pig = 2
Dog = 1 Cat = 3 Pig = 3
Dog = 1 Cat = 4 Pig = 1
Dog = 1 Cat = 4 Pig = 2
Dog = 1 Cat = 4 Pig = 3
Dog = 1 Cat = 5 Pig = 1
Dog = 1 Cat = 5 Pig = 2
Dog = 1 Cat = 5 Pig = 3
Those are enough animals for now.
This is the first line of the code.
This is the second line of the code.
This is the third line of the code.
This is another line of the mess.
This is the last line of this mess.
Pointeurs
Parfois, nous voulons savoir où une variable réside 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.
int num; /* Normal integer variable */
int *numPtr; /* Pointer to an integer variable */
L'exemple suivant imprime la valeur de la variable et l'adresse en 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 donné ci-après :
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 données ci-dessous demandent au compilateur de réserver 4 octets de mémoire sur un ordinateur 32 bits pour la variable à virgule flottante x, puis d'y mettre la valeur 6,5.
float x;
x = 6.5;
Comme l'emplacement de l'adresse en mémoire de toute variable est obtenu en plaçant l'opérateur & devant son nom donc &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. Nous pouvons plutôt dire que le pointeur pointe vers une autre variable. Par exemple :
float x;
float* 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 déclarations suivantes :
int var_x;
int* ptrX;
var_x = 6;
ptrX = &var_x;
*ptrX = 12;
printf("value of x : %d", var_x);
La première ligne force le compilateur à réserver un 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'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. Ensuite, vous pouvez 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 of pointer use */
#include <stdio.h>
int main()
{
int index, *pt1, *pt2;
index = 39; /* any numerical value */
pt1 = &index; /* the address of index */
pt2 = pt1;
printf("The value is %d %d %d\n", index, *pt1, *pt2);
*pt1 = 13; /* this changes the value of index */
printf("The value is %d %d %d\n", index, *pt1, *pt2);
return 0;
}
La sortie du programme sera affichée comme suit :
The value is 39 39 39
The value is 13 13 13
Voyons un autre exemple pour mieux comprendre l'utilisation des pointeurs :
#include <stdio.h>
#include <string.h>
int main()
{
char strg[40], *there, one, two;
int *pt, list[100], index;
strcpy(strg, "This is a character string.");
/* the function strcpy() is to copy one string to another. we’ll read about strcpy() function in String Section later */
one = strg[0]; /* one and two are identical */
two = *strg;
printf("The first output is %c %c\n", one, two);
one = strg[8]; /* one and two are identical */
two = *(strg+8);
printf("The second output is %c %c\n", one, two);
there = strg+10; /* strg+10 is identical to &strg[10] */
printf("The third output is %c\n", strg[10]);
printf("The fourth output is %c\n", *there);
for (index = 0 ; index < 100 ; index++)
list[index] = index + 100;
pt = list + 27;
printf("The fifth output is %d\n", list[27]);
printf("The sixth output is %d\n", *pt);
return 0;
}
La sortie du programme ressemblera à ceci :
The first output is T T
The second output is a a
The third output is c
The fourth output is c
The fifth output is 127
The sixth output is 127
Tableaux
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 qui sont déclarés comme ceci
résultats int[20] ;
Les tableaux peuvent avoir plus de dimensions, auquel cas ils peuvent être déclarés comme
int results_2d[20][5];
int results_3d[20][5][3];
Chaque index a son propre jeu de crochets. Un tableau est déclaré dans la fonction principale, a généralement des détails de dimensions inclus. Il est possible d'utiliser un autre type appelé pointeur à la place d'un tableau. Cela signifie que les dimensions ne sont pas fixées 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 pour additionner tous les nombres entiers dans un tableau unidimensionnel.
int add_array(int array[], int size)
{
int i;
int total = 0;
for(i = 0; i < size; i++)
total += array[i];
return(total);
}
Le programme donné ensuite créera une chaîne, accédera à certaines données qu'elle contient, l'imprimera. Accédez-y à nouveau à l'aide de pointeurs, puis imprimez la chaîne. Il devrait imprimer "Salut !" et "012345678" sur différentes lignes. Voyons le codage du programme :
#include <stdio.h>
#define STR_LENGTH 10
void main()
{
char Str[STR_LENGTH];
char* pStr;
int i;
Str[0] = 'H';
Str[1] = 'i';
Str[2] = '!';
Str[3] = '\0'; // special end string character NULL
printf("The string in Str is : %s\n", Str);
pStr = &Str[0];
for (i = 0; i < STR_LENGTH; i++)
{
*pStr = '0'+i;
pStr++;
}
Str[STR_LENGTH-1] = '\0';
printf("The string in Str is : %s\n", Str);
}
[] (accolades) sont utilisés pour déclarer le tableau. La ligne du programme char Str[STR_LENGTH]; déclare un tableau de dix caractères. Ce sont dix personnages individuels, qui sont tous rassemblés en mémoire au même endroit. Ils sont tous accessibles via notre nom de variable Str avec un [n] où n est le numéro de l'élément.
Il faut toujours garder à l'esprit quand on parle de tableau que lorsque C déclare un tableau de dix, les éléments auxquels on peut accéder sont numérotés de 0 à 9. Accéder au premier élément correspond à accéder au 0ème élément. Ainsi, dans le cas des tableaux, comptez toujours de 0 à la taille du tableau - 1.
Ensuite, notez que nous mettons les lettres "Salut !" dans le tableau, mais ensuite nous mettons 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'. Si ce n'est pas le cas, et que quelqu'un appelle printf sur la chaîne, alors printf commencerait à l'emplacement mémoire de votre chaîne et continuerait à imprimer en disant qu'il rencontre '\ 0' et donc vous vous retrouverez avec un tas d'ordures à la fin de votre chaîne. Assurez-vous donc de bien terminer vos chaînes.
Tableaux de caractères
Une constante de chaîne, telle que
"Je suis une chaîne"
est un tableau de caractères. Il est représenté en interne en C par les caractères ASCII dans la chaîne, c'est-à-dire "I", vide, "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 intelligible à l'aide de printf :
printf("Hello, world\n");
printf("The value of a is: %f\n", a);
Les constantes de chaîne peuvent être associées à des variables. C fournit la variable de type 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 type caractère, un caractère ASCII par emplacement.
N'oubliez jamais que, puisque les chaînes se terminent classiquement par le caractère nul "\0", nous avons besoin d'un emplacement de stockage supplémentaire dans le tableau.
C ne fournit aucun opérateur qui manipule 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 facile puisque le nom d'un tableau est juste un pointeur vers son premier élément. Considérez le programme ci-dessous :
#include<stdio.h>
void main()
{
char text_1[100], text_2[100], text_3[100];
char *ta, *tb;
int i;
/* set message to be an arrray */
/* of characters; initialize it */
/* to the constant string "..." */
/* let the compiler decide on */
/* its size by using [] */
char message[] = "Hello, I am a string; what are
you?";
printf("Original message: %s\n", message);
/* copy the message to text_1 */
i=0;
while ( (text_1[i] = message[i]) != '\0' )
i++;
printf("Text_1: %s\n", text_1);
/* use explicit pointer arithmetic */
ta=message;
tb=text_2;
while ( ( *tb++ = *ta++ ) != '\0' )
;
printf("Text_2: %s\n", text_2);
}
Le résultat du programme sera le suivant :
Original message: Hello, I am a string; what are you?
Text_1: Hello, I am a string; what are you?
Text_2: Hello, I am a string; what are you?
La bibliothèque standard de "chaînes" contient de nombreuses fonctions utiles pour manipuler les chaînes, que nous apprendrons plus tard dans la section sur les chaînes.
Accéder aux éléments
Pour accéder à un élément individuel 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 affecte 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. Comme 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 multiplication par trois.
int x[10] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30} ;
Cela évite d'affecter les valeurs individuellement comme dans l'exemple suivant.
int 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;
Boucler dans un tableau
Comme 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()
{
int x[10];
int counter;
/* Randomise the random number generator */
srand((unsigned)time(NULL));
/* Assign random values to the variable */
for (counter=0; counter<10; counter++)
x[counter] = rand();
/* Display the contents of the array */
for (counter=0; counter<10; counter++)
printf("element %d has the value %d\n", counter, x[counter]);
return 0;
}
bien que la sortie imprimera les différentes valeurs à chaque fois, le résultat sera affiché quelque chose comme ceci :
element 0 has the value 17132
element 1 has the value 24904
element 2 has the value 13466
element 3 has the value 3147
element 4 has the value 22006
element 5 has the value 10397
element 6 has the value 28114
element 7 has the value 19817
element 8 has the value 27430
element 9 has the value 22136
Tableaux multidimensionnels
Un tableau peut avoir plusieurs dimensions. Le fait de 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 à deux dimensions ; un tableau pour les lignes et un tableau pour les colonnes.
L'exemple suivant utilise un tableau à deux dimensions avec deux lignes contenant chacune cinq colonnes :
#include <stdio.h>
int main()
{
/* Declare a 2 x 5 multidimensional array */
int x[2][5] = { {1, 2, 3, 4, 5},
{2, 4, 6, 8, 10} };
int row, column;
/* Display the rows */
for (row=0; row<2; row++)
{
/* Display the columns */
for (column=0; column<5; column++)
printf("%d\t", x[row][column]);
putchar('\n');
}
return 0;
}
La sortie de ce programme sera affichée comme suit :
1 2 3 4 5
2 4 6 8 10
Chaînes
Une chaîne est un groupe de caractères, généralement des lettres de l'alphabet, afin de formater votre affichage d'impression de manière à ce qu'il soit beau, qu'il ait des noms et des titres significatifs et qu'il soit esthétique pour vous et les personnes qui utilisent le sortie de votre programme.
En fait, vous avez déjà utilisé des chaînes dans les exemples des rubriques précédentes. Mais ce n'est pas l'introduction complète des cordes. Il existe de nombreux cas possibles dans la programmation, où l'utilisation de chaînes formatées aide le programmeur à éviter les trop nombreuses complications du programme et bien sûr trop de bugs.
Une définition complète d'une chaîne est une série de données de type caractère terminée par un caractère nul ('\0').
Lorsque C va utiliser une chaîne de données d'une manière ou d'une autre, soit pour la comparer à une autre chaîne, la sortir, la copier dans une autre chaîne, ou quoi que ce soit, les fonctions sont configurées pour faire ce pour quoi elles sont appelées jusqu'à ce qu'un null soit détecté.
Il n'y a pas de type de données de base pour une chaîne en C à la place ; 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 à l'écran, saisie par l'utilisateur :
#include <stdio.h>
int main()
{
char name[80]; /* Create a character array
called name */
printf("Enter your name: ");
gets(name);
printf("The name you entered was %s\n", name);
return 0;
}
L'exécution du programme sera :
Enter your name: Tarun Tyagi
The name you entered was Tarun Tyagi
Quelques fonctions de chaîne courantes
La bibliothèque standard string.h contient de nombreuses fonctions utiles pour manipuler les chaînes. Certaines des fonctions 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 l'utilisation de strlen avec l'exemple :
#include <stdio.h>
#include <string.h>
int main()
{
char name[80];
int length;
printf("Enter your name: ");
gets(name);
length = strlen(name);
printf("Your name has %d characters\n", length);
return 0;
}
Et l'exécution du programme sera la suivante :
Enter your name: Tarun Subhash Tyagi
Your name has 19 characters
Enter your name: Preeti Tarun
Your name has 12 characters
La fonction strcpy
La fonction strcpy est utilisée pour copier une chaîne dans une autre. Apprenons l'utilisation de cette fonction avec l'exemple :
#include <stdio.h>
#include <string.h>
int main()
{
char first[80];
char second[80];
printf("Enter first string: ");
gets(first);
printf("Enter second string: ");
gets(second);
printf("first: %s, and second: %s Before strcpy()\n "
, first, second);
strcpy(second, first);
printf("first: %s, and second: %s After strcpy()\n",
first, second);
return 0;
}
et la sortie du programme sera :
Enter first string: Tarun
Enter second string: Tyagi
first: Tarun, and second: Tyagi Before strcpy()
first: Tarun, and second: Tarun After strcpy()
La fonction strcmp
La fonction strcmp est utilisée pour comparer deux chaînes ensemble. Le nom de la variable d'un tableau pointe vers l'adresse de base de ce tableau. Par conséquent, si nous essayons de comparer deux chaînes en utilisant ce qui suit, nous comparerions deux adresses, qui ne seraient évidemment jamais identiques car il n'est pas possible de stocker deux valeurs au même emplacement.
if (first == second) /* Cela ne peut jamais être fait pour comparer des chaînes */
L'exemple suivant utilise la fonction strcmp pour comparer deux chaînes :
#include <string.h>
int main()
{
char first[80], second[80];
int t;
for(t=1;t<=2;t++)
{
printf("\nEnter a string: ");
gets(first);
printf("Enter another string: ");
gets(second);
if (strcmp(first, second) == 0)
puts("The two strings are equal");
else
puts("The two strings are not equal");
}
return 0;
}
Et l'exécution du programme sera la suivante :
Enter a string: Tarun
Enter another string: tarun
The two strings are not equal
Enter a string: Tarun
Enter another string: Tarun
The two strings are equal
La fonction strcat
La fonction strcat est utilisée pour joindre une chaîne à une autre. Voyons comment ? A l'aide de l'exemple :
#include <string.h>
int main()
{
char first[80], second[80];
printf("Enter a string: ");
gets(first);
printf("Enter another string: ");
gets(second);
strcat(first, second);
printf("The two strings joined together: %s\n",
first);
return 0;
}
Et l'exécution du programme sera la suivante :
Enter a string: Data
Enter another string: Recovery
The two strings joined together: DataRecovery
La fonction strtok
La fonction strtok est utilisée pour trouver le jeton suivant 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 du retour à la ligne. Chaque mot est alors affiché sur une ligne distincte :
#include <stdio.h>
#include <string.h>
int main()
{
FILE *in;
char line[80];
char *delimiters = " \t\n";
char *token;
if ((in = fopen("C:\\text.txt", "r")) == NULL)
{
puts("Unable to open the input file");
return 0;
}
/* Read each line one at a time */
while(!feof(in))
{
/* Get one line */
fgets(line, 80, in);
if (!feof(in))
{
/* Break the line up into words */
token = strtok(line, delimiters);
while (token != NULL)
{
puts(token);
/* Get the next word */
token = strtok(NULL, delimiters);
}
}
}
fclose(in);
return 0;
}
Le programme ci-dessus, in = fopen("C:\\text.txt", "r"), ouvre le fichier existant C:\\text.txt. Si le n'existe pas dans le chemin spécifié ou pour une raison quelconque, le fichier n'a pas pu être ouvert, un message d'erreur s'affiche à l'écran.
Prenez l'exemple suivant, qui utilise certaines de ces fonctions :
#include <stdio.h>
#include <string.h>
void main()
{
char line[100], *sub_text;
/* initialize string */
strcpy(line,"hello, I am a string;");
printf("Line: %s\n", line);
/* add to end of string */
strcat(line," what are you?");
printf("Line: %s\n", line);
/* find length of string */
/* strlen brings back */
/* length as type size_t */
printf("Length of line: %d\n", (int)strlen(line));
/* find occurence of substrings */
if ( (sub_text = strchr ( line, 'W' ) )!= NULL )
printf("String starting with \"W\" ->%s\n",
sub_text);
if ( ( sub_text = strchr ( line, 'w' ) )!= NULL )
printf("String starting with \"w\" ->%s\n",
sub_text);
if ( ( sub_text = strchr ( sub_text, 'u' ) )!= NULL )
printf("String starting with \"w\" ->%s\n",
sub_text);
}
La sortie du programme sera affichée comme suit :
Line: hello, I am a string;
Line: hello, I am a string; what are you?
Length of line: 35
String starting with "w" ->what are you?
String starting with "w" ->u?
Fonctions
La meilleure façon de développer et de maintenir un grand programme est de le construire à partir de petits morceaux dont chacun est 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 permettent de diviser des programmes complexes en petits blocs, dont chacun est plus facile à écrire, à lire et à entretenir. Nous avons déjà rencontré la fonction main 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 :
return-type function-name ( argument list if necessary )
{
local-declarations;
statements ;
return return-value;
}
Si return-type est omis, C par défaut est int. La valeur de retour doit être du type déclaré. Toutes les variables déclarées dans les fonctions sont appelées variables locales, en ce sens qu'elles ne sont connues que dans la fonction pour laquelle elles ont été définies.
Certaines fonctions ont 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, en ce sens qu'ils ne sont pas disponibles en dehors de la fonction. Les programmes couverts jusqu'ici ont tous main, qui est une fonction.
Une fonction peut simplement effectuer une tâche sans renvoyer de valeur, auquel cas elle a la disposition suivante :
void function-name ( argument list if necessary )
{
local-declarations ;
statements;
}
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. Toute modification apportée aux arguments en interne dans la fonction est effectuée uniquement sur les copies locales des arguments.
Afin de modifier ou de définir un argument dans la liste des arguments, cet argument doit être passé en tant qu'adresse. Vous utilisez des variables régulières 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 des exemples :
#include <stdio.h>
void exchange ( int *a, int *b )
{
int temp;
temp = *a;
*a = *b;
*b = temp;
printf(" From function exchange: ");
printf("a = %d, b = %d\n", *a, *b);
}
void main()
{
int a, b;
a = 5;
b = 7;
printf("From main: a = %d, b = %d\n", a, b);
exchange(&a, &b);
printf("Back in main: ");
printf("a = %d, b = %d\n", a, b);
}
Et la sortie de ce programme sera affichée comme suit :
From main: a = 5, b = 7
From function exchange: a = 7, b = 5
Back in main: a = 7, b = 5
Let us see another example. The following example uses a function called square which writes the square of the numbers between 1 and 10.
#include <stdio.h>
int square(int x); /* Function prototype */
int main()
{
int counter;
for (counter=1; counter<=10; counter++)
printf("Square of %d is %d\n", counter, square(counter));
return 0;
}
/* Define the function 'square' */
int square(int x)
{
return x * x;
}
La sortie de ce programme sera affichée comme suit :
Square of 1 is 1
Square of 2 is 4
Square of 3 is 9
Square of 4 is 16
Square of 5 is 25
Square of 6 is 36
Square of 7 is 49
Square of 8 is 64
Square of 9 is 81
Square of 10 is 100
Le prototype de fonction carré 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 capable de vérifier l'appel de fonction par rapport à la définition de la fonction.
Lorsque le programme atteint la ligne qui appelle le carré de fonction, le programme saute à 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 la fonction peuvent être Pass By Value ou Pass By Reference.
Une fonction récursive est une fonction qui s'appelle elle-même. Et ce processus s'appelle la récursivité.
Fonctions de passage par valeur
Les paramètres de la fonction square de l'exemple précédent sont passés par valeur. Cela signifie que seule une copie de la variable a été transmise à la fonction. Toute modification de la valeur ne sera pas répercutée sur 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 nulle car il n'y a pas de type de retour.
#include <stdio.h>
void count_down(int x);
int main()
{
int counter;
for (counter=1; counter<=10; counter++)
count_down(counter);
return 0;
}
void count_down(int x)
{
int counter;
for (counter = x; counter > 0; counter--)
{
printf("%d ", x);
x--;
}
putchar('\n');
}
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 passage en C par valeur pour mieux le comprendre. L'exemple suivant convertit un nombre entre 1 et 30 000 tapé 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, residue;
do
{
printf("Enter a number between 1 and 30,000: ");
scanf("%d", &num);
} while (num < 1 || num > 30000);
residue = num;
printf("%d in words = ", num);
do_tens(residue/1000);
if (num >= 1000)
printf("thousand ");
residue %= 1000;
do_units(residue/100);
if (residue >= 100)
{
printf("hundred ");
}
if (num > 100 && num%100 > 0)
printf("and ");
residue %=100;
do_tens(residue);
putchar('\n');
return 0;
}
void do_units(int num)
{
switch(num)
{
case 1:
printf("one ");
break;
case 2:
printf("two ");
break;
case 3:
printf("three ");
break;
case 4:
printf("four ");
break;
case 5:
printf("five ");
break;
case 6:
printf("six ");
break;
case 7:
printf("seven ");
break;
case 8:
printf("eight ");
break;
case 9:
printf("nine ");
}
}
void do_tens(int num)
{
switch(num/10)
{
case 1:
do_teens(num);
break;
case 2:
printf("twenty ");
break;
case 3:
printf("thirty ");
break;
case 4:
printf("forty ");
break;
case 5:
printf("fifty ");
break;
case 6:
printf("sixty ");
break;
case 7:
printf("seventy ");
break;
case 8:
printf("eighty ");
break;
case 9:
printf("ninety ");
}
if (num/10 != 1)
do_units(num%10);
}
void do_teens(int num)
{
switch(num)
{
case 10:
printf("ten ");
break;
case 11:
printf("eleven ");
break;
case 12:
printf("twelve ");
break;
case 13:
printf("thirteen ");
break;
case 14:
printf("fourteen ");
break;
case 15:
printf("fifteen ");
break;
case 16:
printf("sixteen ");
break;
case 17:
printf("seventeen ");
break;
case 18:
printf("eighteen ");
break;
case 19:
printf("nineteen ");
}
}
et le résultat du programme sera le suivant :
Enter a number between 1 and 30,000: 12345
12345 in words = twelve thousand three hundred and forty five
Appel par référence
Pour qu'une fonction soit appelée par référence, au lieu de transmettre la variable elle-même, transmettez l'adresse de la variable. L'adresse de la variable peut être prise en utilisant le & opérateur. Ce qui suit appelle une fonction d'échange en transmettant 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 swap a reçu l'adresse plutôt que la variable, nous devons donc déréférencer les variables afin que nous examinions les valeurs réelles plutôt que les adresses des variables afin de permuter eux.
Le déréférencement est réalisé en C en utilisant la notation pointeur (*). En termes simples, cela signifie placer un * avant chaque variable avant de l'utiliser afin qu'il se réfère à 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>
void swap(int *x, int *y);
int main()
{
int x=6, y=10;
printf("Before the function swap, x = %d and y =
%d\n\n", x, y);
swap(&x, &y);
printf("After the function swap, x = %d and y =
%d\n\n", x, y);
return 0;
}
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
Voyons la sortie du programme :
Before the function swap, x = 6 and y = 10
After the function swap, x = 10 and 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 souvenir de 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 placer plus de données.
L'exemple suivant calcule la factorielle d'un nombre à l'aide de la récursivité. Une factorielle est un nombre multiplié par tous les autres entiers en dessous de lui-même, 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. On peut voir dans l'exemple ci-dessus que la factorielle 6 = 6 * la factorielle 5. De même, la factorielle 5 = 5 * la factorielle 4, et ainsi de suite.
Voici la règle générale pour le calcul des nombres factoriels.
factoriel(n) = n * factoriel(n-1)
La règle ci-dessus se termine lorsque n = 1, car la factorielle de 1 est 1. Essayons de mieux la comprendre à l'aide d'un exemple :
#include <stdio.h>
long int factorial(int num);
int main()
{
int num;
long int f;
printf("Enter a number: ");
scanf("%d", &num);
f = factorial(num);
printf("factorial of %d is %ld\n", num, f);
return 0;
}
long int factorial(int num)
{
if (num == 1)
return 1;
else
return num * factorial(num-1);
}
Voyons le résultat de l'exécution de ce programme :
Enter a number: 7
factorial of 7 is 5040
Allocation de mémoire en C
Le compilateur C possède une bibliothèque d'allocation de mémoire, définie dans malloc.h. La mémoire est réservée à l'aide de la fonction malloc et renvoie un pointeur vers l'adresse. Il prend un paramètre, la taille de la mémoire requise en octets.
L'exemple suivant alloue de l'espace pour la chaîne, "hello world".
ptr = (char *)malloc(strlen("Hello world") + 1);
L'octet supplémentaire est requis pour prendre en compte le caractère de fin de chaîne, '\0'. Le (char *) est appelé un transtypage et force le type de retour à être char *.
Comme les types de données ont des tailles différentes et que malloc renvoie l'espace en octets, il est recommandé, pour des raisons de portabilité, 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 requise et la copie dans une variable appelée "ptr".
#include <string.h>
#include <malloc.h>
int main()
{
char *ptr, buffer[80];
printf("Enter a string: ");
gets(buffer);
ptr = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(ptr, buffer);
printf("You entered: %s\n", ptr);
return 0;
}
Le résultat du programme sera le suivant :
Enter a string: India is the best
You entered: India is the best
Réallouer de la mémoire
Il est possible plusieurs fois pendant que vous programmez que vous vouliez réallouer 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 réservé de l'espace pour un pointeur appelé msg et que nous voulions réallouer de l'espace à la quantité d'espace qu'il occupe déjà, plus la longueur d'une autre chaîne, nous pourrions utiliser ce qui suit.
msg = (char *)realloc(msg, (strlen(msg) + strlen(buffer) + 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 <string.h>
#include <malloc.h>
int main()
{
char buffer[80], *msg;
int firstTime=0;
do
{
printf("\nEnter a sentence: ");
gets(buffer);
if (!firstTime)
{
msg = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(msg, buffer);
firstTime = 1;
}
else
{
msg = (char *)realloc(msg, (strlen(msg) +
strlen(buffer) + 1) * sizeof(char));
strcat(msg, buffer);
}
puts(msg);
} while(strcmp(buffer, ""));
free(msg);
return 0;
}
Le résultat du programme sera le suivant :
Enter a sentence: Once upon a time
Once upon a time
Enter a sentence: there was a king
Once upon a timethere was a king
Enter a sentence: the king was
Once upon a timethere was a kingthe king was
Enter a sentence:
Once upon a timethere was a kingthe king was
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 de la mémoire allouée, utilisez la fonction free.
gratuit(ptr);
Structures
En plus des types de données de base, C dispose d'un mécanisme de structure qui vous permet de regrouper des éléments de données liés les uns aux autres sous un nom commun. C'est ce qu'on appelle communément un type défini par l'utilisateur.
Le mot-clé struct commence la définition de la structure et une balise donne le nom unique à 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.
struct month
{
char name[10];
char abbrev[4];
int days;
};
Un type de structure est généralement défini près du début d'un fichier à l'aide d'une instruction typedef. typedef définit et nomme un nouveau type, permettant son utilisation dans tout le programme. typedef se produit généralement juste 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 plutôt que de spécifier le mot-clé struct avec le nom de la structure. Il est habituel de nommer le typedef en majuscules. Voici les exemples de définition de structure.
typedef struct {
char name[64];
char course[128];
int age;
int year;
} student;
Ceci définit un nouveau type de variable étudiant de type étudiant pouvant être déclaré comme suit.
étudiant st_rec ;
Remarquez à quel point cela ressemble à la déclaration d'un int ou d'un float. Le nom de la variable est st_rec, il a des membres appelés nom, cours, âge et année. De même,
typedef struct element
{
char data;
struct element *next;
} STACKELEMENT;
A variable of the user defined type struct element may now be declared as follows.
STACKELEMENT *stack;
Considérez la structure suivante :
struct student
{
char *name;
int grade;
};
Un pointeur vers la structure étudiant peut être défini comme suit.
struct student *hnc;
When accessing a pointer to a structure, the member pointer operator, -> is used instead of the dot operator. To add a grade to a structure,
s.grade = 50;
Vous pouvez attribuer une note à la structure comme suit.
s->grade = 50;
Comme pour les types de données de base, si vous voulez que les modifications apportées dans une fonction aux paramètres passés soient persistantes, 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 faites référence à la variable en utilisant la notation de pointeur.
Après avoir défini la structure, vous pouvez en déclarer une instance et attribuer des valeurs aux membres en utilisant la notation par points. L'exemple suivant illustre l'utilisation de la structure mensuelle.
#include <stdio.h>
#include <string.h>
struct month
{
char name[10];
char abbreviation[4];
int days;
};
int main()
{
struct month m;
strcpy(m.name, "January");
strcpy(m.abbreviation, "Jan");
m.days = 31;
printf("%s is abbreviated as %s and has %d days\n", m.name, m.abbreviation, m.days);
return 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'affecter une structure à une autre, en effectuant une copie par membre. Si nous avions des structures de mois appelées m1 et m2, nous pourrions attribuer les valeurs de m1 à m2 avec ce qui suit :
- Structure avec des membres pointeurs.
- La structure s'initialise.
- 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 <string.h>
#include <malloc.h>
struct month
{
char *name;
char *abbreviation;
int days;
};
int main()
{
struct month m;
m.name = (char *)malloc((strlen("January")+1) *
sizeof(char));
strcpy(m.name, "January");
m.abbreviation = (char *)malloc((strlen("Jan")+1) *
sizeof(char));
strcpy(m.abbreviation, "Jan");
m.days = 31;
printf("%s is abbreviated as %s and has %d days\n",
m.name, m.abbreviation, m.days);
return 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. Comme les mois commencent à 1, mais que les tableaux commencent à zéro en C, un élément supplémentaire à la position zéro appelé indésirable a été utilisé dans l'exemple suivant.
#include <stdio.h>
#include <string.h>
struct month
{
char *name;
char *abbreviation;
int days;
} month_details[] =
{
"Junk", "Junk", 0,
"January", "Jan", 31,
"February", "Feb", 28,
"March", "Mar", 31,
"April", "Apr", 30,
"May", "May", 31,
"June", "Jun", 30,
"July", "Jul", 31,
"August", "Aug", 31,
"September", "Sep", 30,
"October", "Oct", 31,
"November", "Nov", 30,
"December", "Dec", 31
};
int main()
{
int counter;
for (counter=1; counter<=12; counter++)
printf("%s is abbreviated as %s and has %d days\n",
month_details[counter].name,
month_details[counter].abbreviation,
month_details[counter].days);
return 0;
}
Et la sortie sera affichée comme suit :
January is abbreviated as Jan and has 31 days
February is abbreviated as Feb and has 28 days
March is abbreviated as Mar and has 31 days
April is abbreviated as Apr and has 30 days
May is abbreviated as May and has 31 days
June is abbreviated as Jun and has 30 days
July is abbreviated as Jul and has 31 days
August is abbreviated as Aug and has 31 days
September is abbreviated as Sep and has 30 days
October is abbreviated as Oct and has 31 days
November is abbreviated as Nov and has 30 days
December is abbreviated as Dec and has 31 days
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 transmettez que la valeur du jour, mais toute la structure est transmise pour illustrer le passage des structures aux fonctions.
#include <stdio.h>
#include <string.h>
struct month
{
char *name;
char *abbreviation;
int days;
} month_details[] =
{
"Junk", "Junk", 0,
"January", "Jan", 31,
"February", "Feb", 28,
"March", "Mar", 31,
"April", "Apr", 30,
"May", "May", 31,
"June", "Jun", 30,
"July", "Jul", 31,
"August", "Aug", 31,
"September", "Sep", 30,
"October", "Oct", 31,
"November", "Nov", 30,
"December", "Dec", 31
};
struct date
{
int day;
int month;
int year;
};
int isLeapYear(struct date d);
int main()
{
struct date d;
printf("Enter the date (eg: 11/11/1980): ");
scanf("%d/%d/%d", &d.day, &d.month, &d.year);
printf("The date %d %s %d is ", d.day,
month_details[d.month].name, d.year);
if (isLeapYear(d) == 0)
printf("not ");
puts("a leap year");
return 0;
}
int isLeapYear(struct date d)
{
if ((d.year % 4 == 0 && d.year % 100 != 0) ||
d.year % 400 == 0)
return 1;
return 0;
}
Et l'exécution du programme sera la suivante :
Enter the date (eg: 11/11/1980): 9/12/1980
The date 9 December 1980 is a leap year
L'exemple suivant alloue dynamiquement un tableau de structures pour stocker les noms et les notes des étudiants. Les notes sont ensuite affichées à l'utilisateur par ordre croissant.
#include <string.h>
#include <malloc.h>
struct student
{
char *name;
int grade;
};
void swap(struct student *x, struct student *y);
int main()
{
struct student *group;
char buffer[80];
int spurious;
int inner, outer;
int counter, numStudents;
printf("How many students are there in the group: ");
scanf("%d", &numStudents);
group = (struct student *)malloc(numStudents *
sizeof(struct student));
for (counter=0; counter<numStudents; counter++)
{
spurious = getchar();
printf("Enter the name of the student: ");
gets(buffer);
group[counter].name = (char *)malloc((strlen(buffer)+1) * sizeof(char));
strcpy(group[counter].name, buffer);
printf("Enter grade: ");
scanf("%d", &group[counter].grade);
}
for (outer=0; outer<numStudents; outer++)
for (inner=0; inner<outer; inner++)
if (group[outer].grade <
group[inner].grade)
swap(&group[outer], &group[inner]);
puts("The group in ascending order of grades ...");
for (counter=0; counter<numStudents; counter++)
printf("%s achieved Grade %d \n”,
group[counter].name,
group[counter].grade);
return 0;
}
void swap(struct student *x, struct student *y)
{
struct student temp;
temp.name = (char *)malloc((strlen(x->name)+1) *
sizeof(char));
strcpy(temp.name, x->name);
temp.grade = x->grade;
x->grade = y->grade;
x->name = (char *)malloc((strlen(y->name)+1) *
sizeof(char));
strcpy(x->name, y->name);
y->grade = temp.grade;
y->name = (char *)malloc((strlen(temp.name)+1) *
sizeof(char));
strcpy(y->name, temp.name);
}
L'exécution de la sortie sera la suivante :
How many students are there in the group: 4
Enter the name of the student: Anuraaj
Enter grade: 7
Enter the name of the student: Honey
Enter grade: 2
Enter the name of the student: Meetushi
Enter grade: 1
Enter the name of the student: Deepti
Enter grade: 4
The group in ascending order of grades ...
Meetushi achieved Grade 1
Honey achieved Grade 2
Deepti achieved Grade 4
Anuraaj achieved Grade 7
syndicat
Une union vous permet d'examiner les mêmes données avec différents types ou d'utiliser les mêmes données avec des noms différents. Les syndicats ressemblent à 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 qu'un seul de ses membres peut être utilisé à la fois. La raison en est simple. Tous les membres d'un syndicat occupent le même espace de mémoire. Ils sont posés les uns sur les 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 simple union d'une variable char et d'une variable entière, vous écririez ce qui suit :
union shared {
char c;
int i;
};
Cette union, partagée, peut être utilisée pour créer des instances d'une union pouvant contenir soit une valeur de caractère c, soit une valeur entière i. Il s'agit d'une condition OU. Contrairement à une structure qui contiendrait les deux valeurs, l'union ne peut contenir qu'une seule valeur à la fois.
Une union peut être initialisée sur sa déclaration. Parce qu'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 déclarée et initialisée :
union partagée generic_variable = {`@'} ;
Notez que l'union generic_variable a été initialisée comme le premier membre d'une structure serait initialisé.
Les membres individuels de l'union peuvent être utilisés de la même manière que les membres de la structure peuvent être utilisés en utilisant l'opérateur de membre (.). Cependant, il existe une différence importante dans l'accès aux membres du syndicat.
Un seul membre du syndicat doit être accessible à 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é union
union tag {
union_member(s);
/* additional statements may go here */
}instance;
Le mot clé union est utilisé pour déclarer les unions. Une union est une collection d'une ou plusieurs variables (union_members) qui ont été regroupées sous un nom unique. De plus, chacun de ces syndiqués occupe le même espace mémoire.
Le mot clé union identifie le début d'une définition d'union. Il est suivi d'une étiquette qui est le nom donné au syndicat. Après la balise se trouvent les membres du syndicat 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, c'est juste un modèle qui peut être utilisé plus tard dans un programme pour déclarer des structures. Voici le format d'un modèle :
union tag {
union_member(s);
/* additional statements may go here */
};
Pour utiliser le modèle, vous devez utiliser le format suivant :
instance de balise union ;
Pour utiliser ce format, vous devez avoir préalablement déclaré une union avec la balise donnée.
/* Declare a union template called tag */
union tag {
int num;
char alps;
}
/* Use the union template */
union tag mixed_variable;
/* Declare a union and instance together */
union generic_type_tag {
char c;
int i;
float f;
double d;
} generic;
/* Initialize a union. */
union date_tag {
char full_date[9];
struct part_date_tag {
char month[2];
char break_value1;
char day[2];
char break_value2;
char year[2];
} part_date;
}date = {"09/12/80"};
Comprenons-le mieux à l'aide d'exemples :
#include <stdio.h>
int main()
{
union
{
int value; /* This is the first part of the union */
struct
{
char first; /* These two values are the second part of it */
char second;
} half;
} number;
long index;
for (index = 12 ; index < 300000L ; index += 35231L)
{
number.value = index;
printf("%8x %6x %6x\n", number.value,
number.half.first,
number.half.second);
}
return 0;
}
Et la sortie du programme sera affichée comme suit :
c c 0
89ab ffab ff89
134a 4a 13
9ce9 ffe9 ff9c
2688 ff88 26
b027 27 ffb0
39c6 ffc6 39
c365 65 ffc3
4d04 4 4d
Une utilisation pratique d'une union dans la récupération de données
Voyons maintenant une utilisation pratique de l'union est 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 un lecteur de disquette (a : ), mais il ne s'agit pas du modèle complet de logiciel d'analyse des secteurs défectueux.
Examinons le programme :
#include<dos.h>
#include<conio.h>
int main()
{
int rp, head, track, sector, status;
char *buf;
union REGS in, out;
struct SREGS s;
clrscr();
/* Reset the disk system to initialize to disk */
printf("\n Resetting the disk system....");
for(rp=0;rp<=2;rp++)
{
in.h.ah = 0;
in.h.dl = 0x00;
int86(0x13,&in,&out);
}
printf("\n\n\n Now Testing the Disk for Bad Sectors....");
/* scan for bad sectors */
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
in.h.ah = 0x04;
in.h.al = 1;
in.h.dl = 0x00;
in.h.ch = track;
in.h.dh = head;
in.h.cl = sector;
in.x.bx = FP_OFF(buf);
s.es = FP_SEG(buf);
int86x(0x13,&in,&out,&s);
if(out.x.cflag)
{
status=out.h.ah;
printf("\n track:%d Head:%d Sector:%d Status ==0x%X",track,head,sector,status);
}
}
}
}
printf("\n\n\nDone");
return 0;
}
Voyons maintenant à quoi ressemblera sa sortie s'il y a un secteur défectueux sur la disquette :
Réinitialisation du système de disque...
Test maintenant le disque pour les secteurs défectueux...
track:0 Head:0 Sector:4 Status ==0xA
track:0 Head:0 Sector:5 Status ==0xA
track:1 Head:0 Sector:4 Status ==0xA
track:1 Head:0 Sector:5 Status ==0xA
track:1 Head:0 Sector:6 Status ==0xA
track:1 Head:0 Sector:7 Status ==0xA
track:1 Head:0 Sector:8 Status ==0xA
track:1 Head:0 Sector:11 Status ==0xA
track:1 Head:0 Sector:12 Status ==0xA
track:1 Head:0 Sector:13 Status ==0xA
track:1 Head:0 Sector:14 Status ==0xA
track:1 Head:0 Sector:15 Status ==0xA
track:1 Head:0 Sector:16 Status ==0xA
track:1 Head:0 Sector:17 Status ==0xA
track:1 Head:0 Sector:18 Status ==0xA
track:1 Head:1 Sector:5 Status ==0xA
track:1 Head:1 Sector:6 Status ==0xA
track:1 Head:1 Sector:7 Status ==0xA
track:1 Head:1 Sector:8 Status ==0xA
track:1 Head:1 Sector:9 Status ==0xA
track:1 Head:1 Sector:10 Status ==0xA
track:1 Head:1 Sector:11 Status ==0xA
track:1 Head:1 Sector:12 Status ==0xA
track:1 Head:1 Sector:13 Status ==0xA
track:1 Head:1 Sector:14 Status ==0xA
track:1 Head:1 Sector:15 Status ==0xA
track:1 Head:1 Sector:16 Status ==0xA
track:1 Head:1 Sector:17 Status ==0xA
track:1 Head:1 Sector:18 Status ==0xA
track:2 Head:0 Sector:4 Status ==0xA
track:2 Head:0 Sector:5 Status ==0xA
track:14 Head:0 Sector:6 Status ==0xA
Done
Il peut être un peu difficile de comprendre les fonctions et les interruptions utilisées dans ce programme pour vérifier le disque pour les secteurs défectueux et réinitialiser le système de disque, etc. mais vous n'avez pas à vous inquiéter, nous allons apprendre toutes ces choses dans le BIOS et interrompez les sections de programmation plus tard dans les prochains chapitres.
Gestion des fichiers en C
L'accès aux fichiers en C est obtenu 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 sous la forme FILE *. Un pointeur de fichier appelé output_file est déclaré dans une instruction comme
FILE *output_file ;
Les modes de fichier de la fonction fopen
Votre programme doit ouvrir un fichier avant de pouvoir y accéder. Cela se fait à l'aide de la fonction fopen, qui renvoie le pointeur de fichier requis. Si le fichier ne peut pas être ouvert pour une raison quelconque, la valeur NULL sera renvoyée. Vous utiliserez généralement fopen comme suit
if ((output_file = fopen("output_file", "w")) == NULL)
fprintf(stderr, "Cannot open %s\n",
"output_file");
fopen prend deux arguments, les deux sont 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 l'un des r, a ou w etc. Les fichiers peuvent être ouverts dans un certain nombre de modes, comme indiqué dans le tableau suivant.
File Modes |
r |
Open a text file for reading. |
w |
Create a text file for writing. If the file exists, it is overwritten. |
a |
Open a text file in append mode. Text is added to the end of the file. |
rb |
Open a binary file for reading. |
wb |
Create a binary file for writing. If the file exists, it is overwritten. |
ab |
Open a binary file in append mode. Data is added to the end of the file. |
r+ |
Open a text file for reading and writing. |
w+ |
Create a text file for reading and writing. If the file exists, it is overwritten. |
a+ |
Open a text file for reading and writing at the end. |
r+b or rb+ |
Open binary file for reading and writing. |
w+b or wb+ |
Create a binary file for reading and writing. If the file exists, it is overwritten. |
a+b or ab+ |
Open a text file for reading and writing at the end. |
Les modes de mise à jour 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.
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
Fermeture de fichiers
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 liste le contenu d'un fichier à l'écran, en utilisant fgetc pour lire le fichier un caractère à la fois.
#include <stdio.h>
int main()
{
FILE *in;
int key;
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
while (!feof(in))
{
key = fgetc(in);
/* The last character read is the end of file marker so don't print it */
if (!feof(in))
putchar(key);
}
fclose(in);
return 0;
}
La fonction fscanf peut être utilisée pour lire différents types de données à partir 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 est utilisée pour lire un certain nombre de caractères à partir d'un fichier. stdin est le flux de fichier d'entrée standard et la fonction fgets peut être utilisée pour contrôler l'entrée.
Écrire dans des fichiers
Les données peuvent être écrites dans le fichier en utilisant 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()
{
FILE *in, *out;
int key;
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Unable to open the file");
return 0;
}
out = fopen("copy.txt", "w");
while (!feof(in))
{
key = fgetc(in);
if (!feof(in))
fputc(key, out);
}
fclose(in);
fclose(out);
return 0;
}
La fonction fprintf peut être utilisée pour écrire des données formatées dans un fichier.
fprintf(out, "Date: %02d/%02d/%02d\n",
day, month, year);
Arguments de ligne de commande avec C
La définition ANSI C pour déclarer la fonction main( ) est soit :
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 transmis depuis la ligne de commande. Le paramètre argv est le vecteur d'argument qui est un tableau de pointeurs vers des chaînes qui représentent les paramètres réels passés.
L'exemple suivant permet de passer n'importe quel nombre d'arguments à partir de 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 argc, char **argv)
{
int counter;
puts("The arguments to the program are:");
for (counter=0; counter<argc; counter++)
puts(argv[counter]);
return 0;
}
If the program name was count.c, it could be called as follows from the command line.
count 3
or
count 7
or
count 192 etc.
L'exemple suivant utilise les 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é :
txtcpy un.txt deux.txt
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *in, *out;
int key;
if (argc < 3)
{
puts("Usage: txtcpy source destination\n");
puts("The source must be an existing file");
puts("If the destination file exists, it will be
overwritten");
return 0;
}
if ((in = fopen(argv[1], "r")) == NULL)
{
puts("Unable to open the file to be copied");
return 0;
}
if ((out = fopen(argv[2], "w")) == NULL)
{
puts("Unable to open the output file");
return 0;
}
while (!feof(in))
{
key = fgetc(in);
if (!feof(in))
fputc(key, out);
}
fclose(in);
fclose(out);
return 0;
}
Manipulateurs de bits
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 jeu de bits est calculé comme 2 à la puissance du jeu 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.
binary representation of the number 59 |
bit 5 4 3 2 1 0 |
2 power n 32 16 8 4 2 1 |
set 1 1 1 0 1 1 |
Avec trois bits, il est possible de représenter les nombres de 0 à 7. Le tableau suivant présente les nombres de 0 à 7 sous leur forme binaire.
Binary Digits |
000 |
0 |
001 |
1 |
010 |
2 |
011 |
3 |
100 |
4 |
101 |
5 |
110 |
6 |
111 |
7 |
Le tableau suivant répertorie les opérateurs au niveau du bit qui peuvent être utilisés pour manipuler les nombres binaires.
Binary Digits |
& |
Bitwise AND |
| |
Bitwise OR |
^ |
Bitwise Exclusive OR |
~ |
Bitwise Complement |
<< |
Bitwise Shift Left |
>> |
Bitwise Shift Right |
ET au niveau du bit
L'ET au niveau du bit est Vrai uniquement si les deux bits sont définis. L'exemple suivant montre le résultat d'un ET au niveau du bit sur les nombres 23 et 12.
10111 (23)
01100 (12) AND
____________________
00100 (result = 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 si les bits 1 et 3) et tester le résultat par rapport au masque.
#include <stdio.h>
int main()
{
int num, mask = 10;
printf("Enter a number: ");
scanf("%d", &num);
if ((num & mask) == mask)
puts("Bits 1 and 3 are set");
else
puts("Bits 1 and 3 are not set");
return 0;
}
OU au niveau du bit
Le OU au niveau du bit est vrai si l'un ou l'autre des bits est défini. Ce qui suit montre le résultat d'un OU au niveau du bit sur les nombres 23 et 12.
10111 (23)
01100 (12) OR
______________________
11111 (result = 31) |
Vous pouvez utiliser un masque pour vous assurer 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, mask = 4;
printf("Enter a number: ");
scanf("%d", &num);
num |= mask;
printf("After ensuring bit 2 is set: %d\n", num);
return 0;
}
OU exclusif au niveau du bit
Le OU exclusif au niveau du bit est Vrai si l'un ou l'autre des 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) Exclusive OR (XOR)
_____________________________
11011 (result = 27) |
Le OU exclusif a des propriétés intéressantes. Si vous utilisez un OU exclusif sur un nombre seul, il se met à zéro car les zéros resteront à zéro et les uns ne peuvent pas être définis tous les deux, ils sont donc mis à zéro.
En conséquence, si vous faites un OU Exclusif avec un nombre avec un autre nombre, puis un OU Exclusif avec l'autre nombre à nouveau, le résultat est le nombre d'origine. Vous pouvez essayer ceci avec les nombres utilisés dans l'exemple ci-dessus.
23 XOR 12 = 27
27 XOR 12 = 23
27 XOR 23 = 12
Cette fonctionnalité peut être utilisée pour le chiffrement. Le programme suivant utilise une clé de cryptage de 23 pour illustrer la propriété sur un nombre saisi par l'utilisateur.
#include <stdio.h>
int main()
{
int num, key = 23;
printf("Enter a number: ");
scanf("%d", &num);
num ^= key;
printf("Exclusive OR with %d gives %d\n", key, num);
num ^= key;
printf("Exclusive OR with %d gives %d\n", key, num);
return 0;
}
Compliment au niveau du bit
Le compliment au niveau du bit est un opérateur de compliment à un qui active ou désactive le bit. Si c'est 1, il sera mis à 0, si c'est 0, il sera mis à 1.
#include <stdio.h>
int main()
{
int num = 0xFFFF;
printf("The compliment of %X is %X\n", num, ~num);
return 0;
}
Décalage au niveau du bit 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éplace vers la gauche, et les bits les moins significatifs libérés sont nuls. Ce qui suit montre la représentation binaire de 43.
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 au bit le moins significatif. Voici le nombre résultant.
1010110 (décimal 86)
Décalage au niveau du bit vers la droite
L'opérateur Bitwise Shift Right décale le nombre vers la droite. 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 un), et le nombre est complété par un zéro au bit le plus significatif. Voici le nombre résultant.
0010101 (décimal 21)
Le programme suivant utilise les options Bitwise Shift Right et Bitwise AND pour afficher un nombre sous la forme d'un nombre binaire 16 bits. Le nombre est décalé vers la droite successivement de 16 vers le bas jusqu'à zéro et bitwise AND avec 1 pour voir si le bit est défini. Une méthode alternative consisterait à utiliser des masques successifs avec l'opérateur Bitwise OR.
#include <stdio.h>
int main()
{
int counter, num;
printf("Enter a number: ");
scanf("%d", &num);
printf("%d is binary: ", num);
for (counter=15; counter>=0; counter--)
printf("%d", (num >> counter) & 1);
putchar('\n');
return 0;
}
Fonctions pour les conversions binaires et décimales
Les deux fonctions données ensuite sont pour la conversion Binaire en Décimal et Décimal en Binaire. La fonction donnée ensuite pour convertir un nombre décimal en nombre binaire correspondant prend en charge jusqu'à 32 - Nombre binaire binaire. Vous pouvez utiliser ceci ou le programme donné auparavant pour la conversion selon vos besoins.
Fonction de conversion décimal en binaire :
void Decimal_to_Binary(void)
{
int input =0;
int i;
int count = 0;
int binary [32]; /* 32 Bit, MAXIMUM 32 elements */
printf ("Enter Decimal number to convert into
Binary :");
scanf ("%d", &input);
do
{
i = input%2; /* MOD 2 to get 1 or a 0*/
binary[count] = i; /* Load Elements into the Binary Array */
input = input/2; /* Divide input by 2 to decrement via binary */
count++; /* Count how many elements are needed*/
}while (input > 0);
/* Reverse and output binary digits */
printf ("Binary representation is: ");
do
{
printf ("%d", binary[count - 1]);
count--;
} while (count > 0);
printf ("\n");
}
Fonction de conversion binaire en décimal :
La fonction suivante consiste à convertir n'importe quel nombre binaire en son nombre décimal correspondant :
void Binary_to_Decimal(void)
{
char binaryhold[512];
char *binary;
int i=0;
int dec = 0;
int z;
printf ("Please enter the Binary Digits.\n");
printf ("Binary digits are either 0 or 1 Only ");
printf ("Binary Entry : ");
binary = gets(binaryhold);
i=strlen(binary);
for (z=0; z<i; ++z)
{
dec=dec*2+(binary[z]=='1'? 1:0); /* if Binary[z] is
equal to 1,
then 1 else 0 */
}
printf ("\n");
printf ("Decimal value of %s is %d",
binary, dec);
printf ("\n");
}
Débogage et test
Erreurs de syntaxe
La syntaxe fait référence à la grammaire, à la structure et à l'ordre des éléments dans une instruction. Une erreur de syntaxe se produit lorsque nous enfreignons les règles, comme oublier de terminer une instruction par un point-virgule. Lorsque vous compilez le programme, le compilateur produit une liste de toutes les erreurs de syntaxe qu'il peut rencontrer.
Un bon compilateur affichera la liste avec une description de l'erreur et pourra fournir une solution possible. La correction des erreurs peut entraîner l'affichage d'autres erreurs lors de la recompilation. La raison en 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 recompilerez, vous obtiendrez 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 peut causer des problèmes lors de l'exécution de votre 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. Il ne s'agit pas d'une erreur de syntaxe, mais cela peut entraîner des problèmes. Dans cet exemple particulier, vous pouvez afficher l'intention en transtypant la variable dans le 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 pendant l'affectation, ce qui éliminerait tout avertissement du compilateur.
x = (flottant)y ;
Erreurs de logique
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 peut jamais être vrai, mais s'il est syntaxiquement correct, le programme se compilera avec succès. Prenons l'exemple suivant :
if (x < 4 && x > 8)
puts("Will never happen!");
La syntaxe est correcte, donc le programme compilera, mais l'instruction puts ne sera jamais imprimée car la valeur de x ne peut pas être inférieure à quatre et supérieure à huit en même temps.
La plupart des erreurs de logique sont découvertes lors des tests initiaux du programme. Lorsqu'il ne se comporte pas comme prévu, vous inspectez les instructions logiques de plus près et les corrigez. Cela n'est vrai que pour les erreurs logiques évidentes. Plus le programme est volumineux, plus il y aura de chemins à travers lui, plus il devient difficile de vérifier que le programme se comporte comme prévu.
Test
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 antérieures de développement du logiciel sont manuelles. Par conséquent, le code développé au cours de l'activité de codage est susceptible de comporter des erreurs d'exigence et des erreurs de conception, en plus des erreurs introduites au cours de l'activité de codage. Pendant les tests, le programme à tester est exécuté avec 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 est performante est attendue.
Ainsi, le test est le processus d'analyse d'un élément logiciel pour détecter la différence entre les conditions existantes et requises (c'est-à-dire les bogues) et pour évaluer les fonctionnalités des éléments logiciels. Ainsi, le test est le processus d'analyse d'un programme dans le but de trouver des erreurs.
Quelques principes de test
- Les tests ne peuvent pas montrer l'absence de défauts, seulement leur présence.
- Plus une erreur est commise tôt, plus elle est coûteuse.
- Plus une erreur est détectée tardivement, plus elle est coûteuse.
Voyons maintenant quelques techniques de test :
Test de la boîte blanche
Le test de la boîte blanche est une technique par laquelle tous les chemins du programme sont testés avec toutes les valeurs possibles. Cette approche nécessite une certaine connaissance du comportement du programme. Par exemple, si votre programme acceptait une valeur entière entre 1 et 50, un test de boîte blanche testerait le programme avec les 50 valeurs pour s'assurer qu'il était correct pour chacune, puis testerait toutes les autres valeurs possibles qu'un entier peut prendre et testerait que il s'est comporté comme prévu. Compte tenu du nombre d'éléments de données qu'un programme typique peut avoir, les permutations possibles rendent les tests en boîte blanche extrêmement difficiles pour les grands programmes.
Les tests de la 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 des tests de la 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ù des plages de valeurs sont transmises rapidement au programme via un programme spécial, enregistrant les exceptions au comportement attendu. Les tests en boîte blanche sont parfois appelés tests structurels, clairs ou ouverts.
Test de la boîte noire
Le test de la boîte noire est similaire au test 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 normalement conçus dès que les spécifications du programme sont terminées. Les cas de test sont basés sur des classes d'équivalence.
Classes d'équivalence
Pour chaque entrée, une classe d'équivalence identifie les états valides et invalides. Il y a généralement trois scénarios à prévoir lors de la définition des classes d'équivalence.
Si l'entrée spécifie une plage ou une valeur spécifique, il y aura un état valide et deux états invalides définis. Par exemple, si un nombre doit être compris entre 1 et 20, l'état valide est compris entre 1 et 20, il y aura un état invalide inférieur à 1 et un état invalide supérieur à 20.
Si l'entrée exclut une plage ou une valeur spécifique, il y aura deux états valides et un état invalide défini. Par exemple, si un nombre ne doit pas être compris entre 1 et 20, les états valides sont inférieurs à un et supérieurs à 20, et l'état invalide est 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 invalide.
Analyse de la valeur limite
L'analyse des valeurs limites ne prend en compte que les valeurs à la limite des entrées. Par exemple, dans le cas d'un nombre compris entre 1 et 20, les cas de test peuvent être 1, 20, 0 et 21. L'idée sous-jacente est que si le programme fonctionne comme prévu avec ces valeurs, les autres valeurs seront également fonctionne comme prévu.
Le tableau suivant donne un aperçu des limites typiques que vous voudrez peut-être identifier.
Testing Ranges |
Input type |
Test Values |
Range |
- x[lower_bound]-1
- x[lower_bound]
- x[upper_bound]
- x[upper_bound]+1
|
Boolean |
|
Concevoir un plan de test
Identifiez les classes d'équivalence et, pour chaque classe, identifiez les limites. Après avoir identifié les limites de la classe, écrivez une liste de valeurs valides et invalides sur 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.
Ce qui suit peut être un plan de test typique utilisé pour vérifier si un âge est entré où les valeurs acceptables sont comprises entre 10 et 110.
Equivalence Class |
Valid |
Invalid |
Between 10 and 110 |
> 110 |
|
< 10 |
Après avoir défini notre classe d'équivalence, nous pouvons maintenant concevoir un plan de test pour l'âge.
Test Plan |
Value |
State |
Expected Result |
Actual Result |
10 |
Valid |
Continue execution to get name |
|
110 |
Valid |
Continue execution to get name |
|
9 |
Invalid |
Ask for age again |
|
111 |
Invalid |
Ask for age again |
|
Le "Résultat réel" colonne est laissée vide, car elle sera complétée lors des tests. Si le résultat est comme prévu, la colonne sera cochée. Si ce n'est pas le cas, un commentaire indiquant ce qui s'est passé doit être saisi.
Page modifiée le: 09/03/2022