From 5a3abc94d4238ae0c1a1c95c4e0dd7cddcbb3ebb Mon Sep 17 00:00:00 2001 From: Cyril Jovet Date: Fri, 12 Apr 2024 13:15:25 +0200 Subject: [c/fr] C French translation (#3972) * [c/fr] C French translation New C French translation c-fr.html.markdown file * Update c-fr.html.markdown --------- Co-authored-by: ven --- fr-fr/c-fr.html.markdown | 839 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 fr-fr/c-fr.html.markdown (limited to 'fr-fr') diff --git a/fr-fr/c-fr.html.markdown b/fr-fr/c-fr.html.markdown new file mode 100644 index 00000000..1fe80f07 --- /dev/null +++ b/fr-fr/c-fr.html.markdown @@ -0,0 +1,839 @@ +--- +language: c +filename: learnc.c +contributors: + - ["Adam Bard", "http://adambard.com/"] + - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"] + - ["Jakub Trzebiatowski", "http://cbs.stgn.pl"] + - ["Marco Scannadinari", "https://marcoms.github.io"] + - ["Zachary Ferguson", "https://github.io/zfergus2"] + - ["himanshu", "https://github.com/himanshu81494"] + - ["Joshua Li", "https://github.com/JoshuaRLi"] + - ["Dragos B. Chirila", "https://github.com/dchirila"] + - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"] +translators: + - ["Cyril Jovet", "https://twitter.com/CyrilJovet"] +lang: fr-fr +--- + +Le C est le langage de plus bas niveau que la plupart des programmeurs seront +amenés à utiliser, mais ceci est largement conpensé par sa vitesse brute. + +> **À propos des options de compilation** +> +> Par défaut, gcc et clang sont assez silencieux sur les avertissements et +> les erreurs de compilation, qui peuvent être des informations très utiles. +> L'utilisation explicite d'options de compilation plus strictes est recommandée. +> Voici quelques valeurs par défaut recommandées: +> +> `-Wall -Wextra -Werror -O2 -std=c99 -pedantic` +> +> Pour plus d'informations sur ce que font ces options ainsi que sur d'autres, +> vous pouvez consulter la page du manuel de votre compilateur C (par exemple `man 1 gcc`) +> ou recherchez simplement en ligne. + +```c +// Les commentaires sur une ligne commencent par // - valable seulement pour C99 et plus tard. + +/* +Les commentaires multilignes resemblent à ceci. Ils restent valables en C89. +*/ + +/* +Les commentaires multilignes ne s'emboîtent pas /* Attention */ // Le commentaire se termine sur cette ligne... +*/ // ...pas ici ! + +// Constante : #define +// Les constantes sont écrites en majuscules par convention, pas d'obligation +#define DAYS_IN_YEAR 365 + +// Les constantes d'énumeration sont aussi une façon de déclarer des valeurs. +// Toutes les instructions doivent se terminer par un point-virgule. +enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; +// MON vaut 2 automatiquement, TUE vaut 3, etc. + +// Import de fichiers d'en-tête avec #include +#include +#include +#include + +// Pour vos propres fichiers d'en-tête, utilisez les doubles quotes au lieu des crochets sup. et inf.: +//#include "my_header.h" + +// Declarez les signatures des fonctions auparavant dans un fichier .h, ou en haut de votre +// fichier .c. +void function_1(); +int function_2(void); + +// Si vous voulez appeler une fonction avant de la définir, +// vous pouvez déclarer son prototype +// (types des arguments et de la valeur renvoyée) +int add_two_ints(int x1, int x2); // prototype de la fonction +// bien que `int add_two_ints (int, int);` soit également valide (pas besoin de nommer les arguments), +// il est recommandé de nommer les arguments dans le prototype pour faciliter l'inspection. + +// Le point d'entrée de votre programme est une fonction appélée +// main avec une sortie de type entier. +int main(void) { + // votre programme +} + +// Les arguments de la ligne de commande utilisés pour exécuter votre programme sont également passés à la fonction main +// argc étant le nombre d'arguments - le nom de votre programme compte pour 1 +// argv est un tableau de tableaux de caractères - contenant les arguments eux-mêmes +// argv[0] = nom de votre programme, argv[1] = premier argument, etc. +int main (int argc, char** argv) +{ + // écriture en sortie à l'aide de printf, pour "print formatted" + // %d est un entier, \n est une nouvelle ligne + printf("%d\n", 0); // => Prints 0 + + /////////////////////////////////////// + // Types + /////////////////////////////////////// + + // Les compilateurs qui ne sont pas conformes C99 nécessitent de déclarer + // les variables en début de portée du bloc de code courant. + // Les compilateurs qui SONT conformes C99 acceptent les déclarations + // plus tard dans les fonctions. + + // Les entiers font généralement de 4 octets + int x_int = 0; + + // Les entiers courts font généralement 2 octets + short x_short = 0; + + // Les caractères ont une taille fixée à 1 octet + char x_char = 0; + char y_char = 'y'; // les caractères littéraux sont entre apostrophes '' + + // Les entiers longs font généralement 4 à 8 octets; les entiers longs de type long font + // 8 octets + long x_long = 0; + long long x_long_long = 0; + + // les nombres à virgule sont généralement des nombres à virgule flottantes de 32 bits + float x_float = 0.0f; // 'f' est le suffixe qui indique ici le littéral à virgule flottante + + // les nombres de type double sont généralement des nombres à virgule flottante de 64 bits + double x_double = 0.0; // les nombres réels sans suffixe sont de type double + + // Les types entier peuvent être non signés (plus grand ou égal à zero) + unsigned short ux_short; + unsigned int ux_int; + unsigned long long ux_long_long; + + // Les caractères entre guillemets simples sont des entiers d'un jeu de caractères machine. + '0'; // => 48 dans le jeu de caractères ASCII. + 'A'; // => 65 dans le jeu de caractères ASCII. + + // sizeof(T) vous rend la taille d'une variable de type T en octets. + // sizeof obj revoie la taille en sortie de l'expression (variable, littéral, etc.). + printf("%zu\n", sizeof(int)); // => 4 (sur la plupart des machines les mots font 4 octets) + + // Si l'argument de l'opérateur `sizeof` est une expression, alors son argument + // n'est pas évalué (sauf les VLA - voir ci-dessous). + // La valeur qu'elle donne dans ce cas est une constante évaluée à la compilation. + int a = 1; + // size_t est un type entier non signé d'au moins 2 octets utilisé pour représenter + // la taille d'un objet. + size_t size = sizeof(a++); // a++ n'est pas évalué + printf("sizeof(a++) = %zu où a = %d\n", size, a); + // affiche "sizeof(a++) = 4 où a = 1" (sur une architecture 32 bits) + + // Si l'argument de l'opérateur `sizeof` est une expression, alors son argument + // n'est pas évalué (sauf les VLAs (voir ci-dessous)). + // La valeur qu'elle donne dans ce cas est une constante évaluée au moment de la compilation. + int a = 1; + // size_t est un nombre de type entier non signé dont au moins 2 octets sont utilisés pour représenter + // la taille d'un objet. + size_t size = sizeof(a++); // a++ n'est pas évalué + printf("sizeof(a++) = %zu where a = %d\n", size, a); + // affiche "sizeof(a++) = 4 where a = 1" (sur une architecture 32-bit) + + // Les tableaux doivent être initialisés avec une taille concrète. + char my_char_array[20]; // Ce tableau occupe 1 * 20 = 20 octets + int my_int_array[20]; // Ce tableau occupe 4 * 20 = 80 octets + // (en considérant des mots de 4 octets) + + // Vous pouvez ainsi initialiser un tableau à 0: + char my_array[20] = {0}; + // où la partie "{0}" est appelée "initialiseur de tableau". + // NOTEZ que vous vous en sortez sans déclarer explicitement la taille du tableau, + // SI vous initialisez le tableau sur la même ligne. Ainsi, la déclaration suivante + // est équivalent: + char my_array[] = {0}; + // MAIS, alors vous devez évaluer la taille du tableau au moment de l'exécution, comme ceci: + size_t my_array_size = sizeof(my_array) / sizeof(my_array[0]); + // ATTENTION Si vous adoptez cette approche, vous devez évaluer la taille *avant* + // qui vous commenciez à transmettre le tableau à la fonction (voir la discussion ultérieure), car + // les tableaux sont "rétrogradés" en pointeurs bruts lorsqu'ils sont passés à des fonctions + // (donc l'instruction ci-dessus produira le mauvais résultat à l'intérieur de la fonction). + + // L'indexation commence à zero et utilise [] + my_array[0]; // => 0 + + // Les tableaux sont modifiables ; c'est juste de la mémoire! + my_array[1] = 2; + printf("%d\n", my_array[1]); // => 2 + + // En C99 (et optionnellement en C11), des tableaux à taille variable (VLAs) + // peuvent également être déclarés. La taille d'un tel tableau n'a pas besoin d'être + // une constante définie lors de la compilation: + printf("Enter the array size: "); // demande à l'utilisateur la taille du tableau + int array_size; + fscanf(stdin, "%d", &array_size); + int var_length_array[array_size]; // déclare le VLA + printf("sizeof array = %zu\n", sizeof var_length_array); + + // Exemple: + // > Enter the array size: 10 + // > sizeof array = 40 + + // Les chaînes de caractères sont juste des tableaux de caractères de terminant par octet NULL (0x00), + // représenté dans les chaînes de caractères par le caractère spécial '\0'. + // (Nous n'avons pas besoin d'ajouter l'octet NULL dans les chaînes de caractères littérales; le compilateur + // l'ajoute à la fin du tableau pour nous.) + char a_string[20] = "This is a string"; + printf("%s\n", a_string); // %s insère une chaîne de caractères + + printf("%d\n", a_string[16]); // => 0 + // i.e., l'octet #17 est 0 (comme le sont 18, 19, et 20) + + // Si nous avons un caractère entre apostrophes, c'est un caractère littéral. + // Ils sont de types `int`, et *non* `char` (pour des raisons historiques). + int cha = 'a'; // bon + char chb = 'a'; // bon aussi (conversion implicite de int vers char) + + // Tableaux dimension multiple: + int multi_array[2][5] = { + {1, 2, 3, 4, 5}, + {6, 7, 8, 9, 0} + }; + // Accés au éléments: + int array_int = multi_array[0][2]; // => 3 + + /////////////////////////////////////// + // Operateurs + /////////////////////////////////////// + + // Raccourcis pour plusieurs déclarations: + int i1 = 1, i2 = 2; + float f1 = 1.0, f2 = 2.0; + + int b, c; + b = c = 0; + + // Arithmétique + i1 + i2; // => 3 + i2 - i1; // => 1 + i2 * i1; // => 2 + i1 / i2; // => 0 (0.5, mais tronqué après 0) + + // Vous devez convertir un entier en type 'float' pour obtenir un résultat en virgule flottante + (float)i1 / i2; // => 0.5f + i1 / (double)i2; // => 0.5 // Pareil avec double + f1 / f2; // => 0.5, plus ou moins epsilon + // Les nombres à virgule flottante et leurs calculs ne sont pas exacts + + // Modulo est aussi là + 11 % 3; // => 2 + + // Les opérateurs de comparaison sont probablement familiers, mais + // il n'y a pas de type booléen en C. On utilise plutôt des entiers + // (C99 introduit _Bool ou bool). + // 0 est faux, tout le reste est vrai. + // (La comparaison les opérateurs donnent toujours 0 ou 1) + 3 == 2; // => 0 (faux) + 3 != 2; // => 1 (vrai) + 3 > 2; // => 1 + 3 < 2; // => 0 + 2 <= 2; // => 1 + 2 >= 2; // => 1 + + // C n'est pas Python - les comparaisons ne s'enchaînent pas. + // Attention : la ligne ci-dessous se compilera, mais cela signifie `(0 < a) <2`. + // Cette expression est toujours vraie, car (0 < a) peut être 1 ou 0. + // Dans ce cas, c'est 1, car (0 < 1). + int between_0_and_2 = 0 < a < 2; + // Utilisez plutôt: + int between_0_and_2 = 0 < a && a < 2; + + // La logique fonctionne avec les entiers + !3; // => 0 (non logique) + !0; // => 1 + 1 && 1; // => 1 (et logique) + 0 && 1; // => 0 + 0 || 1; // => 1 (ou logique) + 0 || 0; // => 0 + + // Expression conditionnelle ternaire ( ? : ) + int e = 5; + int f = 10; + int z; + z = (e > f) ? e : f; // => 10 "if e > f return e, else return f." + + // Opérateurs d'incrémentation et de décrémentation : + int j = 0; + int s = j++; // Renvoi j PUIS augmente j. (s = 0, j = 1) + s = ++j; // Augmente j PUIS revoi j. (s = 2, j = 2) + // pareil avec j-- et --j + + // Opérateurs de manipulation des bits ! + ~0x0F; // => 0xFFFFFFF0 (opérateur de négation, "complémentaire de 1", exemple d'un résultat pour un entier 32-bit) + 0x0F & 0xF0; // => 0x00 (opérateur AND) + 0x0F | 0xF0; // => 0xFF (opérateur OR) + 0x04 ^ 0x0F; // => 0x0B (opérateur XOR) + 0x01 << 1; // => 0x02 (opérateur de décalage à gauche - de 1) + 0x02 >> 1; // => 0x01 (opérateur de décalage à droite - de 1) + + // Soyez prudent lorsque vous effectuez un décalage sur des entiers signés - les éléments suivants ne sont pas définis: + // - décalage du bit de signe d'un entier signé (int a = 1 << 31) + // - décalage à gauche d'un nombre négatif (int a = -1 << 2) + // - décalage par un offset qui est >= à la largeur du type LHS (partie de gauche de l'affectation): + // int a = 1 << 32; // UB (comportement indéfini) si int a une taille de 32 bits + + /////////////////////////////////////// + // Structures de contrôle + /////////////////////////////////////// + + if (0) { + printf("Je ne serai jamais exécuté\n"); + } else if (0) { + printf("Moi aussi, je ne serai jamais exécuté\n"); + } else { + printf("Je suis affiché\n"); + } + + // Les boucles while + int ii = 0; + while (ii < 10) { // TOUTE valeur plus petite que dix est vraie. + printf("%d, ", ii++); // ii++ augmente ii APRES avoir utilisé sa valeur actuelle. + } // => affiche "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + int kk = 0; + do { + printf("%d, ", kk); + } while (++kk < 10); // ++kk augmente kk AVANT d'utiliser sa valeur actuelle. + // => affiche "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // Les boucles for + int jj; + for (jj=0; jj < 10; jj++) { + printf("%d, ", jj); + } // => affiche "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " + + printf("\n"); + + // *NOTES* : + // Les boucles et les fonctions DOIVENT posséder un corps. + // Vous pouvez toutefois utiliser un bloc vide ({}) ou un point-virgule. + int i; + for (i = 0; i <= 5; i++) { + } + // Ou + for (i = 0; i <= 5; i++); // Déconseillé, car facilement confondable + + // condition à choix multiples : switch() + switch (a) { + case 0: // les options doivent être des expressions intégrales *constantes* (telles que des énumérations) + printf("Hey, 'a' equals 0!\n"); + break; // si vous ne mettez pas 'break', le cas d'après est exécuté sans tester le `case` + case 1: + printf("Huh, 'a' equals 1!\n"); + break; + // Attention - sans le "break", l'execution se poursuit jusqu'au + // prochain "break" atteint. + case 3: + case 4: + printf("Look at that.. 'a' is either 3, or 4\n"); + break; + default: + // si `a` ne correspond à aucune option + fputs("Erreur !\n", stderr); + exit(-1); + break; + } + + // Utilisation de "goto" en C + typedef enum { false, true } bool; + bool disaster = false; + int i, j; + for(i=0; i<100; ++i) + for(j=0; j<100; ++j) + { + if (i + j >= 150) + disaster = true; + if (disaster) + goto error; + } + error: + printf("Error occurred at i = %d & j = %d.\n", i, j); + // Ceci affichera "Error occurred at i = 51 & j = 99." + + /////////////////////////////////////// + // Transtypage + /////////////////////////////////////// + + // Chaque valeur de C a un type, mais vous pouvez convertir le type d'une valeur en un autre type + // si vous le souhaitez (avec quelques contraintes). + + int x_hex = 0x01; // Vous pouvez définir des variables avec des littéraux hexadécimaux + + // La conversion entre les types tentera de conserver leurs valeurs numériques + printf("%d\n", x_hex); // => Affiche 1 + printf("%d\n", (short) x_hex); // => Affiche 1 + printf("%d\n", (char) x_hex); // => Affiche 1 + + // Les types déborderont sans avertissement + printf("%d\n", (unsigned char) 257); // => 1 (max = 255 si le caractère mesure 8 bits) + + // Pour déterminer la valeur maximale d'un `char`, d'un `signed char` et d'un `unsigned char`, + // respectivement, utilisez les macros CHAR_MAX, SCHAR_MAX et UCHAR_MAX de + + // Les types entiers peuvent être convertis en types à virgule flottante et vice versa. + printf("%f\n", (double) 100); // %f toujours utilisé pour un type double... + printf("%f\n", (float) 100); // ...même avec un float. + printf("%d\n", (char)100.0); + + /////////////////////////////////////// + // Pointeurs + /////////////////////////////////////// + + // Un pointeur est une variable déclarée pour stocker une adresse mémoire. Sa déclaration + // vous indique également le type de données vers lequel il pointe. Vous pouvez récupérer l'adresse mémoire + // de vos variables, puis jouer avec. + + int x = 0; + printf("%p\n", (void *)&x); // Utilisez le caractère & pour récupérer l'adresse d'une variable + // (%p met en forme un objet pointeur de type void *) + // => Affiche une adresse en mémoire; + + // Les pointeurs sont préfixés du caractère * lors de la déclaration + int *px, not_a_pointer; // px est un pointeur sur un entier + px = &x; // Sauvegarde de l'adressse mémoire de x dans px + printf("%p\n", (void *)px); // => Affiche une adresse mémoire + printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); + // => Affiche "8, 4" sur un système classique 64-bit + + // Pour avoir la valeur située à l'adresse du pointeur, + // on met * devant pour le déréférencer. + // Remarque: oui, il peut être déroutant que '*' soit utilisé pour _les deux_ déclarer un + // pointeur et le déréférencement. + printf("%d\n", *px); // => Affiche 0, la valeur de x + + // Vous pouvez également modifier la valeur vers laquelle pointe le pointeur. + // Nous devons mettre la déréférence entre parenthèses car + // ++ a une priorité plus élevée que *. + (*px)++; // Augmente de 1 la valeur pointée par px + printf("%d\n", *px); // => Affiche 1 + printf("%d\n", x); // => Affiche 1 + + // Les tableaux sont un bon moyen d'allouer un bloc de mémoire contigu + int x_array[20]; //déclare un tableau de taille 20 (la taille ne pourra être changée) + int xx; + for (xx = 0; xx < 20; xx++) { + x_array[xx] = 20 - xx; + } // Initialise x_array à 20, 19, 18,... 2, 1 + + // Declare un pointeur sur un type entier et l'initialise pour pointer sur x_array + int* x_ptr = x_array; + // x_ptr pointe maintenant vers le premier élément du tableau (l'entier 20). + // Cela fonctionne car les tableaux s'interprètent souvent comme pointeurs vers leur premier élément. + // Par exemple, lorsqu'un tableau est transmis à une fonction ou affecté à un pointeur, + // il est converti implicitement en pointeur. + // Exceptions : lorsque le tableau est l'argument de l'opérateur `&` (adresse de): + int arr[10]; + int (*ptr_to_arr)[10] = &arr; // &arr n'est PAS de type `int *`! + // Il est de type "pointeur sur tableau" (de dix entiers). + // ou losqu'une chaine de caractères littérale est utilisée pour initialiser un tableau de caractères: + char otherarr[] = "foobarbazquirk"; + // ou lorsqu'il est l'argument de l'opérateur `sizeof` ou `alignof`: + int arraythethird[10]; + int *ptr = arraythethird; // équivalent à int *ptr = &arr[0]; + printf("%zu, %zu\n", sizeof(arraythethird), sizeof(ptr)); + // affiche probablement "40, 4" ou "40, 8" + + // L'augmentation ou la diminution d'un pointeur se fait suivant son type + // (c'est ce qu'on appelle l'arithmétique du pointeur) + printf("%d\n", *(x_ptr + 1)); // => Affiche 19 + printf("%d\n", x_array[1]); // => Affiche 19 + + // You can also dynamically allocate contiguous blocks of memory with the + // standard library function malloc, which takes one argument of type size_t + // representing the number of bytes to allocate (usually from the heap, although this + // may not be true on e.g. embedded systems - the C standard says nothing about it). + // Vous pouvez également allouer dynamiquement des blocs de mémoire contigus avec la + // fonction malloc de la bibliothèque standard, qui prend un argument de type size_t + // représentant le nombre d'octets à allouer (généralement à partir du tas, bien que cela + // peut ne pas être vrai par exemple dans les systèmes embarqués - la norme C ne dit rien à ce sujet). + int *my_ptr = malloc(sizeof(*my_ptr) * 20); + for (xx = 0; xx < 20; xx++) { + *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx + } // Initialise la mémoire à 20, 19, 18, 17... 2, 1 (comme entiers) + + // Soyez prudent en passant des valeurs fournies par l'utilisateur à malloc! Si vous le souhaitez + // pour plus de sécurité, vous pouvez utiliser calloc à la place (qui, contrairement à malloc, met également à zéro la mémoire) + int* my_other_ptr = calloc(20, sizeof(int)); + + // Notez qu'il n'y a pas de méthode standard pour obtenir la longueur d'un + // tableau alloué dynamiquement en C. Pour cette raison, si vos tableaux sont + // manipulés par votre programme, vous avez besoin d'une autre variable + // pour garder une trace du nombre d'éléments (taille) d'un tableau. Voir la + // section fonctions pour plus d'informations. + size_t size = 10; + int *my_arr = calloc(size, sizeof(int)); + // Add an element to the array + size++; + my_arr = realloc(my_arr, sizeof(int) * size); + if (my_arr == NULL) { + //N'oubliez pas de vérifier l'échec de la fonction realloc! + return 0; + } + my_arr[10] = 5; + + // Déréférencer de la mémoire que vous n'avez pas allouée donne des + // UBs "undefined behaviors" ou "comportement imprévisibles", + printf("%d\n", *(my_ptr + 21)); // => Peut crash, afficher n'importe quoi, ou autre + + // Lorsque vous avez terminé avec un bloc de mémoire alloué via malloc, vous devez le libérer, + // ou bien personne d'autre ne pourra l'utiliser jusqu'à la fin de votre programme : + // (cela s'appelle une "fuite de mémoire") + free(my_ptr); + + // Les chaînes de caractères sont des tableaux de caractères, mais ils sont généralement représentés comme + // pointeur-vers-caractère (qui est un pointeur vers le premier élément du tableau). + // Il est recommandé d'utiliser un `const char *' pour référencer une chaîne littérale de caractères, + // car les chaînes de caractères littérales ne doivent pas être modifiées (i.e. "foo"[0] = 'a' est INCORRECT.) + const char *my_str = "This is my very own string literal"; + printf("%c\n", *my_str); // => 'T' + + // Ce n'est pas le cas si la chaîne de caractères est un tableau + // (potentiellement initialisée avec une chaîne littérale) + // qui réside dans la mémoire réinscriptible, comme dans: + char foo[] = "foo"; + foo[0] = 'a'; // ceci est correct, foo contient maintenant "aoo" + + function_1(); +} // fin de la fonction main + +/////////////////////////////////////// +// Fonctions +/////////////////////////////////////// + +// Sytaxe pour déclarer une fonction: +// () + +int add_two_ints(int x1, int x2) +{ + return x1 + x2; // Utilisez return pour retourner une valeur de sortie +} + +/* +Les fonctions sont appelées par valeur. Lorsqu'une fonction est appelée, les arguments passés à +à la fonction sont une copie des arguments originaux (sauf pour les tableaux). Tout ce que vous +allez faire aux arguments de la fonction ne changera pas la valeur des arguments +originaux avant appel de la fonction. + +Utilisez les pointeurs si vous avez besoin de modifier la valeur d'origine des arguments. + +Exemple : inversion sur place d'une chaîne de caractères +*/ + +// Une fonction void ne retourne aucune valeur +void str_reverse(char *str_in) +{ + char tmp; + size_t ii = 0; + size_t len = strlen(str_in); // `strlen()` fait partie de la bibliothèque standard c + // REMARQUE : la longueur renvoyée par `strlen` N'INCLUT PAS + // l'octet NULL de fin ('\0'). + for (ii = 0; ii < len / 2; ii++) { // en C99 vous pouvez déclarer directement le type de `ii` ici + tmp = str_in[ii]; + str_in[ii] = str_in[len - ii - 1]; // ii-ème caractère depuis la fin + str_in[len - ii - 1] = tmp; + } +} +// REMARQUE : le fichier d'entête string.h a besoin d'être inclus pour utiliser strlen() + +/* +char c[] = "This is a test."; +str_reverse(c); +printf("%s\n", c); // => ".tset a si sihT" +*/ +/* +car nous ne pouvons renvoyer qu'une seule variable +pour changer les valeurs de plusieurs variables, nous passons des pointeurs +*/ +void swapTwoNumbers(int *a, int *b) +{ + int temp = *a; + *a = *b; + *b = temp; +} +/* +int first = 10; +int second = 20; +printf("first: %d\nsecond: %d\n", first, second); +swapTwoNumbers(&first, &second); +printf("first: %d\nsecond: %d\n", first, second); +// les valeurs seront échangées +*/ + +/* +En ce qui concerne les tableaux, ils seront toujours transmis aux fonctions +comme pointeurs. Même si vous allouez statiquement un tableau comme `arr[10]`, +il est toujours passé en tant que pointeur vers le premier élément de tout appel de fonction. +Encore une fois, il n'y a pas de moyen standard pour connaître la taille d'un tableau +alloué dynamiquement en C. +*/ +// La taille doit être transmise! +// Sinon, cette fonction n'a aucun moyen de connaître la taille du tableau. +void printIntArray(int *arr, size_t size) { + int i; + for (i = 0; i < size; i++) { + printf("arr[%d] is: %d\n", i, arr[i]); + } +} +/* +int my_arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; +int size = 10; +printIntArray(my_arr, size); +// affichera "arr[0] is: 1" etc +*/ + +// si vous faites référence à des variables externes en dehors de la fonction, vous devez utiliser le mot clé extern. +int i = 0; +void testFunc() { + extern int i; //i ici utilise la variable externe i +} + +// rendre les variables external privées au fichier source avec static: +static int j = 0; //les autres fichiers utilisant testFunc2() n'auront pas accés à la variable j +void testFunc2() { + extern int j; +} + +// Le mot clé static rend une variable inaccessible au code en dehors de +// l'unité de compilation. (Sur presque tous les systèmes, une "unité de compilation" est un +// fichier .c.) static peut être appliqué aussi bien aux variables globales (à l'unité de compilation), +// aux fonctions et aux variables locales aux fonctions. Lorsque vous utilisez static avec +// une variable locale à une fonction, la variable est effectivement globale et conserve sa +// valeur sur les appels de la fonction, mais n'est accessible que dans la fonction où +// elle a été déclarée. De plus, les variables statiques sont initialisées à 0 si pas +// déjà déclaré avec une autre valeur de départ. +// ** Vous pouvez également déclarer des fonctions statiques pour les rendre privées ** + +///////////////////////////////////////////////// +// Types et structures définis par l'utilisateur +///////////////////////////////////////////////// + +// Typedef peuvent être utilisé pour créer un alias de type +typedef int my_type; +my_type my_type_var = 0; + +// Struct est juste une collection de données, dont les membres sont positionnés séquentiellement, +// dans l'ordre où ils sont écrits:: +struct rectangle { + int width; + int height; +}; + +// Il n'est généralement aps vrai que +// sizeof(struct rectangle) == sizeof(int) + sizeof(int) +// en raison du remplissage potentiel entre les membres de la structure (c'est pour des raisons +// d'alignement). [1] + +void function_1() +{ + struct rectangle my_rec; + + // L'accés aux membres de la structure se fait avec . + my_rec.width = 10; + my_rec.height = 20; + + // Vous pouvez déclarer un pointeur vers une structure + struct rectangle *my_rec_ptr = &my_rec; + + // Utiliser le déréférencement pour définir les membres du pointeur de structure... + (*my_rec_ptr).width = 30; + + // préférez le raccourci -> par souci de lisibilité + my_rec_ptr->height = 10; // Identique à (*my_rec_ptr).height = 10; +} + +// Vous pouvez appliquer un typedef à une structure pour plus de commodité +typedef struct rectangle rect; + +int area(rect r) +{ + return r.width * r.height; +} + +// si vous avez de grandes structures, vous pouvez les passer "par pointeur" afin d'éviter la copie +// de toute la structure: +int areaptr(const rect *r) +{ + return r->width * r->height; +} + +/////////////////////////////////////// +// Pointeurs sur fonction +/////////////////////////////////////// +/* +Au moment de l'exécution, les fonctions sont situées à des adresses de mémoire connues. Les pointeurs de fonction sont +un peu comme n'importe quel autre pointeur (ils stockent juste une adresse mémoire), mais peuvent être utilisés +pour appeler directement des fonctions et pour transmettre des gestionnaires de fonctions (ou des fonctions de rappel). +Cependant, la syntaxe de définition peut être source de confusion au départ. + +Exemple: Utilisation de str_reverse à partir d'un pointeur +*/ +void str_reverse_through_pointer(char *str_in) { + // Définit une variable pointeur sur fonction, nommée f. + void (*f)(char *); // La signature doit être la même que la fonction cible. + f = &str_reverse; // Assigne l'adresse de la fonction réelle (déterminé au runtime) + // f = str_reverse; marcherait aussi - les fonctions s'interprètent en pointeurs, comme les tableaux + (*f)(str_in); // Il suffit d'appeler la fonction via le pointeur + // f(str_in); // C'est une syntaxe alternative mais tout aussi valide pour l'appel. +} + +/* +Tant que les signatures de fonction correspondent, vous pouvez affecter n'importe quelle fonction au même pointeur. +Les pointeurs de fonction sont généralement typés via typedef pour plus de simplicité et de lisibilité, comme suit: +*/ + +typedef void (*my_fnp_type)(char *); + +// Puis utilisé lors de la déclaration de la variable réelle de pointeur: +// ... +// my_fnp_type f; + + +//Caractères spéciaux: +/* +'\a'; // caractère d'alerte (cloche) +'\n'; // caractère de nouvelle ligne +'\t'; // caractère de tabulation (texte justifié à gauche) +'\v'; // tabulation verticale +'\f'; // nouvelle page (flux de formulaire) +'\r'; // retour chariot +'\b'; // caractère de retour arrière +'\0'; // Caractère NULL. Habituellement mis à la fin des chaînes en C. +// bonjour\n\0. \0 utilisé par convention pour marquer la fin de la chaîne. +'\\'; // barre oblique inverse +'\?'; // point d'interrogation +'\' '; // simple guillemet +'\"'; // double quillemets +'\xhh'; // nombre hexadécimal. Exemple: '\xb' = caractère de tabulation verticale +'\0oo'; // nombre octal. Exemple: '\013' = caractère de tabulation verticale + +//Format d'affichage: +"%d"; // entier +"%3d"; // entier avec une taille minimum de 3 digits (texte justifié à droite) +"%s"; // chaîne de caractères +"%f"; // nombre à virgule flottante +"%ld"; // nombre long +"%3.2f"; // minimum de 3 digits à gauche et 2 digits à droite nombre décimal à virgule flottante +"%7.4s"; // (peut être fait aussi avec une chaîne de caractères) +"%c"; // caratère +"%p"; // pointeur. REMARQUE: il est nécessaire de caster en (void *) le pointeur, avant de la passer + // comme argument à `printf`. +"%x"; // hexadecimal +"%o"; // octal +"%%"; // affiche % +*/ + +/////////////////////////////////////// +// Ordre des évaluations +/////////////////////////////////////// + +//--------------------------------------------------------// +// Operateurs | Associativité // +//--------------------------------------------------------// +// () [] -> . | de gauche à droite // +// ! ~ ++ -- + = *(type)sizeof | de droite à gauche // +// * / % | de gauche à droite // +// + - | de gauche à droite // +// << >> | de gauche à droite // +// < <= > >= | de gauche à droite // +// == != | de gauche à droite // +// & | de gauche à droite // +// ^ | de gauche à droite // +// | | de gauche à droite // +// && | de gauche à droite // +// || | de gauche à droite // +// ?: | de droite à gauche // +// = += -= *= /= %= &= ^= |= <<= >>= | de droite à gauche // +// , | de gauche à droite // +//--------------------------------------------------------// + +/******************************* Fichiers en-têtes ********************************** + +Les fichiers d'en-tête sont une partie importante de C car ils permettent l'interconnexion +des fichiers source C ce qui permet de simplifier le code et les définitions en les séparant +dans des fichiers séparés. + +Les fichiers d'en-tête sont syntaxiquement similaires aux fichiers source C mais résident dans +des fichiers ".h". Ils peuvent être inclus dans votre fichier source C en utilisant la commande +du précompilateur #include "example.h", avec example.h existant dans le même répertoire +que le fichier C. +*/ + +/* Un garde-fou pour éviter que l'en-tête ne soit défini trop de fois. Ce */ +/* qui se produit dans le cas de dépendance cyclique, et que le contenu du fichier */ +/* d'en-tête est déjà défini. */ +#ifndef EXAMPLE_H /* si EXAMPLE_H n'est pas déjà défini. */ +#define EXAMPLE_H /* Definit la macro EXAMPLE_H. */ + +/* Des en-têtes peuvent être inclus dans d'autres en-têtes et donc par transitivité */ +/* être inclus dans des fichiers qui incluent un en-tête. */ +#include + +/* Les macros de fichiers source c peuvent être définies dans les en-têtes et utilisées dans les fichiers */ +/* qui incluent ce fichier d'en-tête. */ +#define EXAMPLE_NAME "Dennis Ritchie" + +/* Les macros de fonction peuvent aussi être définies. */ +#define ADD(a, b) ((a) + (b)) + +/* Remarquez les parenthèses entourant les arguments - c'est important pour */ +/* assurer que a et b ne soient pas développés de manière inattendue (par exemple, pensez à */ +/* MUL (x, y) (x * y); MUL (1 + 2, 3) s'étendrait à (1 + 2 * 3), produisant un */ +/* résultat incorrect) */ + +/* Les structures et les typedefs peuvent être utilisés pour la cohérence entre les fichiers. */ +typedef struct Node +{ + int val; + struct Node *next; +} Node; + +/* Il en va de même pour les énumérations. */ +enum traffic_light_state {GREEN, YELLOW, RED}; + +/* Les prototypes de fonctions peuvent également être définis ici pour une utilisation dans plusieurs fichiers, */ +/* mais c'est une mauvaise pratique de définir la fonction dans l'en-tête. Les définitions */ +/* devraient plutôt être placées dans un fichier C. */ +Node createLinkedList(int *vals, int len); + +/* Au-delà des éléments ci-dessus, les autres définitions devraient être placées dans un fichier source C */ +/* Les inclusions ou définitions excessives ne devraient pas non plus figurer dans */ +/* un fichier d'en-tête mais placées plutôt dans des en-têtes séparés ou un fichier C. */ + +#endif /* Fin de la directive if du precompilateur. */ + +``` +## Lectures complémentaires + +- [Learn C The Hard Way](http://learncodethehardway.org/c/). +- Si vous avez une question, lisez le [compl.lang.c Frequently Asked Questions](http://c-faq.com). + +Il est très important d'utiliser un espacement et une indentation appropriés et d'être cohérent avec votre style de codage en général. +Un code lisible est meilleur qu'un code intelligent et un code rapide. Pour un bon style de codage sain à adopter, consultez le +[Linux kernel coding style](https://www.kernel.org/doc/Documentation/process/coding-style.rst). + +[1] [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) -- cgit v1.2.3