Rappels de langage C
Transcription
Rappels de langage C
ESIEE IN3T01 Abrégé de langage C 2010/2011 Le langage C Le langage C est le langage de développement lié à UNIX. Le système UNIX est d'ailleurs écrit à 95% en C. C est un langage assez proche de la machine, mais portable. Le développement en C prend en moyenne sept fois moins de temps que le même développement en assembleur par un programmeur confirmé, et le surcoût en taille mémoire des programmes et en temps d'exécution n'est de l'ordre que de une fois et demie à deux fois. De plus, sa portabilité en fait un langage de développement idéal pour l'écriture de systèmes, de SGBD ou d'autres logiciels applicatifs. Le langage C a une réputation de difficulté à maintenir qui est due en grande partie à la tendance de certains programmeurs à utiliser des trucs et astuces permis par C au détriment de la lisibilité. Cependant, un programme C correctement construit et commenté est aussi facile à lire qu'un programme écrit dans un langage plus « clair ». Voici un exemple de programme C, une esquisse de la commande wc d'UNIX qui compte les caractères, les mots et les lignes d'un fichier, avec la faible définition pour un mot d'être une suite de caractères sans espace, retour chariot ou tabulation. [1] #include <stdio.h> [2] #define OUI 1 [3] #define NON 0 [4] int main(void) { [5] int c, nl, nm, nc, dans_un_mot; [6] dans_un_mot = NON; [7] nl = nm = nc = 0; [8] while ((c = getchar()) != EOF) { [9] ++nc; [10] if (c == '\n') [11] ++nl; [12] if (c == ' ' || c == '\n' || c == '\t') [13] dans_un_mot = NON; [14] else if (dans_un_mot == NON) { [15] dans_un_mot = OUI; [16] ++nm; [17] } [18] } [19] printf ("%d %d %d\n", nl, nm, nc); [20] return 0; [21]} Les lignes sont numérotées ici pour le besoin de l'explication. Un programme C n'a pas de numéros de ligne. JCG 1/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 Pour compiler sous UNIX ce programme, enregistré sous le nom compte_mots.c, on utilise la commande $ cc compte_mots.c <Entrée> qui appelle le compilateur C et produit si il n'y a pas d'erreur un fichier exécutable appelé a.out (nom donné par défaut). Si on veut lui donner un autre nom que a.out (par exemple wc), il suffit d'appeler $ cc compte_mots.c -o wc <Entrée> La commande $ wc < compte_mots.c <Entrée> nous donnera une sortie du genre 24 75 373 $ Revenons à l'étude du programme source. La ligne [1] demande au compilateur d'inclure le texte du fichier stdio.h qui se trouve en général dans le répertoire /usr/include et qui contient des déclarations de fonctions (comme getchar) et des définitions (comme EOF). Les lignes [2] et [3] préviennent le compilateur que, chaque fois que dans le texte du programme il rencontrera le mot OUI (respectivement NON), il devra le remplacer par 1 (respectivement 0). Ces remplacements ne se feront évidemment pas dans les commentaires, chaînes de caractères constantes ou à l'intérieur d'un mot. Par convention, tous les programmes C possèdent une fonction appelée main. C'est cette fonction qui est exécutée au lancement du programme. Dans notre exemple, c'est la seule fonction du programme. Elle est déclarée ligne [4]. Les fonctions C retournent en général une valeur. Si elles n'en retournent pas, on les préfixe par void pour éviter une erreur de type warning (erreur mineure, n'empêchant pas la compilation, mais signalant souvent un défaut). Les parenthèses vides indiquent que main n'a pas de paramètres. Le texte d'une fonction est entre deux accolades { et }. Dans le texte de main, il y a cinq déclarations de variables (ligne [5] ), toutes cinq de type entier (int) et cinq instructions : – une instruction d'affectation simple à la ligne [6] – une instruction d'affectation composée ligne [7] – une instruction de boucle : while... (ligne [8] à ligne [18] – une instruction printf d'affichage (ligne [19]) – une instruction de retour (ligne [20]) JCG 2/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 L'instruction d'affectation composée n'est pas une spécificité, mais simplement la conséquence qu'en C, l'affectation peut être utilisée dans une expression, avec comme valeur celle de la partie gauche de l'affectation, et que de plus l'affectation est associative droite à gauche. On peut donc écrire des instructions du type : a = (b = 5)+( c = 2); qui aura exactement le même résultat que b = 5; c = 2; a = b + c; Dans le cas de l'affectation composée du programme, tout se passe comme si l'on avait écrit : nl = (nm = (nc = 0)); L'instruction while teste une condition; si elle est vraie, exécute le corps de la boucle, et ce tant que la condition est vraie. Ici, la condition est : Est-ce que le caractère lu dans le fichier d'entrée standard (par la fonction getchar())et stocké dans c (par l'affectation) est différent du caractère signalant la fin de fichier (désigné par EOF). Si oui, c'est à dire si un caractère du fichier vient d'être lu, la boucle est exécutée. Sinon, on passe à l'instruction suivante (affichage). Le corps de la boucle while est une instruction, ici composée de trois instructions encadrées entre accolades : – incrémentation du compteur de caractère ++nc; a exactement la même signification que nc = nc + 1; mais est plus concise et souvent plus efficace. – une instruction de test si le caractère lu (stocké dans c) est égal (==) au caractère de retour chariot ('\n'), on incrémente le compteur de ligne (++nl). – une autre instruction de test si le caractère lu est égal à un espace(' ') ou (||) s'il est égal à un retour chariot ('\n') ou s'il est égal à une tabulation('\t'), alors on n'est pas dans un mot (dans_un_mot = NON) sinon ( c'est à dire si le caractère lu est un non-espace ) si on n'est pas dans un mot (dans_un_mot == NON) alors on rentre dans un mot (dans_un_mot = OUI) et on le compte (++nm) L'instruction d'affichage affiche les trois variables nl, nm, nc, sous un format entier (%d) séparées par des espaces et suivies d'un retour ligne : "%d %d %d\n" Enfin, l'instruction return termine le programme et renvoie au système la valeur 0. JCG 3/21 ESIEE IN3T01 2010/2011 Abrégé de langage C 1 La syntaxe C 1.1 Les règles d'écriture 1.1.1 Commentaires et espaces Un commentaire commence par les caractères /* et se termine par */. Le commentaire /* fin de ligne est accepté par la plupart des compilateurs. Les commentaires imbriqués sont autorisés par certains compilateurs, mais pas par tous. Pour séparer les mots C, on peut utiliser des espaces, tabulations, retours ligne ou des commentaires. 1.1.2 Les identificateurs Un identificateur nomme une variable, une étiquette ou une fonction. Il est formé d'une suite alphanumérique commençant par une lettre. Le tiret de soulignement ( _ ) est considéré comme une lettre. Attention : Le langage C distingue les majuscules et les minuscules. La longueur maximum d'un identificateur dépend des compilateurs (6 minimum, souvent 32). Certains identificateurs sont des mots réservés du langage : auto break case char continue default do double else entry enum extern float for goto if int long register return short sizeof static struct Tableau 1 : les mots réservés du C JCG 4/21 typedef switch union unsigned void while ESIEE IN3T01 1.1.3 Abrégé de langage C 2010/2011 Les types simples Le langage C possède plusieurs types simples pour les données, dont la taille mémoire en multiple de la taille d'un caractère peut être fournie par l'opérateur sizeof. - char représente n'importe quel caractère du jeu de caractères utilisé. Un caractère est représenté sous la forme d'un entier et sa valeur dépend du code (ASCII, EBCDIC, Unicode, ...) - short int, int, long int désignent trois types d'entiers en arithmétique modulo 2n, où n est le nombre de bits utilisés pour représenter un nombre. Les trois types respectent les règles suivantes : 1 = sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) sizeof(short) < sizeof(long) - unsigned short int , unsigned int, unsigned long int désignent les entiers non signés. Le mot int peut être omis si unsigned, short ou long est précisé. – float et double désignent les réels simple et double précision. 1.1.4 Les constantes Une constante entière s'écrit comme une suite de chiffres. Si elle commence par 0, elle est considérée comme octale (en base 8), par 0x ou 0X comme hexadécimale(en base 16, les valeurs de 10 à 15 sont alors représentées par a-f ou A-F). Les constantes de type long se suffixent par l (la lettre L minuscule) ou L. Une constante de type caractère s'écrit entre apostrophes simples ( ' ). On utilise la contre-oblique \ pour représenter les caractères spéciaux selon le tableau suivant : représentation caractère '\n' '\t' '\b' '\r' '\\' '\'' '\0' nouvelle ligne (nl) tabulation (ht) retour arrière (bs) retour chariot (cr) anti slash apostrophe nul Tableau 2 : les constantes caractères spéciales De plus, on peut représenter un caractère sous sa forme numérique octale '\ddd' où d désigne un chiffre octal. Les constantes chaîne de caractères sont des suites de caractères encadrées par des double guillemets anglais ( " ). Elles peuvent contenir les caractères spéciaux sous la forme décrite précédemment avec en plus \" pour inclure un guillemet à l'intérieur de la chaîne. Le caractère nul ('\0') est ajouté systématiquement à toute constante chaîne. JCG 5/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 Les constantes réelles sont traitées en double précision et s'écrivent sous la forme : partie_entière[.partie_décimale]e[±]exposant comme par exemple 0.0 -2.71828 6.02e23 1.1.5 Les variables Une variable est un nom (identificateur) qui permet d'adresser un espace mémoire où sera stocké le contenu (la valeur) de la variable. Une variable est déclarée par nom_type nom_variable; Le type est nécessaire pour pouvoir réserver une place suffisante pour stocker la valeur de la variable. La variable existera tant que la fin du bloc dans lequel elle est déclarée n'est pas atteinte (variable automatique), sauf si elle est déclarée static ou extern, auquel cas elle existera depuis le début jusqu'à la fin du programme. 1.2 Les expressions et les opérateurs Une expression est une constante, un identificateur, un élément de tableau, une référence à une structure ou une union, un appel de fonction ou toute combinaison d'expressions. 1.2.1 Les opérateurs arithmétiques + * / % addition soustraction multiplication division ( entière si les deux opérandes sont entiers) reste de la division entière (17 % 5 -> 2) Tableau 3 : les opérateurs arithmétiques 1.2.2 Les opérateurs relationnels Ils retournent 0 si la comparaison est fausse et 1 si elle est vraie < strictement inférieur <= inférieur ou égal > strictement supérieur >= supérieur ou égal Tableau 4 : les comparateurs arithmétiques 1.2.3 Les opérateur d'égalité et d'inégalité Ils retournent 0 si la comparaison est fausse et 1 si elle est vraie == égal != différent Tableau 5 : les opérateurs d'égalité JCG 6/21 ESIEE IN3T01 1.2.4 Abrégé de langage C 2010/2011 Les opérateurs de décalage Ils décalent l'opérande gauche d'un nombre de bits égal à l'opérande droit >> décalage droite (si unsigned, remplissage par des 0, sinon dépendant du compilateur) << décalage gauche remplissage par des 0 Tableau 6 : les opérateurs de décalage 1.2.5 Les opérateurs bit à bit Ils réalisent pour les bits de même rang de leurs opérandes l'opération logique indiquée. & et logique | ou logique ^ ou exclusif Tableau 7 : les opérateurs bit à bit 1.2.6 Les opérateurs logiques Ils n'évaluent leur opérande droit qu'en cas de nécessité. && et logique (retourne 1 si les deux opérandes non nuls, 0 sinon) || ou logique (retourne 1 si un des opérandes non nul, 0 sinon) ! non logique (retourne 1 si un des opérandes non nul, 0 sinon) Tableau 8 : les opérateurs logiques 1.2.7 L'opérateur virgule expr1, expr2 évalue expr1, puis expr2 et retourne la valeur de expr2 1.2.8 Les opérateurs d'affectation l_value = expr ; l_value est une expression permettant de désigner une adresse mémoire (identificateur de variable, indirection de pointeur, élément de tableau, référence à une structure ou à une union) , et expr une expression. l_value et expr sont évaluées et la valeur de expr est rangée à l'endroit défini par la l_value. += -= *= /= %= >>= <<= &= ^= |= effectuent entre leurs deux opérandes l'opération indiquée avant le signe = et range leur résultat dans leur membre gauche x += y est équivalent à x = x + y, mais l'adresse de x n'est recherchée qu'une fois. JCG 7/21 ESIEE IN3T01 1.2.9 Abrégé de langage C 2010/2011 L'opérateur conditionnel expr ? expr1 : expr2 Il évalue expr. Si sa valeur est non nulle, retourne la valeur de expr1 sinon la valeur de expr2. 1.2.10 Les opérateurs unaires e représente une expression et v une l_value opérateur description *e retourne la valeur contenue à l'adresse calculée par e &v retourne l'adresse mémoire de la variable v -e moins unaire !e non logique (si e vaut 0, retourne 1 sinon retourne 0) ~e non logique bit à bit ++v incrémente v et retourne sa valeur --v décrémente v et retourne sa valeur v++ retourne la valeur de v, puis l'incrémente v-retourne la valeur de v, puis le décrémente (nom_type)e convertit e dans le type nom_type sizeof(e) taille (en char) de e sizeof(type) taille (en char) d'un objet de type Tableau 9 : les opérateurs unaires 1.2.11 La conversion de type Des conversions de type sont effectuées automatiquement à chaque opération ou appel de fonction. D'abord, les opérandes char ou short sont convertis en int, et ceux de type float sont convertis en double Puis, si l'un des opérandes est double, l'autre est converti en double et le résultat est de type double. Sinon, si l'un des opérandes est long, l'autre est converti en long et le résultat est de type long. Sinon, si l'un des opérandes est unsigned, l'autre est converti en unsigned et le résultat est de type unsigned. Sinon, les deux opérateurs sont de types int et le résultat de type int. 1.2.12 Priorité et ordre d'évaluation. Le tableau suivant donne l'ordre de priorité, décroissant d'une ligne à la suivante, et le sens d'évaluation en cas d'opérateurs de même priorité d'une expression. JCG 8/21 ESIEE IN3T01 Abrégé de langage C Opérateur () [] -> . ! ~ ++ -- - (nom_type) * & sizeof * / % + << >> < <= > >= == != & ^ | && || ?: = += -= *= ... , 2010/2011 Sens d'évaluation → ← → → → → → → → → → → ← ← → Tableau 10 : priorités des opérateurs 2 Le contrôle du programme 2.1 Les instructions de contrôle L'ordre normal d'exécution des instructions est l'ordre d'écriture de ces instructions. Une instruction composée est une suite d'instructions, encadrée par des accolades. Sauf précision contraire, toute instruction peut être considérée comme une instruction composée. 2.1.1 L'instruction if if (expression) instruction1 ou if (expression) instruction1 else instruction2 Si la valeur de l'expression est non nulle, c'est instruction1 qui sera exécutée. Sinon, lorsque la partie else existe, c'est instruction2. 2.1.2 L'instruction switch switch (expression_de_type_int) instruction_composée Selon la valeur de l'expression, le débranchement se fait sur l'une des instructions de l'instruction composée étiquetée de la manière suivante : case expression_constante : ou default : JCG 9/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 Le déroulement se poursuit à l'instruction suivant l'étiquette dont la valeur est égale à la valeur de l'expression, ou à l'instruction étiquetée default jusqu'à rencontrer une instruction break; qui débranche sur l'instruction suivant l'instruction switch. 2.1.3 Les itérations while (expression) instruction tant que l'expression est évaluée à une valeur non nulle, le programme exécute l'instruction. ● for (instr1; expr; instr2) instruction est équivalente à : instr1 while (expr2) { instruction instr2 } ● do instruction while (expr) est équivalente à instruction while(expr) instruction ● break; permet de sortir d'une l'instruction do, for, while ou switch, d'un niveau d'imbrication seulement. ● goto etiquette; permet de débrancher inconditionnellement sur l'instruction de la même fonction étiquetée par etiquette, du type etiquette : instruction; ● continue; débranche le programme sur l'itération suivante de boucle for, while ou do. ● 2.2 Les fonctions Une fonction est un morceau de programme appelable aussi souvent que nécessaire, et qui rend souvent un programme plus lisible. ● Une fonction est déclarée en spécifiant le type de résultat (void si elle ne retourne pas de valeur, on l'appelle alors procédure) et le nom de la fonction. type_de_résultat nom_de_la_fonction(liste_de_paramètres); ● Une fonction est définie en précisant de plus le nom de ses paramètres formels, leurs types et le corps de la fonction. Une définition peut servir de déclaration. type_de_résultat nom_de_la_fonction (liste_de_paramètres) { corps_de_la_fonction } Si le type_de_résultat n'est pas déclaré, la fonction est supposée retourner un int. Une fonction ne peut pas être définie dans une autre fonction. Le corps de la fonction JCG 10/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 commence par la déclaration des variables locales à la fonction. Une variable locale déclarée static conservera sa valeur d'un appel à l'autre de la fonction. Une instruction return terminera l'exécution de la fonction. Il peut y avoir plusieurs instructions return dans une même fonction (mais une seule sera exécutée). return; terminera la fonction sans transmettre de valeur return expr; terminera la fonction en retournant expr Une fonction ne peut retourner qu'un seul résultat de type simple (caractère, entier, flottant, pointeur). Une fonction peut être appelée dans une instruction ou dans une expression . Si c'est une instruction, sa valeur de retour est ignorée. Si c'est une expression, sa valeur de retour est utilisée pour l'évaluation de l'expression. Une fonction peut s'appeler elle-même (appel récursif). Lors de l'appel, les arguments réels (ceux du programme appelant) sont copiés dans l'ordre dans les paramètres formels (les arguments de la déclaration). Les valeurs transmises peuvent donc être modifiées sans que les paramètres réels soient modifiés. Par exemple, int fac1(int n){ int fac2(int n) { int fac3(int n){ int i, res; int res; if (n<=1) res =1; res = 1; return 1; for(i=2;i<=n;i++) for(n;n>=2;n--) else res = i * res; res*=n; return return res; return res; n*fac3(n-1); } } } L'appel à ces fonctions se fera, par exemple, de la manière suivante : a = 5; b = 2; x = fac1(a) / fac2(b) / fac3(a-b); La première fonction est écrite dans un style classique. La deuxième se sert du fait que les paramètres ne sont transmis que par valeur, et que n peut servir à la fois de compteur de boucle et de test. La troisième utilise la récursivité. Attention : Le langage C ne transmet les paramètres de fonction que par copie. Si une modification intervient dans la fonction, elle n'aura d'effet que sur la copie, pas sur l'original. Pour modifier la valeur d'un paramètre par l'intermédiaire d'une fonction, on transmet l'adresse du paramètre à modifier, et on réceptionne cette adresse dans un pointeur. void triple(int *a) {*a *= 3;} int x=2; triple(&x); /* x vaut maintenant 6 */ JCG 11/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 3 Les types composés et les pointeurs 3.1 Les tableaux Un tableau est un ensemble de variables de même type. int a[4] ; déclare 4 variables de type int : a[0], a[1], a[2] et a[3]. Les éléments d'un tableau sont des l_values et peuvent donc apparaître à gauche d'une affectation. Un tableau à deux dimensions est déclaré comme ceci : char ecran[24][80]; déclare un tableau de 24 lignes (de 0 à 23) de 80 caractères (de 0 à 79). ecran[i][j] désignera le caractère j de la ligne i. Dans les appels de fonctions, la valeur transmise pour un tableau est l'adresse du premier élément de ce tableau. Par exemple, les chaînes de caractères étant des tableaux de caractères terminés par '\0', on peut écrire le programme suivant : /* recopie la ch2 dans ch1 */ void copie_chaine(char ch1[], char ch2[]) { /*la taille d'un tableau n'est ici pas nécessaire */ int i; for (i=0; ((ch1[i] = ch2[i]) != '\0' ; i++) ; /* le résultat de l'affectation sert au test */ } 3.2 Les pointeurs 3.2.1 Définition Un pointeur est une variable dont le contenu est l'adresse d'une l_value. Il est déclaré en précisant le type d'objet sur lequel il pointe : int *pi; signifie que pi est destiné à contenir l'adresse d'un int Un pointeur peut être sans type. Dans ce cas, on le déclare par void *p; 3.2.2 Opérations L'opérateur * permet d'accéder à la valeur pointée. JCG 12/21 ESIEE IN3T01 Abrégé de langage C L'opérateur & permet d'obtenir l'adresse d'une l_value. Par exemple, int n,z; int *pn; La déclaration a pour effet d'attribuer des emplacement ici A1, A2 et A3 : variable n z adresse mémoire A1 A2 contenu indéterminé indéterminé 2010/2011 mémoire aux variables, notées pn A3 indéterminé pn = &n; En A3, on stocke la valeur A1 (l'adresse de n) variable adresse mémoire contenu n A1 indéterminé z A2 indéterminé pn A3 A1 z A2 indéterminé pn A3 A1 n = 3; En A1, on stocke 3 variable n adresse mémoire A1 3 contenu Les variables n et pn sont initialisées. Voyons maintenant les opérations éventuelles : z = *pn; *pn en tant que valeur signifie la valeur à l'adresse indiquée par le contenu de pn Le contenu de pn vaut A1. La valeur en A1 est 3, donc z vaut 3 variable adresse mémoire contenu n A1 3 z A2 3 pn A3 A1 *pn = 5 *pn, en tant que l_value signifie la l_value située à l'adresse indiquée par de pn pn vaut A1. A1 contiendra donc la valeur 5 variable adresse mémoire contenu JCG n A1 5 z A2 3 13/21 pn A3 A1 ESIEE IN3T01 Abrégé de langage C 2010/2011 Pour un pointeur unique sur un type simple, les trois opérations possibles sont : pointeur = &l_value; /* modifie la valeur du pointeur */ *pointeur = expr; /* modifie la valeur de l'objet pointé */ l_value = *pointeur; /* évalue la valeur de l'objet pointé */ 3.2.3 Pointeurs et tableaux Pointeurs et tableaux sont très liés : char *cp; char colonne[80]; cp = &tampon[0] ou cp = tampon sont équivalentes. cp pointe sur le premier élément du tableau. De même, cp = &tampon[4] ou cp = tampon + 4 sont équivalentes. cp pointe sur le cinquième élément du tableau 3.2.4 Arithmétique sur les pointeurs L'arithmétique sur les pointeurs dépend du type pointé. Si p est un pointeur de type X, p+1 pointera sur l'élément suivant d'un tableau fictif de X commençant en p. 3.2.5 Exemples de fonctions void echanger(int *pi, int *pj) { int z; z = *pi; *pi = *pj; *pj =z; } appelée par #include <stdio.h> int main() { int a=2, b=3; printf("Avant échange, a=%d b=%d\n", a, b); echanger(&a,&b); printf("Après échange, a=%d b=%d\n", a, b); return 0; } JCG 14/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 void strcpy(char *ch1, char *ch2) { /* ch1 doit disposer d'assez de place contenir ch2 */ while (*ch1++ = *ch2++) ; } appelée par #include <stdio.h> int main() { char a[5] = "toto"; char *b = "titi"; printf("Avant copie, a=%s b=%s\n", a, b); strcpy(a, b); printf("Après copie, a=%s b=%s\n", a, b); return 0; } 3.2.6 pour Allocation dynamique de mémoire Un pointeur n'est pas obligé d'être initialisé par l'affectation d'une adresse de l_value. L'allocation dynamique de mémoire permet de demander au système de la mémoire pour contenir des objets créés par le programme. La fonction void *malloc(int n) demande au système n octets contigus et retourne l'adresse de ces octets. ptr = malloc(100); Cette mémoire peut être restituée par un appel à la fonction free free(ptr); rend la mémoire occupée par l'objet pointé par ptr. 3.3 Structures et unions Une structure sert à regrouper des éléments de types différents. Par exemple, struct personne { char nom[20]; int age; } struct personne p[10], x, y; déclarera un tableau p de 10 personne et deux variables x et y de type personne. Pour accéder à un des champs d'une structure, on utilise l'opérateur . (un point) x.nom sera le tableau de 20 caractères correspondant au nom de x x.age sera l'entier correspondant à l'age de x. strcpy(x.nom, "toto"); x.age = 10; JCG 15/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 Un pointeur peut pointer sur un objet de type structure : struct personne *pp; pp = &x; L'accès aux champs de la structure pointée se fait par l'opérateur -> : p->age est équivalent à (*p).age On met des parenthèses, car . est plus prioritaire que * : *p.age <=> *(p.age) Les structures peuvent contenir des références à elles-mêmes par l'intermédiaire de pointeurs : struct elt_liste { char c; struct elt_liste *suivant; }; Dans ce cas, un élément de liste contiendra un caractère et un pointeur sur l'élément de liste suivant. Une union est semblable à une structure, dans le sens où elle contient des objets de types différents, mais un seul à la fois. union nombre { int i; float r; } x; Les champs i et r seront deux façons de consulter ou de modifier le contenu de x. x.i = 2; x.r = 3.14; /* écrase la mémoire occupée par la valeur 3.14 */ Attention : le langage C ne se souvient pas du type de la dernière valeur mémorisée dans une union : c'est au programme de s'en souvenir. 4 Le préprocesseur C Avant de compiler un programme, le compilateur C lance un préprocesseur qui modifie le texte de programme en fonction de directives ( les lignes commençant par #). Une de ses premières tâches est d'éliminer les commentaires (entre /* et */) JCG 16/21 ESIEE IN3T01 4.1 Abrégé de langage C 2010/2011 Constantes et macros #define identificateur objet remplacera dans le texte du programme (sauf dans les chaînes de caractères) identificateur par objet (identificateur, constante, chaîne, opérateur, signe de ponctuation) #define NB_COL 80 #define ATTENTION_COL (NB_COL - 10) Les parenthèses sont mises ici pour éviter que les remplacements dans le texte aient un effet non désiré. if (ATTENTION_COL * 2 < 100) .... sera remplacé mot à mot if ((NB_COL - 10) * 2 < 100) .... lui-même remplacé par if ((80 - 10) * 2 < 100) .... L'effet aurait été différent sans les parenthèses #define identificateur(arguments) chaîne remplacera toutes les occurrences de identificateur(....) par la chaîne dans laquelle les arguments seront remplacés par les valeurs lues dans le programme : #define max(a,b) ( (a) > (b) ? (a) : (b) ) 4.2 Inclusion de fichier #include "nom_fichier" sera remplacé par le contenu du fichier, cherché dans le catalogue courant, puis dans les catalogues système #include <nom_fichier> sera remplacé par le contenu du fichier, cherché dans les catalogues système 4.3 Compilation conditionnelle Elle permet de disposer de sources qui pourront se compiler sur des machines et/ou des compilateurs différents, à condition de distinguer les différences dans le texte du programme. #if condition texte1 #else texte2 #endif permet de compiler l'un ou l'autre des textes suivant que la condition est vérifiée ou non. #ifdef identificateur texte #endif Le texte ne sera compilé que si identificateur a fait l'objet d'une directive #define (même vide) JCG 17/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 5 La bibliothèque standard du langage C À chaque fichier accédé par un programme est associé un ensemble de tampons d'entrée-sortie. Le couple fichier-tampon est un flux (stream), désignée par un pointeur sur le type FILE, prédéfini dans stdio.h, qui définit également les trois pointeurs sur les flux généralement ouverts : stdin, stdout et stderr (entrée, sortie et sortie erreur standard), la constante NULL (absence de flux) et EOF (utilisée comme résultat lors de la fin de fichier). 5.1 La fonction printf int printf ("format", expr1, expr2, ....) Précise un format (sous forme de chaîne de caractères) pour les données en sortie. Les éléments de la chaîne formats qui ne sont pas précédés de % sont sortis tels quels. Les formats disponibles sont les suivants : format %c %d %f %o %s %u %x %% affichage sous forme caractère entier décimal flottant entier octal chaîne de caractères entier non signé entier hexadécimal le caractère % Tableau 11 : formats de printf Si # est un des formats ci-dessus, format affichage sous forme %l# type long %-# cadrage à gauche %3#f sur au moins trois positions %.12# • pour un entier, le nombre de chiffres à afficher (ici 12) • pour un réel, le nombre de chiffres de la partie décimale à afficher (avec arrondi) • pour une chaînes, le nombre maximum de caractères à afficher. Tableau 12 : préfixes des formats de printf 5.2 La fonction scanf int scanf("format",adr_var1, adr_var2, ....) JCG 18/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 correspond à printf, mais pour les entrées. En plus, le préfixe de format * permet d'ignorer un champ d'entrée. Par exemple, int i; float x; char nom[50]; scanf("%d %f %s', &i, &x, nom); /* l'entrée 25 54.32e-1 Thompson affectera 25 à i, 5.432 à x et "Thompson" à nom */ scanf(%2d %f %*d %2s", &i, &x, nom); /* l'entrée 56789 0123 45a72 affectera 56 à i, 789.0 à x, ignorera 0123, "45" à nom. Le prochain caractère lu sera 'a' */ JCG 19/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 Index des tableaux Tableau 1 : les mots réservés du C..............................................................................................4 Tableau 2 : les constantes caractères spéciales...........................................................................5 Tableau 3 : les opérateurs arithmétiques.....................................................................................6 Tableau 4 : les comparateurs arithmétiques................................................................................6 Tableau 5 : les opérateurs d'égalité.............................................................................................6 Tableau 6 : les opérateurs de décalage........................................................................................7 Tableau 7 : les opérateurs bit à bit..............................................................................................7 Tableau 8 : les opérateurs logiques.............................................................................................7 Tableau 9 : les opérateurs unaires...............................................................................................8 Tableau 10 : priorités des opérateurs..........................................................................................9 Tableau 11 : formats de printf...................................................................................................18 Tableau 12 : préfixes des formats de printf...............................................................................19 Table des matières 1 La syntaxe C....................................................................................................4 1.1 Les règles d'écriture..........................................................................4 1.1.1 Commentaires et espaces...................................................4 1.1.2 Les identificateurs..............................................................4 1.1.3 Les types simples...............................................................4 1.1.4 Les constantes....................................................................5 1.1.5 Les variables......................................................................6 1.2 Les expressions et les opérateurs......................................................6 1.2.1 Les opérateurs arithmétiques.............................................6 1.2.2 Les opérateurs relationnels................................................6 1.2.3 Les opérateur d'égalité et d'inégalité..................................6 1.2.4 Les opérateurs de décalage................................................6 1.2.5 Les opérateurs bit à bit.......................................................7 1.2.6 Les opérateurs logiques.....................................................7 1.2.7 L'opérateur virgule ............................................................7 1.2.8 Les opérateurs d'affectation...............................................7 1.2.9 L'opérateur conditionnel....................................................7 1.2.10 Les opérateurs unaires.....................................................8 1.2.11 La conversion de type......................................................8 1.2.12 Priorité et ordre d'évaluation............................................8 2 Le contrôle du programme..............................................................................9 2.1 Les instructions de contrôle..............................................................9 2.1.1 L'instruction if....................................................................9 2.1.2 L'instruction switch............................................................9 2.1.3 Les itérations ...................................................................10 2.2 Les fonctions...................................................................................10 JCG 20/21 ESIEE IN3T01 Abrégé de langage C 2010/2011 3 Les types composés et les pointeurs .............................................................12 3.1 Les tableaux....................................................................................12 3.2 Les pointeurs...................................................................................12 3.2.1 Définition.........................................................................12 3.2.2 Opérations........................................................................12 3.2.3 Pointeurs et tableaux .......................................................14 3.2.4 Arithmétique sur les pointeurs.........................................14 3.2.5 Exemples de fonctions.....................................................14 3.2.6 Allocation dynamique de mémoire..................................15 3.3 Structures et unions.........................................................................15 4 Le préprocesseur C........................................................................................17 4.1 Constantes et macros......................................................................17 4.2 Inclusion de fichier.........................................................................17 4.3 Compilation conditionnelle............................................................18 5 La bibliothèque standard du langage C.........................................................18 5.1 La fonction printf............................................................................18 5.2 La fonction scanf............................................................................19 JCG 21/21