TIC 5 · Linguagem C
Programação de Sistemas · Do zero ao avançado

Aprender
Linguagem C

Recursos educativos para dominar a linguagem que está na base de sistemas operativos, microcontroladores e toda a computação moderna.

▶ Começar aqui 🏋️ Exercícios 📋 Referência Rápida 🌐 Compiladores Online
/* hello.c — o primeiro programa em C */ #include <stdio.h> int main() { printf("Olá, Mundo!\n"); return 0; } $ gcc hello.c -o hello && ./hello Olá, Mundo!
1972Ano de criação
#1TIOBE há 50 anos
9Módulos de estudo
30+Exercícios + soluções
01 · Fundamentos

📖 O que é a linguagem C?

Antes de escrever código, é essencial perceber porque C continua a ser a linguagem mais importante da computação moderna.

O C é uma linguagem de programação de propósito geral criada por Dennis Ritchie nos laboratórios Bell entre 1969 e 1973. Nasceu para reescrever o Unix — e esta origem moldou tudo: C é eficiente, próxima do hardware, mas ainda assim portável.

Hoje, o kernel do Linux, o macOS, o Windows, o Python, o MySQL, o SQLite, o Redis e praticamente todos os sistemas operativos e infraestruturas críticas estão escritos em C ou em linguagens derivadas de C.

🟢 C é a linguagem certa quando

  • Precisas de controlo total sobre a memória
  • O desempenho é crítico (sistemas, jogos, embeddes)
  • Programas para microcontroladores (Arduino, RPi)
  • Queres entender como a computação funciona por dentro
  • Escreves bibliotecas usadas por outras linguagens
  • O ambiente tem recursos muito limitados (RAM, CPU)

🔴 C não é ideal quando

  • Escreves aplicações web ou GUIs modernas
  • Precisas de desenvolvimento rápido
  • A segurança de memória automática é prioridade
  • Trabalhas com strings complexas ou listas dinâmicas
  • O projeto tem poucos requisitos de performance
  • A equipa não tem experiência com ponteiros

Velocidade máxima

Código C compilado compete com Assembly. Zero overhead de runtime, sem garbage collector.

🎛️

Controlo de memória

Tu decides quando alocar e libertar memória. Poder absoluto — e responsabilidade absoluta.

🌍

Portabilidade

O mesmo código corre em x86, ARM, RISC-V, microcontroladores de 8 bits ou supercomputadores.

🧬

Pai de todas as linguagens

C++, Java, C#, Python, JavaScript, PHP, Rust — todas beberam da sintaxe e filosofia de C.

🔧

Hardware direto

Acesso a registos, endereços de memória e periféricos. O Arduino usa C/C++ por uma razão.

📚

Base para aprender mais

Quem entende C, entende como qualquer linguagem funciona por baixo. É o melhor investimento.

💡
Analogia: Aprender C é como aprender a conduzir num carro manual antes de passar para automático. É mais exigente no início, mas depois consegues conduzir qualquer coisa — e percebes porque o carro automático faz o que faz.
02 · Estrutura

📚 Programa de Formação

Segue esta ordem para uma progressão lógica — cada módulo constrói sobre o anterior.

03 · Referência

💻 Referência Rápida — Sintaxe Essencial

Os padrões mais usados no dia a dia de qualquer programador C.

tipos_e_io.c
#include <stdio.h>

int main() {
    /* ── Tipos básicos ── */
    int    inteiro  = 42;
    float  decimal  = 3.14f;
    double preciso  = 3.14159265;
    char   letra    = 'A';
    char   texto[]  = "Olá, C!";

    /* ── Tamanho em bytes ── */
    printf("int: %zu bytes\n", sizeof(int));

    /* ── Leitura do utilizador ── */
    int n;
    printf("Introduz um número: ");
    scanf("%d", &n);   /* & = endereço de n */
    printf("Escreveste: %d\n", n);

    /* ── Condições ── */
    if (n > 0) {
        printf("Positivo\n");
    } else if (n < 0) {
        printf("Negativo\n");
    } else {
        printf("Zero\n");
    }

    /* ── Ciclo for ── */
    for (int i = 0; i < 5; i++) {
        printf("i = %d\n", i);
    }

    return 0;
}

Especificadores de formato

