Skip to content · ⁨Passer au contenu⁩
Subjects · ⁨Sujets⁩
  • 1 C basics · ⁨Bases C⁩
    1.1

    main, printf & fonctions

    English

    Every C program starts in main. #include <stdio.h> pulls in a header 头文件 so you can use printf to print. A function 函数 is a named block you can call; \n starts a new line. main returns 0 to mean "success".

    Français

    Tout programme C commence dans main. #include <stdio.h> inclut un header 头文件 afin que vous puissiez utiliser printf pour l'affichage. Une fonction 函数 est un bloc nommé que vous pouvez appeler ; \n crée une nouvelle ligne. main retourne 0 pour indiquer « succès ».

    #include <stdio.h>
    
    void greet(void) {
        printf("Hello, world!\n");
    }
    
    int main(void) {
        greet();
        printf("I am learning C.\n");
        return 0;
    }
    
    Chaque programme C s'exécute à partir de main après avoir inclus les headers
    Chaque programme C s'exécute à partir de main après avoir inclus les headers
    1.2

    Variables, types & arithmétique

    English

    C needs a type for every variable: int (integer 整数), double (floating-point 浮点数), char (one character). printf uses a format specifier 格式说明符 — %d, %f, %c — for each value. / between two ints is integer division; % is the remainder 余数.

    The format string drives both printing and reading:

    Specifier Type Example output
    %d int 17
    %f double (%.2f = 2 decimal places) 3.14
    %c char A
    %s a string Mei
    %zu a size (from sizeof / strlen) 3
    %x int, printed in base 16 ff

    scanf("%d", &n) reads keyboard input with the same specifiers (note the &). Its sibling sscanf parses values out of a string, so it runs anywhere:

    Français

    C nécessite un type pour chaque variable : int (integer 整数), double (floating-point 浮点数), char (un caractère). printf utilise un format specifier 格式说明符 — %d, %f, %c — pour chaque valeur. / entre deux ints effectue une division entière ; % est le reste 余数.

    #include <stdio.h>
    
    int main(void) {
        int n = 17;
        double pi = 3.14;
        char grade = 'A';
        printf("%d %.2f %c\n", n, pi, grade);   // 17 3.14 A
        printf("%d %d\n", 7 / 2, 7 % 2);        // 3 1
        return 0;
    }
    

    La chaîne de format contrôle à la fois l'impression et la lecture :

    Spécificateur Type Exemple de sortie
    %d int 17
    %f double (%.2f = 2 décimales) 3.14
    %c char A
    %s une chaîne de caractères Mei
    %zu une taille (de sizeof / strlen) 3
    %x int, imprimé en base 16 ff

    scanf("%d", &n) lit l'entrée clavier avec les mêmes spécificateurs (notez le &). Son homologue sscanf analyse des valeurs dans une chaîne, ce qui lui permet de s'exécuter partout :

    #include <stdio.h>
    
    int main(void) {
        char line[] = "Mei 88";
        char name[20];
        int score;
        sscanf(line, "%19s %d", name, &score);   // parse text -> values
        printf("%s scored %d\n", name, score);   // Mei scored 88
        return 0;
    }
    
    1.3

    Commentaires & style

    English

    A comment 注释 is a note for humans; the compiler ignores it. Use // for one line and /* ... */ for a block. Good indentation 缩进 and clear names make code easy to read.

    Common mistakes

    • Every statement ends with ;, and main should return int (return 0;).
    • printf needs a format string: %d for int, %f for double, and \n for a new line.
    • A wrong format like %d for a double prints garbage — match the type.
    Français

    Un commentaire 注释 est une note pour les humains ; le compilateur l'ignore. Utilisez // pour une seule ligne et /* ... */ pour un bloc. Un bon indentation 缩进 et des noms clairs rendent le code facile à lire.

    #include <stdio.h>
    
    int main(void) {
        // a single-line comment
        /* a block
           comment */
        int total = 3 + 4;       // clear names help
        printf("%d\n", total);   // 7
        return 0;
    }
    

    Erreurs courantes

    • Chaque instruction se termine par ;, et main devrait retourner int (return 0;).
    • printf nécessite une chaîne de format : %d pour int, %f pour double, et \n pour une nouvelle ligne.
    • Un mauvais format comme %d pour un double imprime des caractères incohérents — respectez le type.
  • 2 Selection · ⁨Sélection⁩
    2.1

    if / else

    English

    An if runs a block when a condition 条件 is true. C has no real boolean 布尔值 type by default: 0 is false and any non-zero value is true. Chain choices with else if and else. Compare with ==, !=, <, >, <=, >=.

    Français

    Un if exécute un bloc quand une condition 条件 est vraie. C n'a pas de véritable type booléen 布尔值 par défaut : 0 est faux et toute valeur non nulle est vraie. Enchaînez les choix avec else if et else. Comparez avec ==, !=, <, >, <=, >=.

    #include <stdio.h>
    
    int main(void) {
        int score = 72;
        if (score >= 90) {
            printf("A\n");
        } else if (score >= 60) {
            printf("Pass\n");
        } else {
            printf("Fail\n");
        }
        return 0;
    }
    
    if choisit la branche vraie ; else la branche fausse
    if choisit la branche vraie ; else la branche fausse
    2.2

    switch · ⁨interrupteur⁩

    English

    A switch picks one case by an integer value. Each case needs a break to jump out 跳出 — without it, C "falls through" into the next case. default runs when nothing matches.

    Common mistakes

    • if (x = 5) assigns and is always true; use == to compare.
    • Each switch case needs a break;, or it falls through to the next.
    • 0 is false and any non-zero value is true in a condition.
    Français

    Un switch sélectionne un case basé sur une valeur entière. Chaque case nécessite un break pour sortir 跳出 — sans cela, C « tombe » dans le case suivant. default s'exécute quand rien ne correspond.

    #include <stdio.h>
    
    int main(void) {
        int day = 3;
        switch (day) {
            case 1: printf("Mon\n"); break;
            case 2: printf("Tue\n"); break;
            case 3: printf("Wed\n"); break;
            default: printf("Other\n");
        }
        return 0;
    }
    

    Erreurs courantes

    • if (x = 5) affecte et est toujours vrai ; utilisez == pour comparer.
    • Chaque switch case nécessite un break;, sinon il tombe dans le suivant.
    • 0 est faux et toute valeur non nulle est vraie dans une condition.
  • 3 Loops · ⁨Boucles⁩
    3.1

    boucles while & for

    English

    A loop 循环 repeats a block. A while loop runs as long as a condition is true. A for loop packs the start, the test, and the increment 自增 (i++) into one line — best when you know how many times to repeat.

    Français

    Une boucle 循环 répète un bloc. Une boucle while s'exécute tant qu'une condition est vraie. Une boucle for regroupe l'initialisation, le test et l'incrémentation 自增 (i++) sur une seule ligne — idéal quand on sait combien de fois répéter.

    #include <stdio.h>
    
    int main(void) {
        int i = 1;
        while (i <= 3) {
            printf("%d ", i);
            i++;
        }
        printf("\n");                    // 1 2 3
        for (int j = 0; j < 5; j++) {
            printf("%d ", j);
        }
        printf("\n");                    // 0 1 2 3 4
        return 0;
    }
    
    while vérifie une condition ; for compte avec un pas
    while vérifie une condition ; for compte avec un pas
    3.2

    Accumulation

    English

    A common pattern: start an accumulator 累加器 at 0, then add to it inside a loop. The same idea counts items or finds a running total.

    Français

    Un motif courant : initialiser un accumulateur 累加器 à 0, puis l'incrémenter à l'intérieur d'une boucle. La même logique sert à compter des éléments ou trouver un total cumulé.

    #include <stdio.h>
    
    int main(void) {
        int total = 0;
        for (int i = 1; i <= 5; i++) {
            total += i;            // 1 + 2 + 3 + 4 + 5
        }
        printf("%d\n", total);     // 15
        return 0;
    }
    
    3.3

    Boucles imbriquées & motifs

    English

    A loop inside another loop is a nested 嵌套 loop. The inner loop finishes fully for each step of the outer loop — perfect for grids and patterns.

    Common mistakes

    • for (i = 0; i < n; i++) runs n times; a semicolon right after for (...) makes an empty loop.
    • A while whose condition never becomes false loops forever.
    • Declare the counter (int i) before or inside the for header.
    Français

    Une boucle à l'intérieur d'une autre boucle est une boucle imbriquée 嵌套. La boucle intérieure se termine complètement pour chaque étape de la boucle extérieure — parfait pour les grilles et les motifs.

    #include <stdio.h>
    
    int main(void) {
        for (int row = 0; row < 3; row++) {
            for (int col = 0; col < 3; col++) {
                printf("*");
            }
            printf("\n");
        }
        return 0;
    }
    

    Erreurs courantes

    • for (i = 0; i < n; i++) s'exécute n fois ; un point-virgule juste après for (...) crée une boucle vide.
    • Une while dont la condition ne devient jamais fausse boucle indéfiniment.
    • Déclarez le compteur (int i) avant ou dans l'en-tête for.
  • 4 Functions · ⁨Fonctions⁩
    4.1

    Paramètres et valeurs de retour

    English

    A function takes parameters 参数 (inputs) and gives back a return value 返回值. The return type comes first (int, double, …); void means it returns nothing.

    Français

    Une fonction prend des paramètres 参数 (entrées) et retourne une valeur de retour 返回值. Le type de retour se trouve en premier (int, double, …) ; void signifie qu'elle ne retourne rien.

    #include <stdio.h>
    
    int square(int x) {        // x is a parameter
        return x * x;          // hand back a value
    }
    
    int main(void) {
        int r = square(5);
        printf("%d\n", r);     // 25
        return 0;
    }
    
    Paramètres in; valeur de retour out
    Paramètres in; valeur de retour out
    4.2

    Prototypes et portée

    English

    C reads top to bottom, so a function must be known before it is called. A prototype 函数原型 — the header line plus ; — declares it early so you can keep main first. A variable's scope 作用域 is the block it lives in: it is local 局部 and disappears when the block ends.

    Common mistakes

    • A function used before it is defined needs a prototype above main.
    • Arguments are passed BY VALUE — changes inside a function do not affect the caller unless you pass a pointer.
    • A variable declared inside a function is local to it.
    Français

    C lit de haut en bas, donc une fonction doit être connue avant d'être appelée. Un prototype 函数原型 — la ligne d'en-tête plus ; — la déclare tôt pour que vous puissiez garder main en premier. La portée 作用域 d'une variable est le bloc dans lequel elle existe : elle est locale 局部 et disparaît lorsque le bloc se termine.

    #include <stdio.h>
    
    int add(int a, int b);     // prototype: declared before use
    
    int main(void) {
        printf("%d\n", add(3, 4));   // 7
        return 0;
    }
    
    int add(int a, int b) {    // definition comes later
        int sum = a + b;       // sum is local to add
        return sum;
    }
    

    Erreurs courantes

    • Une fonction utilisée avant d'être définie nécessite un prototype au-dessus de main.
    • Les arguments sont passés PAR VALEUR — les modifications à l'intérieur d'une fonction n'affectent pas l'appelant sauf si vous passez un pointeur.
    • Une variable déclarée à l'intérieur d'une fonction lui est locale.
  • 5 Arrays · ⁨Tableaux⁩
    5.1

    Tableaux 1-D

    English

    An array 数组 holds several values of one type. Index 索引 from 0. C does not store an array's length, so a common trick computes the element 元素 count: sizeof(a) / sizeof(a[0]).

    Français

    Un tableau 数组 stocke plusieurs valeurs d'un même type. L'index 索引 commence à 0. C ne stocke pas la longueur du tableau, c'est pourquoi on calcule souvent le nombre d'éléments 元素 : sizeof(a) / sizeof(a[0]).

    #include <stdio.h>
    
    int main(void) {
        int scores[3] = {88, 71, 95};
        printf("%d\n", scores[0]);     // 88
        scores[1] = 100;
        printf("%d\n", scores[1]);     // 100
        int n = sizeof(scores) / sizeof(scores[0]);
        printf("%d\n", n);             // 3
        return 0;
    }
    
    Les cases du tableau sont indexées à partir de 0
    Les cases du tableau sont indexées à partir de 0
    5.2

    Algorithmes sur tableaux

    English

    Traverse 遍历 an array with a for loop to find a max, a total, or a count. Always loop from 0 up to n - 1.

    Français

    Parcourez 遍历 un tableau avec une boucle for pour trouver un maximum, un total ou un décompte. Bouclez toujours de 0 jusqu'à n - 1.

    #include <stdio.h>
    
    int main(void) {
        int a[] = {3, 9, 2, 7};
        int n = sizeof(a) / sizeof(a[0]);
        int max = a[0], total = 0;
        for (int i = 0; i < n; i++) {
            if (a[i] > max) max = a[i];
            total += a[i];
        }
        printf("%d %d\n", max, total);   // 9 21
        return 0;
    }
    
    5.3

    Tableaux 2-D

    English

    A 2-D array is a grid of rows 行 and columns 列: grid[row][col]. Use two nested loops to visit every cell.

    Common mistakes

    • C does NOT check array bounds: writing a[n] in a size-n array is undefined behaviour.
    • Valid indexes run from 0 to n - 1.
    • The array name is a pointer to its first element; sizeof only gives the size in the array's own scope.
    Français

    Un tableau 2-D est une grille de lignes 行 et colonnes 列 : grid[row][col]. Utilisez deux boucles imbriquées pour visiter chaque case.

    #include <stdio.h>
    
    int main(void) {
        int grid[2][3] = {{1, 2, 3}, {4, 5, 6}};
        printf("%d\n", grid[1][2]);    // 6
        for (int r = 0; r < 2; r++) {
            for (int c = 0; c < 3; c++) {
                printf("%d ", grid[r][c]);
            }
        }
        printf("\n");                  // 1 2 3 4 5 6
        return 0;
    }
    

    Erreurs courantes

    • C ne vérifie PAS les limites du tableau : écrire a[n] dans un tableau de taille n est un comportement non défini.
    • Les indices valides vont de 0 à n - 1.
    • Le nom du tableau est un pointeur vers son premier élément ; sizeof ne donne la taille que dans la portée propre du tableau.
  • 6 Pointers · ⁨Pointeurs⁩
    6.1

    &, * et passage par pointeur

    English

    A pointer 指针 stores the address 地址 of a variable. &x gives the address of x; *p dereferences 解引用 the pointer — it reads or writes the value stored there. Passing a pointer lets a function change the caller's variable (pass-by-pointer).

    The classic use is a swap function. Passing values only copies them — the swap is lost. Passing pointers lets the function reach the caller's variables:

    An array name acts as a pointer to its first element, and pointer arithmetic 指针运算 steps by whole elements:

    • NULL is the pointer that points at nothing — check for it before you dereference.

    Common mistakes

    • &x is the address of x; *p is the value stored at p.
    • Never use *p on an uninitialised or NULL pointer — it crashes or corrupts memory.
    • To change a caller's variable, pass its address and write through the pointer.
    Français

    Un pointeur 指针 stocke l'adresse 地址 d'une variable. &x donne l'adresse de x ; *p déréférence 解引用 le pointeur — il lit ou écrit la valeur stockée là. Passer un pointeur permet à une fonction de modifier la variable de l'appelant (passage par pointeur).

    Un pointeur stocke une adresse ; sa déréference suit la flèche vers la valeur
    Un pointeur stocke une adresse ; sa déréference suit la flèche vers la valeur
    #include <stdio.h>
    
    void addOne(int *p) {     // p holds an address
        *p = *p + 1;          // change the value at that address
    }
    
    int main(void) {
        int x = 10;
        int *ptr = &x;        // & takes the address of x
        printf("%d\n", *ptr); // * reads the value: 10
        addOne(&x);
        printf("%d\n", x);    // 11 — changed through the pointer
        return 0;
    }
    

    L'usage classique est une fonction d'échange. Passer des valeurs ne fait que les copier — l'échange est perdu. Passer des pointeurs permet à la fonction d'accéder aux variables de l'appelant :

    #include <stdio.h>
    
    void swap_values(int a, int b) {      // copies: the caller sees nothing
        int t = a; a = b; b = t;
    }
    
    void swap_pointers(int *a, int *b) {  // addresses: the swap is real
        int t = *a; *a = *b; *b = t;
    }
    
    int main(void) {
        int x = 1, y = 2;
        swap_values(x, y);
        printf("%d %d\n", x, y);   // 1 2  (unchanged!)
        swap_pointers(&x, &y);
        printf("%d %d\n", x, y);   // 2 1  (swapped)
        return 0;
    }
    

    Le nom d'un tableau agit comme un pointeur vers son premier élément, et l'arithmétique de pointeur 指针运算 avance par éléments entiers :

    #include <stdio.h>
    
    int main(void) {
        int a[] = {10, 20, 30};
        int *p = a;                 // same as &a[0]
        printf("%d\n", *p);         // 10
        printf("%d\n", *(p + 2));   // 30 — same as a[2]
        return 0;
    }
    
    • NULL est un pointeur qui ne pointe sur rien — vérifiez-le avant de le déréférencer.

    Erreurs courantes

    • &x est l'adresse de x ; *p est la valeur stockée à p.
    • N'utilisez jamais *p sur un pointeur non initialisé ou NULL — cela provoque un crash ou une corruption de mémoire.
    • Pour modifier la variable de l'appelant, passez son adresse et écrivez via le pointeur.
  • 7 Strings · ⁨Chaînes de Caractères⁩
    7.1

    Tableaux de caractères & terminateur nul

    English

    A C string 字符串 is an array of char. Every string ends with a hidden null terminator 空终止符 '\0', which marks where it stops. strlen (from <string.h>) counts characters up to that '\0'. Print a whole string with %s and one character 字符 with %c.

    You can traverse a string by looping until you reach '\0'.

    Français

    Une chaîne C 字符串 est un tableau de char. Chaque chaîne se termine par un terminateur null caché 空终止符 '\0', qui marque où elle s'arrête. strlen (depuis <string.h>) compte les caractères jusqu'à ce '\0'. Imprimez une chaîne entière avec %s et un caractère 字符 avec %c.

    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
        char name[] = "Mei";            // 'M', 'e', 'i', '\0'
        printf("%s\n", name);           // Mei
        printf("%zu\n", strlen(name));  // 3 (stops at '\0')
        printf("%c\n", name[0]);        // M
        return 0;
    }
    
    Une chaîne C est un tableau de char se terminant par un terminateur nul caché
    Une chaîne C est un tableau de char se terminant par un terminateur nul caché

    Vous pouvez parcourir une chaîne en bouclant jusqu'à ce que vous atteigniez '\0'.

    #include <stdio.h>
    
    int main(void) {
        char word[] = "banana";
        int count = 0;
        for (int i = 0; word[i] != '\0'; i++) {
            if (word[i] == 'a') count++;
        }
        printf("%d\n", count);   // 3
        return 0;
    }
    
    7.2

    La bibliothèque string.h

    English

    #include <string.h> gives you the everyday string tools:

    Function Does
    strlen(s) the length, not counting the terminator
    strcpy(dst, src) copy — dst must be big enough
    strcat(dst, src) append src onto the end of dst
    strcmp(a, b) compare: 0 when equal, else negative / positive
    • strcmp returns 0 for equal, so the test is strcmp(a, b) == 0 — never a == b.
    • The destination array must have room for the result plus the terminator.

    Common mistakes

    • A C string needs one extra byte for the \0 terminator: a 5-letter word needs char[6].
    • Copy and compare strings with strcpy / strcmp, not = / ==.
    • Forgetting the \0 makes printf("%s", ...) run past the end of the text.
    Français

    #include <string.h> vous fournit les outils courants pour les chaînes :

    Fonction Fait
    strlen(s) la longueur, sans compter le terminateur
    strcpy(dst, src) copier — dst doit être assez grand
    strcat(dst, src) ajouter src à la fin de dst
    strcmp(a, b) comparer : 0 si égal, sinon négatif / positif
    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
        char full[40];
        strcpy(full, "Mei");           // full is now "Mei"
        strcat(full, " Chen");         // append -> "Mei Chen"
        printf("%s (%zu)\n", full, strlen(full));       // Mei Chen (8)
        printf("%d\n", strcmp("apple", "apple") == 0);  // 1 (equal)
        return 0;
    }
    
    • strcmp retourne 0 pour l'égalité, donc le test est strcmp(a, b) == 0 — jamais a == b.
    • Le tableau de destination doit avoir de la place pour le résultat plus le terminateur.

    Erreurs courantes

    • Une chaîne C a besoin d'un octet supplémentaire pour le terminateur \0 : un mot de 5 lettres nécessite char[6].
    • Copiez et comparez des chaînes avec strcpy / strcmp, pas = / ==.
    • Oublier le \0 fait que printf("%s", ...) dépasse la fin du texte.
  • 8 Structs · ⁨Structures⁩
    8.1

    struct, typedef, . vs ->

    English

    A struct 结构体 groups related values into one type. Each value is a member 成员. typedef gives the struct a short name so you can write Dog instead of struct Dog. Use . on a struct value, but -> on a pointer to a struct.

    Common mistakes

    • Use . on a struct value and -> on a struct pointer.
    • typedef lets you drop the word struct when declaring; without it you write struct Point p;.
    • Assigning one struct to another copies all its fields.
    Français

    Une struct 结构体 regroupe des valeurs liées en un seul type. Chaque valeur est un membre 成员. typedef donne à la struct un nom court afin que vous puissiez écrire Dog au lieu de struct Dog. Utilisez . sur une valeur de struct, mais -> sur un pointeur vers une struct.

    #include <stdio.h>
    
    typedef struct {
        char name[20];
        int age;
    } Dog;
    
    int main(void) {
        Dog d = {"Rex", 3};
        printf("%s is %d\n", d.name, d.age);   // Rex is 3   (. on a value)
    
        Dog *p = &d;
        p->age = 4;                            // -> on a pointer
        printf("%s is %d\n", d.name, d.age);   // Rex is 4
        return 0;
    }
    

    Erreurs courantes

    • Utilisez . sur une valeur de struct et -> sur un pointeur de struct.
    • typedef vous permet de supprimer le mot struct lors de la déclaration ; sans cela, vous écrivez struct Point p;.
    • Assigner une struct à une autre copie tous ses champs.
    . pour les valeurs de structure ; -> pour les pointeurs vers des structures
    . pour les valeurs de struct ; -> pour les pointeurs vers des structs
  • 9 Dynamic memory · ⁨Mémoire dynamique⁩
    9.1

    malloc, free & realloc

    English

    malloc allocates 分配 memory on the heap 堆 at run time and returns a pointer to it. realloc resizes that block; free gives it back. Every malloc needs a matching free, or you get a memory leak 内存泄漏. These live in <stdlib.h>.

    • calloc(n, size) allocates an array like malloc AND fills it with zeros.

    Common mistakes

    • Every malloc needs a matching free; forgetting to free leaks memory.
    • Using memory after free (a "use-after-free") is a serious bug.
    • Check that malloc did not return NULL before you use the memory.
    Français

    malloc alloue de la mémoire 分配 sur le tas 堆 à l'exécution et renvoie un pointeur vers celle-ci. realloc redimensionne ce bloc ; free le libère. Chaque malloc nécessite un free correspondant, sinon vous obtenez une fuite de mémoire 内存泄漏. Ceux-ci vivent dans <stdlib.h>.

    Les variables locales sont stockées sur la pile ; la mémoire allouée par malloc se trouve dans le tas jusqu'à ce que vous la libériez
    Les variables locales vivent sur la pile ; la mémoire malloc vit sur le tas jusqu'à ce que vous la libériez
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
        int n = 3;
        int *a = malloc(n * sizeof(int));    // room for 3 ints
        for (int i = 0; i < n; i++) a[i] = i * 10;
    
        a = realloc(a, 4 * sizeof(int));     // grow to 4 ints
        a[3] = 30;
    
        for (int i = 0; i < 4; i++) printf("%d ", a[i]);
        printf("\n");                        // 0 10 20 30
    
        free(a);                             // hand the memory back
        return 0;
    }
    
    • calloc(n, size) alloue un tableau comme malloc ET le remplit de zéros.

    Erreurs courantes

    • Chaque malloc nécessite un free correspondant ; oublier de libérer entraîne une fuite de mémoire.
    • Utiliser de la mémoire après free (un « use-after-free ») est un bug grave.
    • Vérifiez que malloc n'a pas renvoyé NULL avant d'utiliser la mémoire.
  • 10 Data structures · ⁨Structures de données⁩
    10.1

    Listes chainées

    English

    A linked list 链表 is a chain of nodes 节点. Each node holds a value and a pointer to the next node; the last one points to NULL. Unlike an array it grows one node at a time with malloc. Always free every node when done.

    Français

    Une liste chainée 链表 est une chaîne de nœuds 节点. Chaque nœud contient une valeur et un pointeur vers le nœud next ; le dernier pointe vers NULL. Contrairement à un tableau, elle croît d'un nœud à la fois avec malloc. Libérez toujours free chaque nœud une fois terminé.

    Une liste chaînée : chaque nœud contient une valeur et un pointeur vers le suivant, se terminant par NULL
    Une liste chainée : chaque nœud contient une valeur et un pointeur vers le suivant, se terminant à NULL
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct Node {
        int value;
        struct Node *next;
    } Node;
    
    int main(void) {
        Node *head = NULL;
        for (int v = 10; v <= 30; v += 10) {   // prepend 10, 20, 30
            Node *n = malloc(sizeof(Node));
            n->value = v;
            n->next = head;
            head = n;
        }
        for (Node *p = head; p != NULL; p = p->next) {
            printf("%d ", p->value);           // 30 20 10
        }
        printf("\n");
    
        while (head != NULL) {                 // free the whole list
            Node *t = head;
            head = head->next;
            free(t);
        }
        return 0;
    }
    
    10.2

    Piles et files

    English

    A stack 栈 is LIFO 后进先出 (last in, first out): push and pop at the same end. A queue 队列 is FIFO 先进先出 (first in, first out): add at the back, remove from the front. Both are easy to build on an array with index variables.

    Common mistakes

    • In a linked list, never lose the head pointer, or the whole list is unreachable.
    • Free every node when you are done, walking the list before you unlink.
    • Check for an empty list (a NULL head) before you pop.
    Français

    Une pile 栈 est LIFO 后进先出 (last in, first out) : push et pop à la même extrémité. Une file 队列 est FIFO 先进先出 (first in, first out) : ajout à l'arrière, retrait à l'avant. Les deux sont faciles à implémenter sur un tableau avec des variables d'index.

    #include <stdio.h>
    
    int main(void) {
        int stack[10];
        int top = 0;                       // next free slot
        stack[top++] = 1;                  // push
        stack[top++] = 2;
        stack[top++] = 3;
        while (top > 0) {
            printf("%d ", stack[--top]);   // pop: 3 2 1
        }
        printf("\n");
        return 0;
    }
    
    #include <stdio.h>
    
    int main(void) {
        int queue[10];
        int front = 0, back = 0;
        queue[back++] = 1;                       // enqueue
        queue[back++] = 2;
        queue[back++] = 3;
        while (front < back) {
            printf("%d ", queue[front++]);       // dequeue: 1 2 3
        }
        printf("\n");
        return 0;
    }
    

    Erreurs courantes

    • Dans une liste chainée, ne perdez jamais le pointeur head, sinon toute la liste devient inaccessible.
    • Libérez chaque nœud une fois terminé, en parcourant la liste avant de la détacher.
    • Vérifiez une liste vide (une tête NULL) avant de faire un pop.
  • 11 Searching, sorting & recursion · ⁨Recherche, tri & récursion⁩
    11.1

    Recherche linéaire et binaire

    English

    Linear search 线性查找 checks each element in turn — it works on any array. Binary search 二分查找 is far faster but needs a sorted 已排序 array: it checks the middle and discards half each step. Both return the index, or -1 if missing.

    Français

    La recherche linéaire 线性查找 vérifie chaque élément à tour de rôle — elle fonctionne sur tout tableau. La recherche binaire 二分查找 est beaucoup plus rapide mais nécessite un tableau trié 已排序 : elle vérifie le milieu et élimine la moitié à chaque étape. Les deux renvoient l'indice, ou -1 s'il est absent.

    #include <stdio.h>
    
    int linear(int a[], int n, int target) {
        for (int i = 0; i < n; i++)
            if (a[i] == target) return i;
        return -1;
    }
    
    int binary(int a[], int n, int target) {
        int lo = 0, hi = n - 1;
        while (lo <= hi) {
            int mid = (lo + hi) / 2;
            if (a[mid] == target) return mid;
            else if (a[mid] < target) lo = mid + 1;
            else hi = mid - 1;
        }
        return -1;
    }
    
    int main(void) {
        int a[] = {2, 5, 8, 12, 16, 23};
        int n = sizeof(a) / sizeof(a[0]);
        printf("%d %d %d\n", linear(a, n, 12), binary(a, n, 12), binary(a, n, 9));
        return 0;   // 3 3 -1
    }
    
    Les scans linéaires parcourent tout ; le binaire divise un trié en deux
    La recherche linéaire scanne tout ; la recherche binaire divise par deux un intervalle trié
    11.2

    Tri

    English

    Bubble sort 冒泡排序 repeatedly compares neighbours and swaps 交换 any pair that is out of order. After each pass the largest value "bubbles" to the end.

    Français

    Le tri à bulles 冒泡排序 compare répétitivement les voisins et échange 交换 toute paire qui n'est pas dans l'ordre. Après chaque passage, la plus grande valeur « remonte » à la fin.

    #include <stdio.h>
    
    int main(void) {
        int a[] = {5, 2, 9, 1, 7};
        int n = sizeof(a) / sizeof(a[0]);
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (a[j] > a[j + 1]) {
                    int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
                }
            }
        }
        for (int i = 0; i < n; i++) printf("%d ", a[i]);
        printf("\n");   // 1 2 5 7 9
        return 0;
    }
    
    11.3

    Récursivité

    English

    Recursion 递归 is a function that calls itself. It needs a base case 基准情形 to stop, and a recursive call that steps toward it. Without a base case it never ends.

    Common mistakes

    • Binary search needs a sorted array; recursion needs a base case.
    • Each recursive call must move closer to the base case, or the stack overflows.
    • Bubble and insertion sort are O(n²) — fine to learn, slow at scale.
    Français

    La récursion 递归 est une fonction qui s'appelle elle-même. Elle a besoin d'un cas de base 基准情形 pour s'arrêter, et d'un appel récursif qui s'en rapproche. Sans cas de base, elle ne se termine jamais.

    #include <stdio.h>
    
    int factorial(int n) {
        if (n <= 1) return 1;          // base case
        return n * factorial(n - 1);   // recursive call
    }
    
    int main(void) {
        printf("%d\n", factorial(5));  // 120
        return 0;
    }
    

    Erreurs courantes

    • La recherche binaire nécessite un tableau trié ; la récursion nécessite un cas de base.
    • Chaque appel récursif doit se rapprocher du cas de base, sinon la pile déborde.
    • Les tris par bulles et par insertion sont en O(n²) — bien à apprendre, lents à grande échelle.
  • 12 Files & errors · ⁨Fichiers & erreurs⁩
    12.1

    Fichiers texte

    English

    fopen returns a file pointer 文件指针; the mode 模式 string says what to do — "w" write, "r" read, "a" append. Write with fprintf, read with fscanf, and always fclose when done.

    Français

    fopen renvoie un pointeur de fichier 文件指针 ; la chaîne de mode 模式 indique quoi faire — "w" écrire, "r" lire, "a" ajouter. Écrivez avec fprintf, lisez avec fscanf, et fermez toujours fclose une fois terminé.

    #include <stdio.h>
    
    int main(void) {
        FILE *out = fopen("scores.txt", "w");   // open for writing
        fprintf(out, "Alice 80\nBob 95\n");
        fclose(out);
    
        FILE *in = fopen("scores.txt", "r");    // open for reading
        char name[20];
        int score;
        while (fscanf(in, "%s %d", name, &score) == 2) {
            printf("%s -> %d\n", name, score);
        }
        fclose(in);
        return 0;
    }
    
    fopen → lecture/écriture → fclose
    fopen → lecture/écriture → fclose
    12.2

    Gestion d'erreurs avec codes de retour

    English

    C has no exceptions. Instead a function signals failure with a return code 返回码 — by convention 0 means success and non-zero means an error. The caller checks the code before trusting the result. (fopen follows the same idea: it returns NULL when it fails.)

    Common mistakes

    • Check that fopen did not return NULL before reading or writing.
    • Always fclose a file when you are done.
    • Return a non-zero code from main to signal an error to the caller.
    Français

    C n'a pas d'exceptions. Au lieu de cela, une fonction signale un échec avec un code de retour 返回码 — par convention, 0 signifie succès et une valeur non nulle signifie une erreur. L'appelant vérifie le code avant de faire confiance au résultat. (fopen suit la même idée : il renvoie NULL en cas d'échec.)

    #include <stdio.h>
    
    // returns 0 on success, -1 if the divisor is 0
    int safe_divide(int a, int b, int *result) {
        if (b == 0) return -1;          // error code
        *result = a / b;
        return 0;                       // success
    }
    
    int main(void) {
        int r;
        if (safe_divide(10, 2, &r) == 0)
            printf("10 / 2 = %d\n", r);          // 10 / 2 = 5
        if (safe_divide(10, 0, &r) != 0)
            printf("cannot divide by zero\n");   // error reported
        return 0;
    }
    

    Erreurs courantes

    • Vérifiez que fopen n'a pas retourné NULL avant de lire ou d'écrire.
    • Fermez toujours fclose un fichier une fois terminé.
    • Renvoyez un code non nul depuis main pour signaler une erreur à l'appelant.
  • 13 Bits & data · ⁨Bits & données⁩
    13.1

    Bits, binaire et opérateurs bit à bit

    English

    A bit 位 is a single 0 or 1; numbers are stored in binary 二进制. Bitwise 按位 operators work on the bits directly: & AND, | OR, ^ XOR, << shift left (×2 each step), >> shift right (÷2).

    Hexadecimal 十六进制 (base 16) writes binary compactly: one hex digit is exactly four bits. Write hex literals with 0x; print with %x:

    Français

    Un bit 位 est un 0 ou 1 unique ; les nombres sont stockés en binaire 二进制. Les opérateurs bit à bit 按位 agissent directement sur les bits : & AND, | OR, ^ XOR, << décalage vers la gauche (×2 à chaque étape), >> décalage vers la droite (÷2).

    #include <stdio.h>
    
    int main(void) {
        int a = 12;              // 1100
        int b = 10;              // 1010
        printf("%d\n", a & b);   // 8   AND  -> 1000
        printf("%d\n", a | b);   // 14  OR   -> 1110
        printf("%d\n", a ^ b);   // 6   XOR  -> 0110
        printf("%d\n", a << 1);  // 24  left shift
        printf("%d\n", a >> 1);  // 6   right shift
        return 0;
    }
    

    L'hexadécimal 十六进制 (base 16) écrit le binaire de manière compacte : un chiffre hexadécimal correspond exactement à quatre bits. Écrivez les littéraux hexadécimaux avec 0x ; affichez avec %x :

    #include <stdio.h>
    
    int main(void) {
        printf("%d\n", 0xFF);   // 255  (0x marks a hex literal)
        printf("%x\n", 255);    // ff
        printf("%x\n", 12);     // c
        return 0;
    }
    
    Les opérateurs bit à bit travaillent sur les bits des entiers
    Les opérateurs bitwise travaillent sur les bits des entiers
    13.2

    Codage par longueur de run

    English

    Run-length encoding (RLE) is a simple compression 压缩 method: replace each run 游程 of repeated characters with a count and the character. It is lossless 无损 — the original is fully recoverable.

    Common mistakes

    • & is bitwise AND and && is logical AND — do not confuse them.
    • A left shift << 1 doubles a value; a right shift >> 1 halves it.
    • Bit n has value 1 << n (C has no ** power operator); check a bit with (x >> n) & 1.
    Français

    La compression par codage de longueur d'exécution (RLE) est une méthode 压缩 simple : remplacez chaque série 游程 de caractères répétés par un compteur et le caractère. C'est sans perte 无损 — l'original est entièrement récupérable.

    #include <stdio.h>
    #include <string.h>
    
    int main(void) {
        char *s = "aaabbc";
        int n = strlen(s);
        for (int i = 0; i < n; ) {
            char c = s[i];
            int run = 0;
            while (i < n && s[i] == c) { run++; i++; }
            printf("%d%c", run, c);     // 3a2b1c
        }
        printf("\n");
        return 0;
    }
    

    Erreurs courantes

    • & est un ET bit à bit et && est un ET logique — ne les confondez pas.
    • Un décalage à gauche << 1 double une valeur ; un décalage à droite >> 1 la divise par deux.
    • Le bit n a la valeur 1 << n (C n'a pas d'opérateur ** de puissance) ; vérifiez un bit avec (x >> n) & 1.
  • 14 Preprocessor & qualifiers · ⁨Préprocesseur & qualificateurs⁩
    14.1

    Préprocesseur, const, static, enum

    English

    The preprocessor 预处理器 runs before compiling. #define makes a macro 宏 — plain text replaced everywhere. const makes a constant 常量 that cannot change. static inside a function keeps a variable's value between calls. An enum (enumeration 枚举) names a set of integers starting at 0.

    Bigger programs split across files: declarations go in a header 头文件 file (mine.h), included with #include "mine.h" — quotes mean your own file, < > means the standard library. An include guard (#ifndef MINE_H / #define MINE_H / #endif) stops a header being included twice.

    Common mistakes

    • #define does plain text replacement with no type checking; wrap macro bodies and arguments in parentheses.
    • A const value cannot be changed after it is set.
    • A static local variable keeps its value between calls to the function.
    Français

    Le préprocesseur 预处理器 s'exécute avant la compilation. #define crée une macro 宏 — du texte brut remplacé partout. const crée une constante 常量 qui ne peut pas changer. static dans une fonction conserve la valeur d'une variable entre les appels. Une énumération 枚举 enum nomme un ensemble d'entiers commençant à 0.

    #include <stdio.h>
    
    #define MAX 100                     // macro: text replaced before compiling
    
    enum Color { RED, GREEN, BLUE };    // named integers 0, 1, 2
    
    int next_id(void) {
        static int count = 0;           // keeps its value between calls
        count++;
        return count;
    }
    
    int main(void) {
        const double PI = 3.14;         // cannot be changed
        printf("%d %.2f\n", MAX, PI);            // 100 3.14
        printf("%d %d %d\n", RED, GREEN, BLUE);  // 0 1 2
        int a = next_id();
        int b = next_id();
        printf("%d %d\n", a, b);                 // 1 2
        return 0;
    }
    

    Les programmes plus grands sont répartis sur plusieurs fichiers : les déclarations vont dans un fichier d'en-tête 头文件 (mine.h), inclus avec #include "mine.h" — les guillemets signifient votre propre fichier, < > signifie la bibliothèque standard. Un garde d'inclusion (#ifndef MINE_H / #define MINE_H / #endif) empêche qu'un en-tête soit inclus deux fois.

    Erreurs courantes

    • #define effectue un remplacement de texte brut sans vérification de type ; enroulez les corps et arguments des macro dans des parenthèses.
    • Une valeur const ne peut pas être modifiée après qu'elle a été définie.
    • Une variable locale static conserve sa valeur entre les appels à la fonction.
    #define, const, enum et static rendent le code clair
    #define, const, enum et static maintiennent le code clair

Log in or create account · ⁨Se connecter ou créer un compte⁩

IGCSE, A-Level & AP