Skip to content · ⁨Pular para o conteúdo⁩
Subjects · ⁨Matérias⁩
  • 1 C basics
    1.1

    main, printf & funções

    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".

    Português

    Todo programa C começa em main. #include <stdio.h> inclui um cabeçalho 头文件 para que você possa usar printf para imprimir. Uma função 函数 é um bloco nomeado que você pode chamar; \n inicia uma nova linha. main retorna 0 para significar "sucesso".

    #include <stdio.h>
    
    void greet(void) {
        printf("Hello, world!\n");
    }
    
    int main(void) {
        greet();
        printf("I am learning C.\n");
        return 0;
    }
    

    Todo programa C executa a partir de main após incluir cabeçalhos *Todo programa C executa a partir de main após incluir cabeçalhos

    1.2

    Variáveis, tipos e aritmética

    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:

    Português

    C precisa de um tipo para cada variável: int (inteiro 整数), double (ponto flutuante 浮点数), char (um caractere). printf usa um especificador de formato 格式说明符 — %d, %f, %c — para cada valor. / entre dois ints é divisão inteira; % é o resto 余数.

    #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;
    }
    

    A string de formato dirige tanto a impressão quanto a leitura:

    Especificador Tipo Exemplo de saída
    %d int 17
    %f double (%.2f = 2 casas decimais) 3.14
    %c char A
    %s uma string Mei
    %zu um tamanho (de sizeof / strlen) 3
    %x int, impresso em base 16 ff

    scanf("%d", &n) lê entrada do teclado com os mesmos especificadores (note o &). Seu irmão sscanf analisa valores de uma string, então ele roda em qualquer lugar:

    #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

    Comentários e estilo

    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.
    Português

    Um comentário 注释 é uma nota para humanos; o compilador o ignora. Use // para uma linha e /* ... */ para um bloco. Boa indentação 缩进 e nomes claros tornam o código fácil de ler.

    #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;
    }
    

    Erros comuns

    • Toda instrução termina com ;, e main deve retornar int (return 0;).
    • printf precisa de uma string de formato: %d para int, %f para double, e \n para uma nova linha.
    • Um formato errado como %d para um double imprime lixo — corresponda o tipo.
  • 2 Selection · ⁨Seleção⁩
    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 ==, !=, <, >, <=, >=.

    Português

    Um if executa um bloco quando uma condição 条件 é verdadeira. C não tem um tipo booleano real 布尔值 por padrão: 0 é falso e qualquer valor não-zero é verdadeiro. Encadeie escolhas com else if e else. Compare com ==, !=, <, >, <=, >=.

    #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 escolhe o ramo verdadeiro; else o ramo falso *if escolhe o ramo verdadeiro; else o ramo falso

    2.2

    switch · ⁨interruptor⁩

    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.
    Português

    Um switch escolhe um case por um valor inteiro. Cada case precisa de um break para sair 跳出 — sem ele, o C "cai" no próximo caso. default executa quando nada corresponde.

    #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;
    }
    

    Erros comuns

    • if (x = 5) atribui e é sempre verdadeiro; use == para comparar.
    • Cada caso de switch precisa de um break;, ou ele cai para o próximo.
    • 0 é falso e qualquer valor não-zero é verdadeiro em uma condição.
  • 3 Loops
    3.1

    Laços 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.

    Português

    Um laço 循环 repete um bloco. Um laço while roda enquanto uma condição é verdadeira. Um laço for agrupa o início, o teste e o incremento 自增 (i++) em uma linha — melhor quando você sabe quantas vezes repetir.

    #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 verifica uma condição; for conta com um passo *while verifica uma condição; for conta com um passo

    3.2

    Acumulação

    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.

    Português

    Um padrão comum: comece um acumulador 累加器 em 0, depois adicione a ele dentro de um laço. A mesma ideia conta itens ou encontra um total acumulado.

    #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

    Laços aninhados e padrões

    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.
    Português

    Um laço dentro de outro laço é um laço aninhado 嵌套. O laço interno termina completamente para cada etapa do laço externo — perfeito para grades e padrões.

    #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;
    }
    

    Erros comuns

    • for (i = 0; i < n; i++) executa n vezes; um ponto e vírgula logo após for (...) cria um loop vazio.
    • Um while cuja condição nunca se torna falsa roda para sempre.
    • Declare o contador (int i) antes ou no cabeçalho do for.
  • 4 Functions · ⁨Funções⁩
    4.1

    Parâmetros e valores de retorno

    English

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

    Português

    Uma função recebe parâmetros 参数 (inputs) e devolve um valor de retorno 返回值. O tipo de retorno vem primeiro (int, double, …); void significa que não retorna nada.

    #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;
    }
    
    Parâmetros entra; valor de retorno sai
    Parâmetros entra; valor de retorno sai
    4.2

    Protótipos e escopo

    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.
    Português

    C lê de cima para baixo, então uma função deve ser conhecida antes de ser chamada. Um protótipo 函数原型 — a linha do cabeçalho mais ; — a declara cedo para que você possa manter main em primeiro lugar. O escopo 作用域 de uma variável é o bloco onde ela existe: ele é local 局部 e desaparece quando o bloco termina.

    #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;
    }
    

    Erros comuns

    • Uma função usada antes de ser definida precisa de um protótipo acima de main.
    • Os argumentos são passados POR VALOR — alterações dentro de uma função não afetam quem chamou a menos que você passe um ponteiro.
    • Uma variável declarada dentro de uma função é local a ela.
  • 5 Arrays · ⁨Matrizes⁩
    5.1

    Arrays 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]).

    Português

    Um array 数组 armazena vários valores de um único tipo. Índice 索引 começa em 0. C não armazena o tamanho do array, então um truque comum calcula a contagem 元素 de elementos: 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;
    }
    
    As posições do array têm índices começando em 0
    As posições do array têm índices começando em 0
    5.2

    Algoritmos de arrays

    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.

    Português

    Traverse 遍历 um array com um loop for para encontrar um máximo, um total ou uma contagem. Sempre faça o loop de 0 até 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

    Arrays 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.
    Português

    Um array 2-D é uma grade de linhas 行 e colunas 列: grid[row][col]. Use dois loops aninhados para visitar cada célula.

    #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;
    }
    

    Erros comuns

    • C NÃO verifica os limites do array: escrever a[n] em um array de tamanho n é comportamento indefinido.
    • Índices válidos vão de 0 a n - 1.
    • O nome do array é um ponteiro para seu primeiro elemento; sizeof só dá o tamanho no próprio escopo do array.
  • 6 Pointers
    6.1

    &, * e passagem por ponteiro

    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.
    Português

    Um ponteiro 指针 armazena o endereço 地址 de uma variável. &x dá o endereço de x; *p dereferences 解引用 o ponteiro — ele lê ou escreve o valor armazenado lá. Passar um ponteiro permite que uma função mude a variável de quem chamou (passagem por ponteiro).

    Um ponteiro armazena um endereço; dereferenciá-lo segue a seta até o valor
    Um ponteiro armazena um endereço; dereferenciá-lo segue a seta até o valor
    #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;
    }
    

    O uso clássico é uma função de troca. Passar valores apenas os copia — a troca é perdida. Passar ponteiros permite que a função acesse as variáveis de quem chamado:

    #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;
    }
    

    Um nome de array age como um ponteiro para seu primeiro elemento, e a aritmética de ponteiros 指针运算 avança por elementos inteiros:

    #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 é o ponteiro que aponta para nada — verifique-o antes de dereferenciar.

    Erros comuns

    • &x é o endereço de x; *p é o valor armazenado em p.
    • Nunca use *p em um ponteiro não inicializado ou NULL — isso causa crash ou corrupção de memória.
    • Para mudar uma variável de quem chamado, passe seu endereço e escreva através do ponteiro.
  • 7 Strings
    7.1

    Arrays de chars e terminador nulo

    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'.

    Português

    Uma string C 字符串 é um array de char. Toda string termina com um terminador nulo oculto 空终止符 '\0', que marca onde ela termina. strlen (de <string.h>) conta caracteres até esse '\0'. Imprima uma string inteira com %s e um único caractere 字符 com %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;
    }
    
    Uma string C é um array de char terminando em um terminador nulo oculto
    Uma string C é um array de char terminando em um terminador nulo oculto

    Você pode traverse uma string fazendo um loop até encontrar '\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

    A biblioteca 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.
    Português

    #include <string.h> oferece as ferramentas cotidianas de string:

    Função Faz
    strlen(s) o comprimento, sem contar o terminador
    strcpy(dst, src) copiar — dst deve ser grande o suficiente
    strcat(dst, src) anexar src ao final de dst
    strcmp(a, b) comparar: 0 se iguais, senão negativo / positivo
    #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 retorna 0 para iguais, então o teste é strcmp(a, b) == 0 — nunca a == b.
    • O array de destino deve ter espaço para o resultado mais o terminador.

    Erros comuns

    • Uma string C precisa de um byte extra para o terminador \0: uma palavra de 5 letras precisa de char[6].
    • Copie e compare strings com strcpy / strcmp, não = / ==.
    • Esquecer o terminador \0 faz printf("%s", ...) passar do fim do texto.
  • 8 Structs
    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.
    Português

    Um struct 结构体 agrupa valores relacionados em um único tipo. Cada valor é um membro 成员. typedef dá um nome curto ao struct para que você possa escrever Dog em vez de struct Dog. Use . em um valor de struct, mas -> em um ponteiro para um 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;
    }
    

    Erros comuns

    • Use . em um valor de struct e -> em um ponteiro para uma struct.
    • typedef permite omitir a palavra struct na declaração; sem ela você escreve struct Point p;.
    • Atribuir um struct a outro copia todos os seus campos.
    . para valores de struct; -> para ponteiros para structs
    . para valores de struct; -> para ponteiros para structs
  • 9 Dynamic memory
    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.
    Português

    malloc aloca 分配 memória no heap 堆 em tempo de execução e devolve um ponteiro para ela. realloc redimensiona esse bloco; free a devolve. Todo malloc precisa de um free correspondente, ou você terá vazamento de memória 内存泄漏. Estes vivem em <stdlib.h>.

    Locais vivem na pilha; memória de malloc vive no heap até você fazer free
    Locais vivem na pilha; memória de malloc vive no heap até você fazer free
    #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) aloca um array como malloc E o preenche com zeros.

    Erros comuns

    • Todo malloc precisa de um free correspondente; esquecer de free causa vazamento de memória.
    • Usar memória após free (um "uso após liberação") é um bug grave.
    • Verifique se malloc não retornou NULL antes de usar a memória.
  • 10 Data structures
    10.1

    Listas encadeadas

    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.

    Português

    Uma lista encadeada 链表 é uma cadeia de nós 节点. Cada nó contém um valor e um ponteiro para o nó next; o último aponta para NULL. Diferente de um array, cresce um nó de cada vez com malloc. Sempre free cada nó quando terminar.

    Uma lista encadeada: cada nó segura um valor e um ponteiro para o próximo, terminando em NULL
    Uma lista encadeada: cada nó segura um valor e um ponteiro para o próximo, terminando em 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

    Pilhas e filas

    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.
    Português

    Uma pilha 栈 é LIFO 后进先出 (last in, first out): push e pop na mesma extremidade. Uma fila 队列 é FIFO 先进先出 (first in, first out): adiciona atrás, remove da frente. Ambas são fáceis de construir em um array com variáveis de índice.

    #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;
    }
    

    Erros comuns

    • Em uma lista encadeada, nunca perca o ponteiro head, caso contrário toda a lista ficará inacessível.
    • Free todos os nós quando terminar, percorrendo a lista antes de desvincular.
    • Verifique se há uma lista vazia (uma cabeça NULL) antes de fazer o pop.
  • 11 Searching, sorting & recursion
    11.1

    Busca linear e binária

    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.

    Português

    A busca linear 线性查找 verifica cada elemento por sua vez — funciona em qualquer array. A busca binária 二分查找 é muito mais rápida, mas exige um array ordenado 已排序: verifica o meio e descarta metade a cada passo. Ambas retornam o índice, ou -1 se ausente.

    #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
    }
    
    Linear varre tudo; binária divide ao meio um intervalo ordenado
    Linear varre tudo; binária divide ao meio um intervalo ordenado
    11.2

    Ordenação

    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.

    Português

    Bubble sort 冒泡排序 compara vizinhos repetidamente e troca 交换 qualquer par fora de ordem. Após cada passada, o maior valor "bolha" para o final.

    #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

    Recursão

    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.
    Português

    Recursão 递归 é uma função que se chama. Precisa de um caso base 基准情形 para parar, e de uma chamada recursiva que se aproxime dele. Sem um caso base, nunca termina.

    #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;
    }
    

    Erros comuns

    • Busca binária precisa de um array ordenado; recursão precisa de um caso base.
    • Cada chamada recursiva deve se aproximar do caso base, ou a pilha transborda.
    • Bubble e insertion sort são O(n²) — ótimos para aprender, lentos em escala.
  • 12 Files & errors
    12.1

    Arquivos de texto

    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.

    Português

    fopen devolve um ponteiro de arquivo 文件指针; a string de modo 模式 diz o que fazer — "w" escrever, "r" ler, "a" anexar. Escreva com fprintf, leia com fscanf, e sempre fclose quando terminar.

    #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 → read/write → fclose
    fopen → read/write → fclose
    12.2

    Tratamento de erros com códigos de retorno

    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.
    Português

    C não possui exceções. Em vez disso, uma função sinaliza falha com um código de retorno 返回码 — por convenção, 0 significa sucesso e zero não-nulo significa erro. O chamador verifica o código antes de confiar no resultado. (fopen segue a mesma ideia: retorna NULL quando falha.)

    #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;
    }
    

    Erros comuns

    • Verifique se fopen não retornou NULL antes de ler ou escrever.
    • Sempre feche fclose um arquivo quando terminar.
    • Retorne um código não-nulo de main para sinalizar um erro ao chamador.
  • 13 Bits & data
    13.1

    Bits, binário e operadores bit a 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:

    Português

    Um bit 位 é um único 0 ou 1; números são armazenados em binário 二进制. Operadores bitwise 按位 operam diretamente nos bits: & AND, | OR, ^ XOR, << deslocamento à esquerda (×2 a cada passo), >> deslocamento à direita (÷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;
    }
    

    Hexadecimal 十六进制 (base 16) escreve binário de forma compacta: um dígito hex corresponde exatamente a quatro bits. Escreva literais hex com 0x; imprima com %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;
    }
    
    Operadores bit a bit funcionam nos bits de inteiros
    Operadores bit a bit funcionam nos bits de inteiros
    13.2

    Codificação por comprimento de corrida

    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.
    Português

    Run-length encoding (RLE) é um método simples de compressão 压缩: substitui cada run 游程 de caracteres repetidos por uma contagem e o caractere. É lossless 无损 — o original é totalmente recuperável.

    #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;
    }
    

    Erros comuns

    • & é AND bitwise e && é AND lógico — não os confunda.
    • Um deslocamento à esquerda << 1 dobra um valor; um deslocamento à direita >> 1 o divide pela metade.
    • O bit n tem valor 1 << n (C não possui operador de potência **); verifique um bit com (x >> n) & 1.
  • 14 Preprocessor & qualifiers
    14.1

    Preprocessor, 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.
    Português

    O pré-processador 预处理器 roda antes da compilação. #define cria uma macro 宏 — texto puro substituído em todo lugar. const cria uma constante 常量 que não pode mudar. static dentro de uma função mantém o valor de uma variável entre chamadas. Uma enum (enumeration 枚举) nomeia um conjunto de inteiros começando em 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;
    }
    

    Programas maiores dividem-se entre arquivos: declarações vão em um arquivo de cabeçalho 头文件 (mine.h), incluído com #include "mine.h" — aspas significam seu próprio arquivo, < > significa a biblioteca padrão. Um guard de inclusão (#ifndef MINE_H / #define MINE_H / #endif) impede que um header seja incluído duas vezes.

    Erros comuns

    • #define faz substituição de texto simples sem verificação de tipo; encolha os corpos e argumentos da macro em parênteses.
    • Um valor const não pode ser alterado após ser definido.
    • Uma variável local static mantém seu valor entre chamadas à função.
    #define, const, enum e static mantêm o código claro
    #define, const, enum e static mantêm o código claro

Log in or create account · ⁨Entrar ou criar conta⁩

IGCSE, A-Level & AP