EspecificadorTipoExemplo
%d ou %iintprintf("%d", 42)42
%ffloat / doubleprintf("%.2f", 3.14)3.14
%ccharprintf("%c", 'A')A
%sstring (char*)printf("%s", "oi")oi
%pponteiro (endereço)printf("%p", &x)0x7ffd...
%zusize_t (sizeof)printf("%zu", sizeof(int))4
%ldlong intprintf("%ld", 1000000L)
%lfdouble (scanf)scanf("%lf", &x)
funcoes.c
#include <stdio.h>

/* Protótipo — declara antes de main */
int somar(int a, int b);
void trocar(int *a, int *b);
int fatorial(int n);

int main() {
    int x = 5, y = 3;
    printf("%d + %d = %d\n", x, y, somar(x, y));

    trocar(&x, &y);  /* passa endereços! */
    printf("Depois da troca: x=%d y=%d\n", x, y);

    printf("5! = %d\n", fatorial(5));
    return 0;
}

/* Passagem por valor — recebe cópias */
int somar(int a, int b) {
    return a + b;
}

/* Passagem por referência — altera os originais */
void trocar(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

/* Recursividade */
int fatorial(int n) {
    if (n <= 1) return 1;
    return n * fatorial(n - 1);
}
$ ./funcoes
5 + 3 = 8
Depois da troca: x=3 y=5
5! = 120
arrays_strings.c
#include <stdio.h>
#include <string.h>

int main() {
    /* ── Arrays ── */
    int nums[5] = {10, 20, 30, 40, 50};

    for (int i = 0; i < 5; i++)
        printf("nums[%d] = %d\n", i, nums[i]);

    /* ── Array 2D (matriz) ── */
    int mat[2][3] = {{1,2,3},{4,5,6}};
    printf("mat[1][2] = %d\n", mat[1][2]);  // 6

    /* ── Strings ── */
    char nome[20] = "Alice";
    char apelido[] = "Silva";
    char completo[40];

    strcpy(completo, nome);       // copia nome → completo
    strcat(completo, " ");        // concatena espaço
    strcat(completo, apelido);    // concatena apelido

    printf("Nome completo: %s\n", completo);
    printf("Comprimento: %zu\n", strlen(completo));
    printf("Comparação: %d\n", strcmp(nome, "Alice")); // 0 = iguais

    return 0;
}
nums[0] = 10 nums[1] = 20 ... mat[1][2] = 6
Nome completo: Alice Silva · Comprimento: 11
structs.c
#include <stdio.h>
#include <string.h>

/* typedef + struct em conjunto */
typedef struct {
    char  nome[50];
    int   idade;
    float nota;
} Aluno;

void imprimir(Aluno a) {
    printf("%-20s %2d anos  %.1f\n",
           a.nome, a.idade, a.nota);
}

int main() {
    /* Inicialização direta */
    Aluno a1 = {"Ana Martins", 17, 18.5f};

    /* Atribuição por campo */
    Aluno a2;
    strcpy(a2.nome, "João Costa");
    a2.idade = 16;
    a2.nota  = 14.2f;

    /* Array de structs */
    Aluno turma[2] = {a1, a2};

    printf("%-20s %-7s %s\n", "Nome", "Idade", "Nota");
    printf("%-20s %-7s %s\n", "----", "-----", "----");
    for (int i = 0; i < 2; i++)
        imprimir(turma[i]);

    return 0;
}
Nome Idade Nota
Ana Martins 17 anos 18.5
João Costa 16 anos 14.2
alocacao_dinamica.c
#include <stdio.h>
#include <stdlib.h>   /* malloc, calloc, free */

int main() {
    int n;
    printf("Quantos inteiros? ");
    scanf("%d", &n);

    /* malloc — aloca n * 4 bytes no HEAP */
    int *arr = (int *) malloc(n * sizeof(int));

    if (arr == NULL) {
        fprintf(stderr, "Erro: sem memória!\n");
        return 1;
    }

    for (int i = 0; i < n; i++)
        arr[i] = i * 10;

    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");

    free(arr);   /* SEMPRE libertar! memory leak se não o fizeres */
    arr = NULL;  /* boas práticas: evitar dangling pointer */

    return 0;
}
⚠️
Memory Leak: Se chamares malloc e não chamares free, a memória fica alocada até o programa terminar. Em programas longos, isto pode esgotar toda a RAM do sistema.
ficheiros.c
#include <stdio.h>

int main() {
    /* ── Escrever num ficheiro ── */
    FILE *fp = fopen("dados.txt", "w");
    if (!fp) { perror("Erro ao abrir"); return 1; }

    fprintf(fp, "Linha 1: C é incrível!\n");
    fprintf(fp, "Linha 2: valor = %d\n", 42);
    fclose(fp);

    /* ── Ler do ficheiro ── */
    fp = fopen("dados.txt", "r");
    char linha[100];

    while (fgets(linha, sizeof(linha), fp) != NULL)
        printf("%s", linha);

    fclose(fp);
    return 0;
}

/* Modos fopen:
   "r"  — ler (ficheiro deve existir)
   "w"  — escrever (cria ou trunca)
   "a"  — acrescentar ao fim
   "r+" — ler e escrever
   "b"  — modo binário (ex: "rb", "wb") */
04 · Conceito Fundamental

🎯 Ponteiros — O Coração de C

Ponteiros são o conceito mais poderoso — e mais temido — de C. Visualizados corretamente, ficam simples.

Um ponteiro é uma variável que guarda um endereço de memória. Em vez de guardar o valor 42, guarda "o valor 42 está na posição 0x7ffc".

Modelo de Memória de um Processo C
TEXT
Código compilado (instruções da CPU). Só leitura.
0x0000...
DATA
Variáveis globais inicializadas.
int x = 5;
BSS
Variáveis globais não inicializadas (zeroed).
int y;
HEAP ↑
Alocação dinâmica. malloc/free. Cresce para cima.
malloc()
STACK ↓
Variáveis locais, parâmetros. Cresce para baixo.
int n = 3;

Visualização de ponteiro

MEMÓRIA DO PROCESSO — cada célula = 4 bytes (int)
Variável
Valor
Endereço
Código C
x
42
0x7ffc0010
int x = 42;
p
0x7ffc0010
0x7ffc0020
int *p = &x;  /* p aponta para x */
&x = endereço de x = 0x7ffc0010  |  *p = valor apontado por p = 42  |  p == &x → true
ponteiros.c
#include <stdio.h>

int main() {
    int  x = 42;
    int *p = &x;  /* p guarda o endereço de x */

    printf("x        = %d\n", x);      // 42
    printf("&x       = %p\n", &x);     // endereço de x
    printf("p        = %p\n", p);      // mesmo endereço
    printf("*p       = %d\n", *p);     // 42 (desreferência)

    /* Alterar x ATRAVÉS do ponteiro */
    *p = 100;
    printf("x agora  = %d\n", x);     // 100!

    /* Aritmética de ponteiros */
    int arr[] = {10, 20, 30};
    int *q = arr;  /* arr é o endereço do 1º elemento */
    printf("%d %d %d\n", *q, *(q+1), *(q+2));  // 10 20 30

    return 0;
}
⚠️
Ponteiro nulo e dangling pointer: Nunca desreferencies um ponteiro NULL (*p quando p == NULL) — causa segmentation fault. Após free(), faz sempre p = NULL para evitar usar um "dangling pointer" (ponteiro para memória já libertada).
05 · Prática

🏋️ Exercícios de Treino

Pratica com estes desafios progressivos. Cada exercício tem dicas e solução completa — tenta resolver antes de ver!

Iniciante
EX. 01

Olá, utilizador!

Escreve um programa que peça o nome e a idade do utilizador e apresente uma mensagem de saudação personalizada.

printfscanf%s%d
Objetivos
  • Usar scanf para ler uma string e um inteiro
  • Usar printf com múltiplos especificadores
  • Calcular o ano de nascimento a partir da idade
Dicas para resolver
  • Para ler uma string com scanf usa %s e o array sem & (já é endereço)
  • Define o array de nome com tamanho suficiente: char nome[50];
  • O ano de nascimento é aproximadamente 2025 - idade
  • Para ler uma string com espaços usa fgets(nome, 50, stdin) em vez de scanf
ex01_ola.c
#include <stdio.h>

int main() {
    char nome[50];
    int  idade;

    printf("Qual é o teu nome? ");
    scanf("%49s", nome);   /* %49s limita a 49 chars */

    printf("Qual é a tua idade? ");
    scanf("%d", &idade);

    printf("\nOlá, %s!\n", nome);
    printf("Tens %d anos.\n", idade);
    printf("Nasceste por volta de %d.\n", 2025 - idade);

    return 0;
}
$ ./ex01
Qual é o teu nome? Ana
Qual é a tua idade? 17

Olá, Ana!
Tens 17 anos.
Nasceste por volta de 2008.
EX. 02

Calculadora básica

Lê dois números e um operador (+, -, *, /) e apresenta o resultado. Trata a divisão por zero.

switchfloatdivisão por zero
Objetivos
  • Usar switch/case para selecionar a operação
  • Trabalhar com float para resultados decimais
  • Validar entrada — tratar divisão por zero
Dicas para resolver
  • Lê o operador como char op; scanf(" %c", &op); (espaço antes de %c ignora espaços em branco)
  • No case da divisão, verifica se o divisor é 0 antes de dividir
  • Usa float ou double para os números para obter resultados decimais
ex02_calc.c
#include <stdio.h>

int main() {
    double a, b;
    char op;

    printf("Expressão (ex: 3.5 + 2): ");
    scanf("%lf %c %lf", &a, &op, &b);

    printf("%.4g %c %.4g = ", a, op, b);

    switch (op) {
        case '+': printf("%.6g\n", a + b); break;
        case '-': printf("%.6g\n", a - b); break;
        case '*': printf("%.6g\n", a * b); break;
        case '/':
            if (b == 0.0) {
                printf("Erro: divisão por zero!\n");
            } else {
                printf("%.6g\n", a / b);
            }
            break;
        default:
            printf("Operador desconhecido '%c'\n", op);
    }
    return 0;
}
EX. 03

Tabuada com ciclo for

Pede um número ao utilizador e apresenta a sua tabuada completa (de 1 a 10) formatada em tabela.

forformatação%3d
Dicas
  • Usa %3d para alinhar números à direita em 3 espaços
  • O ciclo vai de i=1 a i<=10
  • Bónus: mostra a tabuada de todos os números de 1 a N num ciclo duplo
ex03_tabuada.c
#include <stdio.h>

int main() {
    int n;
    printf("Tabuada de que número? ");
    scanf("%d", &n);

    printf("\n── Tabuada do %d ──\n", n);
    for (int i = 1; i <= 10; i++) {
        printf("%2d × %2d = %3d\n", n, i, n * i);
    }
    return 0;
}
── Tabuada do 7 ──
7 × 1 = 7
7 × 2 = 14
7 × 3 = 21
... 7 × 10 = 70
EX. 04

Verificar número primo

Cria uma função isPrimo(n) e usa-a para listar todos os primos até um N introduzido pelo utilizador.

funçõesformódulo %return
Dicas
  • Um número é primo se só for divisível por 1 e por si próprio
  • Basta testar divisores até √n — otimização importante
  • 1 não é primo por definição; 2 e 3 são primos
  • Usa #include <math.h> e sqrt(n) — compila com gcc -lm
ex04_primos.c
#include <stdio.h>
#include <math.h>

int isPrimo(int n) {
    if (n < 2) return 0;
    if (n == 2) return 1;
    if (n % 2 == 0) return 0;

    for (int i = 3; i <= (int)sqrt(n); i += 2) {
        if (n % i == 0) return 0;
    }
    return 1;
}

int main() {
    int n, count = 0;
    printf("Primos até N: ");
    scanf("%d", &n);

    printf("\nPrimos até %d:\n", n);
    for (int i = 2; i <= n; i++) {
        if (isPrimo(i)) {
            printf("%4d", i);
            if (++count % 10 == 0) printf("\n");
        }
    }
    printf("\n\nTotal: %d primos\n", count);
    return 0;
}
Intermédio
EX. 05

Ordenação por borbulhamento (Bubble Sort)

Lê N inteiros do utilizador para um array e ordena-os com o algoritmo bubble sort. Mostra o array antes e depois.

arraysnested forswapalgoritmo
Dicas
  • Bubble sort: percorre o array N vezes, comparando pares adjacentes e trocando se fora de ordem
  • Cria uma função void bubbleSort(int arr[], int n)
  • A troca de dois valores precisa de uma variável temporária: int temp = a; a = b; b = temp;
  • Otimização: se numa passagem não houver trocas, o array já está ordenado — podes parar
ex05_bubblesort.c
#include <stdio.h>

void imprimir(int arr[], int n) {
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int trocou = 0;
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j]   = arr[j + 1];
                arr[j + 1] = temp;
                trocou = 1;
            }
        }
        if (!trocou) break;  /* otimização */
    }
}

int main() {
    int n;
    printf("Quantos números? ");
    scanf("%d", &n);

    int arr[n];
    printf("Introduz %d inteiros:\n", n);
    for (int i = 0; i < n; i++)
        scanf("%d", &arr[i]);

    printf("Antes: "); imprimir(arr, n);
    bubbleSort(arr, n);
    printf("Depois: "); imprimir(arr, n);

    return 0;
}
EX. 06

Gestão de alunos com struct

Cria um array de structs Aluno (nome, número, notas). Calcula a média de cada aluno e lista o melhor e o pior da turma.

structtypedefarraysfunções
Dicas
  • Define a struct com typedef struct { char nome[50]; int num; float notas[3]; float media; } Aluno;
  • Cria uma função float calcMedia(float notas[], int n) que recebe o array de notas
  • Para encontrar o melhor, percorre o array guardando o índice do maior média
ex06_alunos.c
#include <stdio.h>
#include <string.h>
#define MAX_ALUNOS 3
#define N_NOTAS    3

typedef struct {
    char  nome[50];
    int   numero;
    float notas[N_NOTAS];
    float media;
} Aluno;

float calcMedia(float notas[], int n) {
    float soma = 0;
    for (int i = 0; i < n; i++) soma += notas[i];
    return soma / n;
}

int main() {
    Aluno turma[MAX_ALUNOS] = {
        {"Ana Silva",   101, {18.0f, 16.5f, 19.0f}},
        {"Bruno Costa", 102, {12.0f, 14.0f, 10.5f}},
        {"Carla Matos", 103, {15.5f, 17.0f, 16.0f}},
    };

    int melhor = 0, pior = 0;

    printf("%-15s %4s  %s\n", "Nome", "Num", "Média");
    printf("%-15s %4s  %s\n", "----", "---", "-----");

    for (int i = 0; i < MAX_ALUNOS; i++) {
        turma[i].media = calcMedia(turma[i].notas, N_NOTAS);
        printf("%-15s %4d  %.1f\n",
            turma[i].nome, turma[i].numero, turma[i].media);
        if (turma[i].media > turma[melhor].media) melhor = i;
        if (turma[i].media < turma[pior].media)   pior   = i;
    }

    printf("\n🥇 Melhor: %s (%.1f)\n",
           turma[melhor].nome, turma[melhor].media);
    printf("📉 Pior:   %s (%.1f)\n",
           turma[pior].nome,   turma[pior].media);

    return 0;
}
EX. 07

Inverter uma string sem biblioteca

Implementa a tua própria função inverterStr que inverte uma string no próprio lugar usando dois ponteiros.

ponteirosstringsaritmética de ponteiros
Dicas
  • Usa dois ponteiros: inicio apontando para o 1º char, fim para o último (antes de '\0')
  • Troca os caracteres apontados e move os ponteiros para o centro
  • Para chegar ao fim da string sem strlen: incrementa fim até *fim == '\0', depois recua um
ex07_inverter.c
#include <stdio.h>

void inverterStr(char *s) {
    if (!s || !*s) return;

    char *inicio = s;
    char *fim    = s;

    /* avançar fim até ao '\0', depois recuar */
    while (*fim) fim++;
    fim--;

    while (inicio < fim) {
        char temp = *inicio;
        *inicio   = *fim;
        *fim      = temp;
        inicio++;
        fim--;
    }
}

int main() {
    char s[] = "Linguagem C";
    printf("Original: %s\n", s);
    inverterStr(s);
    printf("Invertida: %s\n", s);
    return 0;
}
Original: Linguagem C
Invertida: C megaugniL
Avançado
EX. 08

Lista ligada simples

Implementa uma lista ligada com operações: inserir no início, inserir no fim, remover por valor e imprimir.

mallocstructponteirosfreelista ligada
Dicas
  • Define o nó: typedef struct No { int val; struct No *prox; } No; — nota o uso de struct No * dentro da própria struct
  • A lista é apenas um ponteiro para o primeiro nó (cabeça)
  • Para inserir no início: cria nó, aponta prox para a cabeça atual, actualiza cabeça
  • Para remover, cuida do caso especial de remover a cabeça
ex08_lista.c
#include <stdio.h>
#include <stdlib.h>

typedef struct No {
    int          val;
    struct No   *prox;
} No;

No* criarNo(int val) {
    No *n = (No*) malloc(sizeof(No));
    n->val  = val;
    n->prox = NULL;
    return n;
}

void inserirInicio(No **head, int val) {
    No *n  = criarNo(val);
    n->prox = *head;
    *head  = n;
}

void imprimir(No *head) {
    printf("HEAD");
    for (No *cur = head; cur; cur = cur->prox)
        printf(" → %d", cur->val);
    printf(" → NULL\n");
}

void libertar(No **head) {
    No *cur = *head;
    while (cur) {
        No *prox = cur->prox;
        free(cur);
        cur = prox;
    }
    *head = NULL;
}

int main() {
    No *lista = NULL;
    inserirInicio(&lista, 30);
    inserirInicio(&lista, 20);
    inserirInicio(&lista, 10);
    imprimir(lista);     // HEAD → 10 → 20 → 30 → NULL
    libertar(&lista);
    return 0;
}
EX. 09

Agenda de contactos com ficheiro

Cria uma mini-agenda que guarda contactos (nome + telefone) num ficheiro .txt. Permite adicionar, listar e pesquisar por nome.

ficheirosstructfwrite/freadmenu
Dicas
  • Guarda os contactos em modo binário com fwrite(&c, sizeof(Contacto), 1, fp) — é mais eficiente que texto
  • Para ler todos: abre em "rb" e faz while(fread(&c, sizeof(Contacto), 1, fp) == 1)
  • Para pesquisar: carrega todos os contactos e compara com strstr (pesquisa parcial)
  • Cria um menu com do-while e switch
ex09_agenda.c
#include <stdio.h>
#include <string.h>
#define FICHEIRO "agenda.dat"

typedef struct {
    char nome[50];
    char tel[20];
} Contacto;

void adicionar() {
    Contacto c;
    printf("Nome: "); scanf("%49s", c.nome);
    printf("Tel:  "); scanf("%19s", c.tel);
    FILE *fp = fopen(FICHEIRO, "ab");
    fwrite(&c, sizeof(Contacto), 1, fp);
    fclose(fp);
    printf("✓ Contacto guardado.\n");
}

void listar() {
    Contacto c;
    FILE *fp = fopen(FICHEIRO, "rb");
    if (!fp) { printf("Agenda vazia.\n"); return; }
    printf("\n%-20s %s\n", "Nome", "Telefone");
    printf("%-20s %s\n", "----", "--------");
    while (fread(&c, sizeof(Contacto), 1, fp) == 1)
        printf("%-20s %s\n", c.nome, c.tel);
    fclose(fp);
}

int main() {
    int op;
    do {
        printf("\n[1] Adicionar [2] Listar [0] Sair: ");
        scanf("%d", &op);
        switch(op) {
            case 1: adicionar(); break;
            case 2: listar();    break;
        }
    } while (op != 0);
    return 0;
}
06 · Desafios

🚀 Desafios Finais — Projetos Completos

Projetos integrados que combinam múltiplos conceitos. Para resolver sem dicas — desafio real.

🏦

Sistema Bancário

Conta bancária com struct. Operações: depositar, levantar, transferir, ver extrato. Persistência em ficheiro binário.

struct + ficheiros
📖

Dicionário C → PT

Hash table simples com array de strings. Guardar pares palavra/tradução. Pesquisa e remoção eficiente.

ponteiros + malloc
🎮

Jogo da Forca

Escolhe palavra aleatória de um array. Lê letras, mostra progresso e tentativas. Valida vitória/derrota.

strings + arrays
📊

Analisador de CSV

Lê um ficheiro CSV de notas, calcula estatísticas (média, mín, máx, desvio padrão) e gera relatório.

ficheiros + math.h
🔢

Calculadora RPN

Calculadora em notação polaca reversa com stack (pilha). Implementa a pilha com malloc. Suporta +, -, *, /.

stack + malloc
🌡️

Monitor de Sensor (RPi)

Ler dados de um sensor (DHT11 via GPIO), guardar leituras num ficheiro CSV com timestamp e gerar alertas.

ficheiros + GPIO C
07 · Ferramentas

🌐 Compiladores Online & Recursos

Pratica C diretamente no browser, sem instalar nada. Todos são gratuitos.

Compilar e executar localmente

Terminal (Linux / macOS / WSL)
# Instalar GCC (Linux)
sudo apt install gcc

# Compilar um ficheiro
gcc hello.c -o hello

# Compilar com avisos e padrão C11
gcc -Wall -Wextra -std=c11 hello.c -o hello

# Compilar com math.h
gcc programa.c -o programa -lm

# Executar
./hello

# Detetar memory leaks com Valgrind
valgrind --leak-check=full ./programa

# Compilar para debugging (GDB)
gcc -g programa.c -o programa
💡
Windows: Instala o MSYS2 para ter gcc nativo, ou usa o WSL (Windows Subsystem for Linux) para um ambiente Linux completo. Alternativamente, o Dev-C++ ou Code::Blocks são IDEs com compilador incluído.