{"id":"43676f01-d4e3-4d51-a851-3d6aa4f7de53","name":"Aprenda a pensar como programador do zero, escrevendo programas em C","description":"Esta trilha é para quem nunca programou ou quer firmar a base. Você vai do primeiro \"olá\" na tela até ordenar e buscar dados, entender ponteiros e alocar memória, sempre praticando. São 9 módulos com vídeos, textos e artigos curtos. Cada módulo fecha com uma revisão de múltipla escolha e dois desafios de código, corrigidos na hora pela própria plataforma. Não precisa instalar nada: você escreve e testa o código direto no navegador.","coverUrl":"/public/files/course-covers/43676f01-d4e3-4d51-a851-3d6aa4f7de53/e93202c6-7643-46ab-8184-f67498392721.webp","ownerNickname":"lucascode","activatedAt":"2026-10-28T11:55:40.528215","modules":[{"id":"1f8499da-f661-4548-93ea-69b741902351","title":"Primeiros passos","description":"Entenda o que é um programa, como o código em C vira algo que o computador executa e escreva suas primeiras mensagens na tela com printf. Ao final, você reconhece a estrutura mínima de um programa em C e sabe compilar e executar.","position":1,"contents":[{"id":"935ef7c2-df02-42ca-b4c0-6a897af9191c","type":"YOUTUBE","title":"Linguagem C começando do absoluto zero","position":1,"description":"Apresentação da linguagem C para quem nunca programou, por Pietro Martins De Oliveira. Cerca de 6 minutos.","availability":"AVAILABLE","youtube":{"videoId":"2w8GYzBjNj8","url":"https://www.youtube.com/watch?v=2w8GYzBjNj8","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"eafda11d-40e8-414f-8ae8-9a3816c19a7d","type":"YOUTUBE","title":"Mostrando mensagens com printf","position":2,"description":"Saída de dados com printf, quebras de linha e primeiros formatos, por Pietro Martins De Oliveira. Cerca de 14 minutos.","availability":"AVAILABLE","youtube":{"videoId":"eK9lfMmkDe0","url":"https://www.youtube.com/watch?v=eK9lfMmkDe0","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"da4e5d51-36c4-47b2-9f81-1197faef74ab","type":"TEXT","title":"Do código ao programa","position":3,"description":"O que é um programa, o papel do compilador, a estrutura de main e o uso de printf, com exemplos e erros comuns.","availability":"AVAILABLE","text":{"body":"Um **programa** é uma sequência de instruções que o computador executa, uma depois da outra. Em C, você escreve essas instruções num arquivo de texto chamado **código-fonte**, normalmente com a extensão `.c`.\n\nO computador não entende C diretamente. Um programa especial, o **compilador**, lê o seu código, confere se ele segue as regras da linguagem e gera um **executável**: o arquivo que realmente roda. Nesta trilha usamos o padrão C17 com o compilador GCC 14, que é o mesmo usado pela plataforma para conferir os desafios.\n\n#### Compilar e executar\n\nNum terminal com o GCC instalado, os dois passos são estes:\n\n```text\ngcc -std=c17 -Wall -Wextra ola.c -o ola\n./ola\n```\n\nO primeiro comando compila `ola.c` e cria o executável `ola`. As opções `-Wall` e `-Wextra` pedem ao compilador que mostre **avisos** (warnings): trechos que compilam, mas provavelmente estão errados. Trate todo aviso como um problema a corrigir. O segundo comando executa o programa.\n\nSe o compilador encontrar um **erro**, ele não gera o executável e mostra o arquivo, a linha e uma mensagem. Leia sempre a primeira mensagem: os erros seguintes costumam ser consequência dela.\n\n#### A estrutura mínima de um programa\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    printf(\"Olá, mundo!\\n\");\n    return 0;\n}\n```\n\nLinha por linha:\n\n- `#include <stdio.h>` traz para o programa as funções de entrada e saída, como `printf` e `scanf`. Sem essa linha, o compilador não conhece `printf`.\n- `int main(void)` declara a função **main**. Todo programa em C começa a executar por ela. O `int` indica que main devolve um número inteiro ao sistema; o `void` indica que ela não recebe nada.\n- As chaves `{` e `}` delimitam o **corpo** de main: tudo o que está entre elas é executado em ordem.\n- `printf(\"Olá, mundo!\\n\");` mostra o texto entre aspas. O `\\n` é uma **quebra de linha**.\n- `return 0;` encerra main e avisa ao sistema que tudo correu bem.\n- Toda instrução termina com ponto e vírgula `;`.\n\n#### Várias mensagens\n\nCada `printf` continua exatamente de onde o anterior parou. Só existe quebra de linha quando você escreve `\\n`.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    printf(\"Linha 1\\n\");\n    printf(\"Linha \");\n    printf(\"2\\n\");\n    printf(\"Aspas dentro do texto: \\\"C\\\"\\n\");\n    printf(\"Uma barra invertida: \\\\\\n\");\n    return 0;\n}\n```\n\nSaída:\n\n```text\nLinha 1\nLinha 2\nAspas dentro do texto: \"C\"\nUma barra invertida: \\\n```\n\nAs sequências que começam com barra invertida são chamadas de **sequências de escape**: `\\n` (nova linha), `\\\"` (aspas) e `\\\\` (a própria barra).\n\n#### Comentários\n\nComentários são anotações para pessoas. O compilador ignora todos eles.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    // Comentário de uma linha\n    /* Comentário que pode\n       ocupar várias linhas */\n    printf(\"Comentários não aparecem na saída\\n\");\n    return 0;\n}\n```\n\n#### Erros comuns\n\n- **Esquecer o ponto e vírgula.** O compilador costuma apontar a linha seguinte, porque só lá percebe que faltou o `;`.\n- **Escrever `Printf` ou `Main`.** C diferencia letras maiúsculas e minúsculas: `printf` e `Printf` são nomes diferentes.\n- **Esquecer o `\\n` no final.** A saída fica grudada na próxima linha do terminal e, nos desafios, pode não bater com a saída esperada.\n- **Esquecer o `#include` de stdio.h.** O GCC 14 trata o uso de `printf` sem declaração como erro.\n- **Abrir aspas e não fechar.** O texto precisa começar e terminar com aspas na mesma linha.\n\n#### Como os desafios conferem seu programa\n\nNos desafios de programação desta trilha, a plataforma executa seu programa, entrega os dados de entrada e compara a saída com a saída esperada. Por isso, imprima **somente** o que o enunciado pede: nada de mensagens como \"Digite um número\" ou \"O resultado é\". Espaços e letras contam.","published":true}},{"id":"2b9291b7-012f-48cb-981c-07b54e53e9be","type":"EXTERNAL_ARTICLE","title":"Primeiros passos em C no material do CPDEE/UFMG","position":4,"description":"Material clássico em português sobre os primeiros programas em C. É anterior ao C17: confira os exemplos com o texto desta trilha.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c200.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"044ca00c-5abf-46f8-88c6-12930324c5df","type":"QUIZ","title":"Revisão: primeiros passos","position":5,"description":"Cinco perguntas para conferir os conceitos do módulo. Você pode tentar quantas vezes quiser.","availability":"AVAILABLE","assessmentId":"c42d5138-e4f7-485b-ab4d-d00a57fd1f8e"},{"id":"25078493-1315-43b4-a5ee-fd51c00b2884","type":"QUIZ","title":"Prática: primeiros programas","position":6,"description":"Desafios de programação em C sobre printf, sequências de escape e a estrutura de main.","availability":"AVAILABLE","assessmentId":"e53a9bca-3d8b-45ce-859b-cbbe3b6daae3"}]},{"id":"c88e1f94-2b0a-4c5c-a6cc-bbb39709402a","title":"Variáveis, tipos e entrada de dados","description":"Guarde valores em variáveis, conheça os tipos int, double e char, leia dados com scanf e faça contas. Atenção especial à divisão entre inteiros e ao operador de resto, que aparecem em muitos problemas.","position":2,"contents":[{"id":"800d794c-a130-4607-b53f-e6743f51064e","type":"YOUTUBE","title":"Variáveis e atribuição com o operador =","position":1,"description":"O que é uma variável e como atribuir valores em C, por Pietro Martins De Oliveira. Cerca de 16 minutos.","availability":"AVAILABLE","youtube":{"videoId":"tfLC_huv-Ko","url":"https://www.youtube.com/watch?v=tfLC_huv-Ko","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"b96669ec-4cce-4dec-856e-05036b4917a5","type":"YOUTUBE","title":"Lendo dados com scanf","position":2,"description":"Entrada de dados com scanf e o uso do &, por Pietro Martins De Oliveira. Cerca de 15 minutos.","availability":"AVAILABLE","youtube":{"videoId":"cKagvm-BiwI","url":"https://www.youtube.com/watch?v=cKagvm-BiwI","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"c8f5813b-bf7a-4f1b-ae92-ad3463e7d8d7","type":"TEXT","title":"Variáveis, tipos, scanf e operações","position":3,"description":"Declaração de variáveis, os tipos int, double e char, formatos de printf e scanf, divisão inteira, resto e erros comuns.","availability":"AVAILABLE","text":{"body":"Uma **variável** é um espaço na memória com um nome e um tipo. O tipo diz que tipo de valor cabe ali e quanto espaço ele ocupa.\n\n#### Declarar e atribuir\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int idade = 16;          // número inteiro\n    double altura = 1.72;    // número com casas decimais\n    char turma = 'B';        // um único caractere, entre aspas simples\n\n    idade = idade + 1;       // o valor antigo é substituído pelo novo\n\n    printf(\"%d\\n\", idade);\n    printf(\"%.2f\\n\", altura);\n    printf(\"%c\\n\", turma);\n    return 0;\n}\n```\n\nSaída:\n\n```text\n17\n1.72\nB\n```\n\nO sinal `=` em C significa **atribuição**: calcule o lado direito e guarde o resultado na variável do lado esquerdo. Ele não é uma comparação.\n\nRegras para nomes: use letras, dígitos e `_`, sem começar por dígito e sem acentos. Escolha nomes que digam o que a variável guarda, como `total` ou `quantidade`.\n\n#### Os tipos mais usados\n\n| Tipo | Guarda | Formato no printf | Formato no scanf |\n|---|---|---|---|\n| `int` | inteiros, como 42 e -7 | `%d` | `%d` |\n| `double` | números reais, como 3.5 | `%f` ou `%.2f` | `%lf` |\n| `char` | um caractere, como 'a' | `%c` | ` %c` (com espaço antes) |\n\nEm C, o separador decimal é o **ponto**: escreva `3.5`, nunca `3,5`. Na entrada, o scanf também espera ponto.\n\nO formato `%.2f` mostra o número com exatamente duas casas decimais, arredondando. `%.1f` mostra uma casa, `%.3f` mostra três.\n\n#### Lendo dados com scanf\n\nO `scanf` lê valores da **entrada padrão** e guarda nas variáveis. Repare no `&` antes do nome de cada variável: ele entrega ao scanf o **endereço** da variável, para que o scanf saiba onde guardar o valor. O módulo sobre memória explica isso em detalhes.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int a, b;\n    scanf(\"%d %d\", &a, &b);\n    printf(\"%d\\n\", a + b);\n    printf(\"%d\\n\", a - b);\n    printf(\"%d\\n\", a * b);\n    return 0;\n}\n```\n\nCom a entrada `7 3`, a saída é `10`, `4` e `21`, uma por linha. O scanf ignora espaços e quebras de linha entre números, então tanto faz receber `7 3` numa linha ou `7` e `3` em linhas separadas.\n\nPara ler um `double`, use `%lf`:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    double preco;\n    int quantidade;\n    scanf(\"%lf %d\", &preco, &quantidade);\n    printf(\"%.2f\\n\", preco * quantidade);\n    return 0;\n}\n```\n\nCom a entrada `2.5 4`, a saída é `10.00`.\n\nPara ler um `char`, coloque um espaço antes do `%c`. Esse espaço faz o scanf pular quebras de linha que sobraram de leituras anteriores:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int numero;\n    char letra;\n    scanf(\"%d\", &numero);\n    scanf(\" %c\", &letra);\n    printf(\"%d %c\\n\", numero, letra);\n    return 0;\n}\n```\n\n#### Divisão inteira e resto\n\nQuando os dois lados de uma divisão são `int`, o resultado também é `int`: a parte decimal é **descartada**. O operador `%` dá o **resto** da divisão inteira.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int a = 17, b = 5;\n    printf(\"%d\\n\", a / b);   // 3\n    printf(\"%d\\n\", a % b);   // 2\n    printf(\"%.2f\\n\", a / 2.0);          // 8.50\n    printf(\"%.2f\\n\", (double) a / b);   // 3.40\n    return 0;\n}\n```\n\nUsos clássicos do resto:\n\n- `n % 2` é 0 quando `n` é par e 1 quando `n` é ímpar positivo.\n- `n % 10` dá o último dígito de `n`, e `n / 10` remove esse dígito.\n- 125 minutos são `125 / 60` horas e `125 % 60` minutos, ou seja, 2 horas e 5 minutos.\n\nPara obter uma divisão com casas decimais, pelo menos um dos lados precisa ser real: escreva `2.0` em vez de `2` ou converta com `(double)`.\n\n#### Ordem das operações\n\nMultiplicação, divisão e resto são feitos antes de soma e subtração. Use parênteses quando quiser outra ordem:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int nota1 = 7, nota2 = 8;\n    printf(\"%d\\n\", nota1 + nota2 / 2);          // 11: só nota2 é dividida\n    printf(\"%d\\n\", (nota1 + nota2) / 2);        // 7: divisão inteira\n    printf(\"%.1f\\n\", (nota1 + nota2) / 2.0);    // 7.5: média correta\n    return 0;\n}\n```\n\n#### Erros comuns\n\n- **Esquecer o `&` no scanf**, como em `scanf(\"%d\", x)`. O programa compila com aviso e costuma travar ao executar.\n- **Usar `%d` para ler um `double`**, ou `%f` no scanf para um `double`. No scanf, `double` sempre usa `%lf`.\n- **Calcular média com divisão inteira**: `(a + b) / 2` com inteiros perde o .5.\n- **Usar uma variável sem valor inicial.** Uma variável declarada sem `= valor` contém lixo até receber algo.\n- **Escrever número com vírgula**, como `3,5`. Em C, a vírgula separa itens, e o ponto é o separador decimal.","published":true}},{"id":"3f619120-b34d-4635-97f0-2ce567d0664a","type":"EXTERNAL_ARTICLE","title":"Variáveis, operadores e expressões no material do CPDEE/UFMG","position":4,"description":"Leitura complementar sobre nomes, tipos, constantes e operadores em C.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c300.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"7f118430-1589-41de-bafc-15af60ecabd5","type":"QUIZ","title":"Revisão: variáveis, tipos e entrada","position":5,"description":"Cinco perguntas sobre tipos, scanf, formatos e operações.","availability":"AVAILABLE","assessmentId":"2fabd5b3-860e-488e-91ae-33109297748e"},{"id":"b4ecdef6-d130-48c7-abd4-4ea86f012dd8","type":"QUIZ","title":"Prática: variáveis e entrada","position":6,"description":"Desafios de programação em C com scanf, divisão inteira, resto e números com casas decimais.","availability":"AVAILABLE","assessmentId":"117290da-be51-4099-8e32-3a43e065000b"}]},{"id":"64ac6f6f-30df-47a1-87bf-53069bcbd5e8","title":"Decisões","description":"Faça o programa escolher o que executar: compare valores, combine condições com operadores lógicos e escolha entre várias opções com if, else e switch.","position":3,"contents":[{"id":"613eaa66-291e-47ab-bb18-6779dd6ca799","type":"YOUTUBE","title":"Comandos if e else","position":1,"description":"Estruturas de decisão com if e else em C, por Pietro Martins De Oliveira. Cerca de 8 minutos.","availability":"AVAILABLE","youtube":{"videoId":"MGUpDTEc3SM","url":"https://www.youtube.com/watch?v=MGUpDTEc3SM","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"02da4c8a-b5cd-4755-89ed-6bb9c50add08","type":"YOUTUBE","title":"Decisão múltipla com switch case","position":2,"description":"O comando switch case para escolher entre várias opções, por Pietro Martins De Oliveira. Cerca de 9 minutos.","availability":"AVAILABLE","youtube":{"videoId":"xgwrJNZGo24","url":"https://www.youtube.com/watch?v=xgwrJNZGo24","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"edf5cf32-7183-4d11-a88a-e5c704d147aa","type":"TEXT","title":"if, else, operadores e switch","position":3,"description":"Operadores relacionais e lógicos, if, else, cadeias de else if, switch com break e os erros mais comuns.","availability":"AVAILABLE","text":{"body":"Até aqui, todo programa executava todas as linhas, em ordem. Com uma **estrutura de decisão**, um trecho só executa se uma condição for verdadeira.\n\n#### Operadores relacionais\n\nComparam dois valores. O resultado é 1 (verdadeiro) ou 0 (falso).\n\n| Operador | Significado |\n|---|---|\n| `==` | igual a |\n| `!=` | diferente de |\n| `>` e `>=` | maior que, maior ou igual |\n| `<` e `<=` | menor que, menor ou igual |\n\nEm C, qualquer valor diferente de zero é considerado verdadeiro, e zero é falso.\n\n#### if e else\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int n;\n    scanf(\"%d\", &n);\n    if (n % 2 == 0) {\n        printf(\"par\\n\");\n    } else {\n        printf(\"impar\\n\");\n    }\n    return 0;\n}\n```\n\nO bloco do `if` executa quando a condição é verdadeira; o bloco do `else`, quando é falsa. Nunca os dois.\n\n#### Várias faixas com else if\n\nQuando há mais de duas possibilidades, encadeie `else if`. As condições são testadas de cima para baixo e só o primeiro bloco verdadeiro executa.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    double nota;\n    scanf(\"%lf\", &nota);\n    if (nota >= 9.0) {\n        printf(\"A\\n\");\n    } else if (nota >= 7.0) {\n        printf(\"B\\n\");\n    } else if (nota >= 5.0) {\n        printf(\"C\\n\");\n    } else {\n        printf(\"D\\n\");\n    }\n    return 0;\n}\n```\n\nRepare que o segundo teste não precisa de `nota < 9.0`: se chegou ali, o primeiro teste já foi falso.\n\n#### Operadores lógicos\n\nCombinam condições:\n\n- `&&` (e): verdadeiro só se as duas condições forem verdadeiras.\n- `||` (ou): verdadeiro se pelo menos uma for verdadeira.\n- `!` (não): inverte o resultado.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int idade, ingresso;\n    scanf(\"%d %d\", &idade, &ingresso);\n    if (idade >= 18 && ingresso == 1) {\n        printf(\"entrada liberada\\n\");\n    } else {\n        printf(\"entrada negada\\n\");\n    }\n    if (idade < 12 || idade >= 60) {\n        printf(\"meia entrada\\n\");\n    }\n    if (!ingresso) {\n        printf(\"sem ingresso\\n\");\n    }\n    return 0;\n}\n```\n\nPara testar se um número está **entre** dois valores, escreva as duas comparações: `x >= 1 && x <= 10`. A forma matemática `1 <= x <= 10` compila, mas não faz o que parece: C compara `1 <= x`, obtém 0 ou 1, e depois compara esse 0 ou 1 com 10, o que é sempre verdadeiro.\n\n#### switch\n\nQuando a decisão depende do valor exato de um inteiro ou de um `char`, o `switch` deixa o código mais limpo:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int a, b;\n    char op;\n    scanf(\"%d %c %d\", &a, &op, &b);\n    switch (op) {\n        case '+':\n            printf(\"%d\\n\", a + b);\n            break;\n        case '-':\n            printf(\"%d\\n\", a - b);\n            break;\n        case '*':\n            printf(\"%d\\n\", a * b);\n            break;\n        default:\n            printf(\"operador invalido\\n\");\n            break;\n    }\n    return 0;\n}\n```\n\nCom a entrada `6 * 7`, a saída é `42`. O `break` encerra o switch. Sem ele, a execução **continua** no próximo `case`, mesmo que o valor não corresponda. O `default` executa quando nenhum `case` corresponde.\n\n#### Erros comuns\n\n- **Usar `=` no lugar de `==`.** `if (x = 5)` atribui 5 a x e a condição fica sempre verdadeira. Com `-Wall`, o GCC avisa.\n- **Ponto e vírgula depois do if.** Em `if (x > 0);` o `;` é um comando vazio, e o bloco seguinte executa sempre.\n- **Esquecer as chaves.** Sem `{ }`, só a primeira linha depois do if pertence a ele. Use chaves sempre.\n- **Esquecer o `break` no switch**, fazendo vários casos executarem.\n- **Comparar números reais com `==`.** Contas com `double` podem gerar 0.30000000000000004 em vez de 0.3. Prefira comparar com uma pequena margem, ou trabalhe com inteiros quando possível.","published":true}},{"id":"6408af42-df06-4bac-90c8-920299b874c0","type":"EXTERNAL_ARTICLE","title":"Estruturas de controle no material do CPDEE/UFMG","position":4,"description":"Leitura complementar sobre if, else, switch e também os laços do próximo módulo.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c400.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"559015f3-a669-4335-a28f-6da56cb6dbde","type":"QUIZ","title":"Revisão: decisões","position":5,"description":"Cinco perguntas sobre condições, operadores lógicos e switch.","availability":"AVAILABLE","assessmentId":"c8b91bf3-7725-459d-999c-a67fce025667"},{"id":"48fd0b19-57db-4a24-a6c0-b2d42ebb33f3","type":"QUIZ","title":"Prática: decisões","position":6,"description":"Desafios de programação em C com if, else, operadores lógicos e switch.","availability":"AVAILABLE","assessmentId":"6d9d6942-4b9a-4d28-b2df-1bd43f5c4ff8"}]},{"id":"7b144296-d86c-4d94-b52b-13ebc443a623","title":"Repetições","description":"Repita trechos de código com while, for e do while. Aprenda os padrões de contador e acumulador, que resolvem a maior parte dos problemas com repetição.","position":4,"contents":[{"id":"2e6afddf-66a7-4c97-bf3a-80fd370e629f","type":"YOUTUBE","title":"Repetição condicional com while","position":1,"description":"Laços condicionais com while em C, por Pietro Martins De Oliveira. Cerca de 19 minutos.","availability":"AVAILABLE","youtube":{"videoId":"FhM-rXPALL8","url":"https://www.youtube.com/watch?v=FhM-rXPALL8","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"9b37b415-0bd8-4f67-bbc7-3edccd87b1bf","type":"YOUTUBE","title":"Repetição contada com for","position":2,"description":"O comando for para repetir um número conhecido de vezes, por Pietro Martins De Oliveira. Cerca de 12 minutos.","availability":"AVAILABLE","youtube":{"videoId":"F3Kn4iyrrEA","url":"https://www.youtube.com/watch?v=F3Kn4iyrrEA","channelName":"Pietro Martins De Oliveira","madeForKids":false,"availability":"AVAILABLE","channelId":"UCSiPG8JbqfRgetCpmMBIWAw","channel":{"handle":"@profpietromartins","description":"","avatarUrl":"https://yt3.ggpht.com/k2Qw7acKnj5lJ4dkWJXYMZ8F9cIERjtNfkMEA6zMsh_EJQ126Xu_apMbqatwAxRxJITiJFGKgA=s240-c-k-c0x00ffffff-no-rj","subscriberCount":79100,"videoCount":330}}},{"id":"e084126b-9e1d-44ab-8e39-b3a766371e15","type":"TEXT","title":"while, for, do while, contadores e acumuladores","position":3,"description":"Os três laços de C, quando usar cada um, os padrões de contador e acumulador e os erros mais comuns.","availability":"AVAILABLE","text":{"body":"Uma **repetição** (ou laço) executa o mesmo bloco várias vezes enquanto uma condição for verdadeira. Cada execução do bloco é chamada de **iteração**.\n\n#### while\n\nO `while` testa a condição **antes** de cada iteração. Se ela já começar falsa, o bloco não executa nenhuma vez.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int n;\n    scanf(\"%d\", &n);\n    while (n > 0) {\n        printf(\"%d\\n\", n);\n        n = n - 1;\n    }\n    printf(\"fim\\n\");\n    return 0;\n}\n```\n\nCom a entrada `3`, a saída é `3`, `2`, `1` e `fim`. Repare que o corpo do laço **muda** a variável da condição. Sem isso, o laço nunca termina.\n\n#### for\n\nO `for` junta, numa única linha, as três partes de uma repetição contada: valor inicial, condição e atualização.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    for (int i = 1; i <= 5; i++) {\n        printf(\"%d \", i * i);\n    }\n    printf(\"\\n\");\n    return 0;\n}\n```\n\nSaída: `1 4 9 16 25 ` seguido de quebra de linha. O `i++` é o mesmo que `i = i + 1`.\n\nUse `for` quando souber quantas vezes vai repetir, e `while` quando a repetição depender de algo que só se descobre durante a execução.\n\n#### do while\n\nO `do while` testa a condição **depois** de cada iteração, então o bloco executa pelo menos uma vez. É útil quando você precisa ler um valor antes de decidir se repete:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int valor;\n    do {\n        scanf(\"%d\", &valor);\n    } while (valor <= 0);\n    printf(\"%d\\n\", valor);\n    return 0;\n}\n```\n\nCom a entrada `-4 0 9`, o programa descarta -4 e 0 e imprime `9`. Note o `;` obrigatório depois do `while (...)` no final.\n\n#### Contador e acumulador\n\nDois padrões aparecem em quase todo problema com repetição:\n\n- **Contador**: começa em 0 e soma 1 a cada vez que algo acontece.\n- **Acumulador**: começa em 0 (para somas) e soma um valor a cada iteração.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int n, x;\n    int soma = 0;     // acumulador\n    int pares = 0;    // contador\n    scanf(\"%d\", &n);\n    for (int i = 0; i < n; i++) {\n        scanf(\"%d\", &x);\n        soma = soma + x;\n        if (x % 2 == 0) {\n            pares++;\n        }\n    }\n    printf(\"%d\\n\", soma);\n    printf(\"%d\\n\", pares);\n    return 0;\n}\n```\n\nCom a entrada `4` seguida de `3 8 10 5`, a saída é `26` e `2`. Os dois começam **antes** do laço; se fossem zerados dentro dele, perderiam o valor a cada iteração.\n\n#### Ler até um valor de parada\n\nÀs vezes a entrada não diz quantos números virão, mas termina com um valor especial, como 0. Esse valor é chamado de **sentinela**:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int x;\n    int quantidade = 0;\n    scanf(\"%d\", &x);\n    while (x != 0) {\n        quantidade++;\n        scanf(\"%d\", &x);\n    }\n    printf(\"%d\\n\", quantidade);\n    return 0;\n}\n```\n\nCom a entrada `5 7 2 0`, a saída é `3`: o 0 encerra a leitura e não é contado.\n\n#### Erros comuns\n\n- **Laço infinito**: a condição nunca fica falsa porque a variável não muda. Se o programa parar de responder, confira a atualização.\n- **Ponto e vírgula depois do for ou do while**: em `for (i = 0; i < n; i++);` o laço repete um comando vazio, e o bloco seguinte executa uma única vez.\n- **Erro de uma unidade (off by one)**: usar `i <= n` quando o certo é `i < n`, ou começar em 1 quando devia começar em 0. Teste com valores pequenos, como n igual a 1.\n- **Acumulador sem valor inicial**, ou reiniciado dentro do laço.\n- **Contar o sentinela** como se fosse um dado válido.","published":true}},{"id":"b46a2274-e086-407a-b819-5eb55f1df68e","type":"QUIZ","title":"Revisão: repetições","position":4,"description":"Cinco perguntas sobre while, for, do while, contadores e acumuladores.","availability":"AVAILABLE","assessmentId":"85ef32c6-613c-4aba-9990-ebcd84b33a3f"},{"id":"6b46c6c6-7529-4a0e-bbd0-b1b152d001e1","type":"QUIZ","title":"Prática: repetições","position":5,"description":"Desafios de programação em C com laços, contadores, acumuladores e valor de parada.","availability":"AVAILABLE","assessmentId":"eaa1a499-24cc-40be-b66f-63b15dffda1a"}]},{"id":"64c0334e-b129-4cfa-b1b2-262ddcfce5f5","title":"Vetores","description":"Guarde muitos valores do mesmo tipo com um único nome. Percorra vetores com for, encontre o maior e o menor elemento, some valores e procure um elemento com a busca linear.","position":5,"contents":[{"id":"5c0dddd2-5e5a-48ad-aad5-c3567f939e90","type":"YOUTUBE","title":"Vetores em linguagem C","position":1,"description":"Declaração, índices e percurso de vetores, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 15 minutos.","availability":"AVAILABLE","youtube":{"videoId":"o-ont-iQDY4","url":"https://www.youtube.com/watch?v=o-ont-iQDY4","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"3b029936-a223-4d3e-8b6f-e0938a9910a0","type":"TEXT","title":"Vetores: guardar, percorrer e procurar","position":2,"description":"Declaração, índices a partir de zero, leitura com for, soma, maior e menor, busca linear e o perigo de sair dos limites.","availability":"AVAILABLE","text":{"body":"Imagine ler as notas de 40 participantes e depois mostrar quantas ficaram acima da média. Você precisa guardar todas as notas, porque a média só é conhecida no final. Criar 40 variáveis seria inviável. A solução é um **vetor** (array): uma sequência de variáveis do mesmo tipo, lado a lado na memória, acessadas por um **índice**.\n\n#### Declarar e acessar\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int v[5] = {10, 20, 30, 40, 50};\n    v[2] = 35;\n    printf(\"%d\\n\", v[0]);   // 10\n    printf(\"%d\\n\", v[2]);   // 35\n    printf(\"%d\\n\", v[4]);   // 50\n    return 0;\n}\n```\n\nUm vetor de tamanho 5 tem os índices **0, 1, 2, 3 e 4**. O primeiro elemento é `v[0]` e o último é `v[4]`. Não existe `v[5]`.\n\n#### Ler e percorrer com for\n\nO par vetor e for é inseparável: o índice do for percorre as posições do vetor.\n\n```c\n#include <stdio.h>\n\n#define MAX 100\n\nint main(void) {\n    int n;\n    int v[MAX];\n    scanf(\"%d\", &n);            // supõe 1 <= n <= MAX\n    for (int i = 0; i < n; i++) {\n        scanf(\"%d\", &v[i]);\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        printf(\"%d\", v[i]);\n        if (i > 0) {\n            printf(\" \");\n        }\n    }\n    printf(\"\\n\");\n    return 0;\n}\n```\n\nCom a entrada `4` seguida de `1 2 3 4`, a saída é `4 3 2 1`. O `#define MAX 100` cria uma constante: o vetor tem espaço para até 100 valores, e o programa usa apenas os `n` primeiros. O `if (i > 0)` evita um espaço sobrando no fim da linha.\n\n#### Soma, maior e menor\n\nPara o maior e o menor, comece com o **primeiro elemento**, e não com 0: se todos os números forem negativos, um maior iniciado em 0 daria uma resposta errada.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int v[6] = {7, -3, 12, 0, 5, -8};\n    int n = 6;\n    int soma = 0;\n    int maior = v[0];\n    int menor = v[0];\n    for (int i = 0; i < n; i++) {\n        soma += v[i];\n        if (v[i] > maior) {\n            maior = v[i];\n        }\n        if (v[i] < menor) {\n            menor = v[i];\n        }\n    }\n    printf(\"%d %d %d\\n\", soma, maior, menor);   // 13 12 -8\n    return 0;\n}\n```\n\nO `soma += v[i]` é uma forma curta de `soma = soma + v[i]`.\n\n#### Busca linear\n\nPara saber se um valor está no vetor, olhe posição por posição. Se encontrar, guarde o índice e pare; se chegar ao fim sem encontrar, o valor não está lá.\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int v[5] = {4, 9, 2, 9, 7};\n    int n = 5;\n    int procurado = 9;\n    int posicao = -1;\n    for (int i = 0; i < n; i++) {\n        if (v[i] == procurado) {\n            posicao = i;\n            break;\n        }\n    }\n    printf(\"%d\\n\", posicao);   // 1: a primeira ocorrência\n    return 0;\n}\n```\n\nO valor -1 funciona como sinal de \"não encontrado\", porque nenhum índice válido é negativo. O `break` interrompe o laço assim que a resposta é conhecida. No pior caso, a busca linear olha todos os `n` elementos.\n\n#### Erros comuns\n\n- **Acessar fora dos limites**, como `v[n]` num vetor de `n` posições. C não confere os limites: o programa lê ou escreve na memória de outra variável, e o resultado é imprevisível. O módulo sobre memória mostra por quê.\n- **Usar `i <= n` no for**, o que acessa uma posição a mais.\n- **Iniciar o maior com 0** quando os valores podem ser negativos.\n- **Esquecer o `&` ao ler um elemento**: o certo é `scanf(\"%d\", &v[i])`.\n- **Achar que `v = w` copia um vetor.** Isso não compila. Para copiar, percorra os dois com um for.","published":true}},{"id":"26209061-fa03-4a70-aca1-f8bd8187bb2f","type":"EXTERNAL_ARTICLE","title":"Vetores e strings no material do CPDEE/UFMG","position":3,"description":"Leitura complementar sobre vetores, matrizes e strings. É um material antigo: onde ele usar gets, prefira fgets, como no próximo módulo.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c500.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"8de9f026-ff25-4650-ae13-8acad51abd79","type":"QUIZ","title":"Revisão: vetores","position":4,"description":"Cinco perguntas sobre índices, percurso, maior e busca linear.","availability":"AVAILABLE","assessmentId":"5dafa048-8459-400f-9fe3-c4770160d225"},{"id":"ecb48098-ae3c-4f32-94e9-c07cf199b662","type":"QUIZ","title":"Prática: vetores","position":5,"description":"Desafios de programação em C com vetores: guardar valores, percorrer e procurar.","availability":"AVAILABLE","assessmentId":"d0e15241-6c4c-4834-aaf0-e565c629e606"}]},{"id":"d945f6f9-9ed4-4c5f-9f80-81f0357ed4ed","title":"Strings","description":"Trabalhe com texto em C: uma string é um vetor de char terminado pelo caractere nulo. Leia palavras e linhas, meça o tamanho, percorra caractere por caractere e compare textos.","position":6,"contents":[{"id":"d719e2ee-72e9-4412-90c3-01517c92bc6b","type":"YOUTUBE","title":"Strings em linguagem C","position":1,"description":"Strings como vetores de char, o caractere nulo e funções de string.h, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 15 minutos.","availability":"AVAILABLE","youtube":{"videoId":"ZXhebWOJCdo","url":"https://www.youtube.com/watch?v=ZXhebWOJCdo","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"28dab10d-cdd6-49b9-acb2-f27389f03bf2","type":"TEXT","title":"Strings: vetores de char terminados em '\\0'","position":2,"description":"Como C guarda texto, leitura com scanf e fgets, strlen, percurso de caracteres, comparação e erros comuns.","availability":"AVAILABLE","text":{"body":"C não tem um tipo próprio para texto. Uma **string** é um vetor de `char` que termina com o **caractere nulo** `'\\0'`, um byte com valor zero que marca onde o texto acaba.\n\n#### Como a string fica na memória\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    char nome[10] = \"Ana\";\n    printf(\"%s\\n\", nome);\n    printf(\"%c %c %c\\n\", nome[0], nome[1], nome[2]);\n    printf(\"%d\\n\", nome[3] == '\\0');   // 1: verdadeiro\n    return 0;\n}\n```\n\nO vetor `nome` tem 10 posições, mas o texto \"Ana\" ocupa 4: `'A'`, `'n'`, `'a'` e `'\\0'`. As outras posições ficam sem uso. Regra prática: uma string com até N letras precisa de um vetor com **N + 1** posições.\n\nO formato `%s` imprime caracteres a partir do início do vetor até encontrar o `'\\0'`.\n\n#### Ler uma palavra com scanf\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    char palavra[31];\n    scanf(\"%30s\", palavra);\n    printf(\"%s\\n\", palavra);\n    return 0;\n}\n```\n\nDuas diferenças em relação a números:\n\n- **Não há `&`** antes de `palavra`. O nome de um vetor já representa o endereço do primeiro elemento.\n- O `%30s` limita a leitura a 30 caracteres, deixando espaço para o `'\\0'`. Sem esse limite, uma palavra grande escreveria além do vetor.\n\nO `%s` para no primeiro espaço: com a entrada `Maria Silva`, só `Maria` é lido.\n\n#### Ler uma linha inteira com fgets\n\nPara ler uma linha com espaços, use `fgets`. Ele guarda também a quebra de linha `'\\n'` do final, se couber; a função `strcspn` ajuda a removê-la:\n\n```c\n#include <stdio.h>\n#include <string.h>\n\nint main(void) {\n    char linha[101];\n    if (fgets(linha, sizeof linha, stdin) != NULL) {\n        linha[strcspn(linha, \"\\n\")] = '\\0';\n        printf(\"[%s]\\n\", linha);\n        printf(\"%zu\\n\", strlen(linha));\n    }\n    return 0;\n}\n```\n\nCom a entrada `Maria Silva`, a saída é `[Maria Silva]` e `11`. O `sizeof linha` informa ao fgets o tamanho do vetor, e ele nunca escreve além disso. `strcspn(linha, \"\\n\")` devolve a posição do primeiro `'\\n'`, que é trocado por `'\\0'`.\n\nA antiga função `gets` foi **removida** da linguagem por não ter limite de tamanho. Se encontrá-la em materiais antigos, use `fgets`.\n\n#### Tamanho e percurso\n\n`strlen`, da biblioteca string.h, conta os caracteres antes do `'\\0'`. O resultado é do tipo `size_t` e é impresso com `%zu`. Para percorrer uma string, avance até encontrar o `'\\0'`:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    char texto[101];\n    int vogais = 0;\n    scanf(\"%100s\", texto);\n    for (int i = 0; texto[i] != '\\0'; i++) {\n        char c = texto[i];\n        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {\n            vogais++;\n        }\n    }\n    printf(\"%d\\n\", vogais);\n    return 0;\n}\n```\n\nCom a entrada `programacao`, a saída é `5`. Cada `char` é um número pequeno (o código do caractere na tabela ASCII), por isso dá para comparar com `==` e fazer contas: `'b' - 'a'` vale 1, e `c - '0'` converte o caractere de um dígito, como `'7'`, no número 7.\n\nA biblioteca ctype.h tem funções úteis para caracteres, como `toupper` (converte para maiúscula) e `isdigit` (testa se é dígito):\n\n```c\n#include <ctype.h>\n#include <stdio.h>\n\nint main(void) {\n    char s[] = \"abc123\";\n    int digitos = 0;\n    for (int i = 0; s[i] != '\\0'; i++) {\n        if (isdigit((unsigned char) s[i])) {\n            digitos++;\n        } else {\n            s[i] = (char) toupper((unsigned char) s[i]);\n        }\n    }\n    printf(\"%s %d\\n\", s, digitos);   // ABC123 3\n    return 0;\n}\n```\n\nLetras acentuadas ocupam mais de um byte em UTF-8, por isso os exemplos usam apenas letras sem acento.\n\n#### Comparar e copiar\n\nStrings não são comparadas com `==` nem copiadas com `=`. Use as funções de string.h:\n\n```c\n#include <stdio.h>\n#include <string.h>\n\nint main(void) {\n    char a[20] = \"banana\";\n    char b[20];\n    strcpy(b, a);                     // copia a para b\n    printf(\"%d\\n\", strcmp(a, b) == 0);        // 1: são iguais\n    printf(\"%d\\n\", strcmp(\"abacate\", a) < 0); // 1: vem antes\n    return 0;\n}\n```\n\n`strcmp` devolve 0 quando as strings são iguais, um número negativo quando a primeira vem antes na ordem dos códigos e positivo quando vem depois. Antes de usar `strcpy`, garanta que o destino tem espaço suficiente.\n\n#### Erros comuns\n\n- **Vetor sem espaço para o `'\\0'`**: `char s[3] = \"Ana\";` não deixa lugar para o terminador.\n- **Usar `==` para comparar strings.** Isso compara endereços, não o texto. Use `strcmp`.\n- **Ler um número com scanf e depois uma linha com fgets.** O `'\\n'` que sobra depois do número faz o fgets ler uma linha vazia. Uma saída simples é ler as duas coisas com fgets, ou consumir o resto da linha antes.\n- **Esquecer de remover o `'\\n'` do fgets**, o que altera o tamanho e as comparações.\n- **Ler sem limite**, como `%s` sem número, em vetores pequenos.","published":true}},{"id":"9c204cd3-d0d6-4b36-99c6-b0a8d260befb","type":"QUIZ","title":"Revisão: strings","position":3,"description":"Cinco perguntas sobre o caractere nulo, leitura, tamanho e comparação de strings.","availability":"AVAILABLE","assessmentId":"15718612-0235-4590-a8b8-2542824d42ce"},{"id":"c1f72602-dec9-44b9-b860-92b2ad48328d","type":"QUIZ","title":"Prática: strings","position":4,"description":"Desafios de programação em C com strings: ler palavras e linhas e percorrer caractere a caractere.","availability":"AVAILABLE","assessmentId":"233f93e1-5950-4db2-86be-880a896ec710"}]},{"id":"4b53af98-d94b-47ce-9a03-0a8423986433","title":"Funções","description":"Divida um problema em partes menores com funções: defina parâmetros, devolva resultados com return, entenda o escopo das variáveis e reaproveite código.","position":7,"contents":[{"id":"9f5843e6-9228-450e-900d-8918029bf18c","type":"YOUTUBE","title":"Funções em linguagem C","position":1,"description":"Como definir e chamar funções, parâmetros e retorno, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 17 minutos.","availability":"AVAILABLE","youtube":{"videoId":"drZQ70-xFug","url":"https://www.youtube.com/watch?v=drZQ70-xFug","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"9b451c90-e452-4d57-a10e-91b7738d31a3","type":"YOUTUBE","title":"Regras de escopo em linguagem C","position":2,"description":"Onde cada variável existe e pode ser usada, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 5 minutos.","availability":"AVAILABLE","youtube":{"videoId":"_mCeGpQRPs8","url":"https://www.youtube.com/watch?v=_mCeGpQRPs8","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"32eb1522-1a2f-4c1e-b357-31110d8cd2c2","type":"TEXT","title":"Funções: dividir para resolver","position":3,"description":"Definição, parâmetros, retorno, void, protótipos, escopo, passagem por valor, vetores como parâmetro e erros comuns.","availability":"AVAILABLE","text":{"body":"Uma **função** é um bloco de código com nome, que recebe dados, faz um trabalho e pode devolver um resultado. Você já usa funções desde o primeiro programa: `main`, `printf`, `scanf` e `strlen`. Agora vai criar as suas.\n\n#### Anatomia de uma função\n\n```c\n#include <stdio.h>\n\nint maior(int a, int b) {\n    if (a > b) {\n        return a;\n    }\n    return b;\n}\n\nint main(void) {\n    int x, y;\n    scanf(\"%d %d\", &x, &y);\n    printf(\"%d\\n\", maior(x, y));\n    printf(\"%d\\n\", maior(maior(x, y), 100));\n    return 0;\n}\n```\n\n- `int` antes do nome é o **tipo de retorno**: o tipo do valor que a função devolve.\n- `maior` é o nome.\n- `(int a, int b)` são os **parâmetros**: variáveis que recebem os valores passados na chamada.\n- `return` encerra a função e devolve o valor. Nada depois de um `return` executado é executado.\n\nNa chamada `maior(x, y)`, os valores de `x` e `y` são **copiados** para `a` e `b`. O resultado pode ser usado em qualquer lugar onde caberia um `int`, inclusive como argumento de outra chamada.\n\n#### Funções sem retorno: void\n\nQuando a função só executa uma ação, o tipo de retorno é `void`:\n\n```c\n#include <stdio.h>\n\nvoid linha(int tamanho) {\n    for (int i = 0; i < tamanho; i++) {\n        printf(\"=\");\n    }\n    printf(\"\\n\");\n}\n\nint main(void) {\n    linha(5);\n    printf(\"C\\n\");\n    linha(5);\n    return 0;\n}\n```\n\n#### Protótipos\n\nO compilador lê o arquivo de cima para baixo. Para chamar uma função definida mais abaixo, declare antes o seu **protótipo**: a primeira linha da função, terminada em `;`.\n\n```c\n#include <stdio.h>\n\nint eh_par(int n);   // protótipo\n\nint main(void) {\n    for (int i = 1; i <= 4; i++) {\n        if (eh_par(i)) {\n            printf(\"%d par\\n\", i);\n        }\n    }\n    return 0;\n}\n\nint eh_par(int n) {\n    return n % 2 == 0;\n}\n```\n\nA função `eh_par` devolve 1 ou 0, por isso pode ser usada diretamente numa condição.\n\n#### Escopo e passagem por valor\n\nUma variável declarada dentro de uma função só existe ali: é uma **variável local**. Duas funções podem ter variáveis com o mesmo nome sem nenhuma relação entre elas. Os parâmetros também são locais e recebem **cópias**:\n\n```c\n#include <stdio.h>\n\nvoid dobra(int n) {\n    n = n * 2;\n    printf(\"dentro: %d\\n\", n);\n}\n\nint main(void) {\n    int n = 5;\n    dobra(n);\n    printf(\"fora: %d\\n\", n);\n    return 0;\n}\n```\n\nSaída: `dentro: 10` e depois `fora: 5`. A função alterou a cópia, não a variável de main. Para que a função entregue um resultado, use `return`. O módulo sobre memória mostra como uma função pode alterar uma variável de quem a chamou, usando ponteiros.\n\n#### Vetores como parâmetro\n\nUm vetor é passado junto com o seu tamanho, porque a função não tem como descobrir quantos elementos ele tem:\n\n```c\n#include <stdio.h>\n\nint soma_vetor(const int v[], int n) {\n    int soma = 0;\n    for (int i = 0; i < n; i++) {\n        soma += v[i];\n    }\n    return soma;\n}\n\nvoid zera(int v[], int n) {\n    for (int i = 0; i < n; i++) {\n        v[i] = 0;\n    }\n}\n\nint main(void) {\n    int dados[4] = {2, 4, 6, 8};\n    printf(\"%d\\n\", soma_vetor(dados, 4));   // 20\n    zera(dados, 4);\n    printf(\"%d\\n\", soma_vetor(dados, 4));   // 0\n    return 0;\n}\n```\n\nRepare: ao contrário do `int` do exemplo anterior, a função `zera` **alterou** o vetor de main. O vetor não é copiado; a função recebe o endereço do vetor original. O `const` em `soma_vetor` é uma promessa de que a função não vai alterar o vetor, e o compilador confere essa promessa. O módulo sobre memória explica o mecanismo.\n\n#### Por que dividir em funções\n\n- Cada função resolve uma parte pequena e pode ser testada separadamente.\n- O nome da função explica o que o trecho faz, e `main` fica parecida com um roteiro.\n- O mesmo código é reaproveitado em vários lugares, sem copiar e colar.\n\nUma boa regra: se você precisa de um comentário para explicar o que um bloco faz, talvez ele mereça virar uma função com esse nome.\n\n#### Erros comuns\n\n- **Esquecer o `return`** numa função que não é void. O valor devolvido fica indefinido; com `-Wall`, o GCC avisa.\n- **Ignorar o valor devolvido**: escrever `maior(x, y);` sozinho não guarda nem imprime nada.\n- **Esperar que uma função altere um parâmetro int de quem chamou.** Ela altera apenas a cópia.\n- **Chamar uma função antes de declará-la**, sem protótipo. No C17 com GCC 14, isso é erro.\n- **Imprimir dentro da função quando o problema pede para devolver.** Separe calcular de mostrar.","published":true}},{"id":"cdd7303c-1dd7-4a34-ae52-8494cfd3c70b","type":"EXTERNAL_ARTICLE","title":"Funções no material do CPDEE/UFMG","position":4,"description":"Leitura complementar sobre return, protótipos, void e escopo de variáveis.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c700.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"2cd942b5-a0df-4cd7-94f5-eb1f07d3ccd7","type":"QUIZ","title":"Revisão: funções","position":5,"description":"Cinco perguntas sobre parâmetros, retorno, protótipos e escopo.","availability":"AVAILABLE","assessmentId":"a4ac9788-8b1b-42ec-a2f0-84976497c334"},{"id":"0aea1781-44a9-4edd-926d-f6a103ccc017","type":"QUIZ","title":"Prática: funções","position":6,"description":"Desafios de programação em C em que você organiza a solução em funções com parâmetros e retorno.","availability":"AVAILABLE","assessmentId":"ac639f62-8773-4a02-9e98-212ac67ffba9"}]},{"id":"64a35341-d232-4de4-b92d-a02bb7a3fc5c","title":"Algoritmos clássicos","description":"Conheça algoritmos que todo programador estuda: busca binária, ordenação por seleção e por bolha e recursão com fatorial e Fibonacci. Comece a pensar no custo de um algoritmo, ou seja, em quantos passos ele faz conforme a entrada cresce.","position":8,"contents":[{"id":"acba265e-1a2e-4648-9f22-d2be12f24f0f","type":"YOUTUBE","title":"Busca sequencial e busca binária","position":1,"description":"Comparação entre as duas buscas, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 3 minutos.","availability":"AVAILABLE","youtube":{"videoId":"4ROhmGfBYNQ","url":"https://www.youtube.com/watch?v=4ROhmGfBYNQ","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"2ed944bb-adfd-439f-a4d6-b93545be618e","type":"YOUTUBE","title":"Ordenação por seleção (Selection Sort)","position":2,"description":"Passo a passo da ordenação por seleção em C, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 11 minutos.","availability":"AVAILABLE","youtube":{"videoId":"LYkZLxO8HtQ","url":"https://www.youtube.com/watch?v=LYkZLxO8HtQ","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"79d1acc2-abdb-452c-8e2b-aa3757a0879a","type":"YOUTUBE","title":"Recursão","position":3,"description":"O que é uma função recursiva, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 3 minutos.","availability":"AVAILABLE","youtube":{"videoId":"3JPEIE4x01Y","url":"https://www.youtube.com/watch?v=3JPEIE4x01Y","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"b7103acb-4303-4e7f-a28c-b5838016bd7f","type":"TEXT","title":"Buscar, ordenar e recursão","position":4,"description":"Busca binária, ordenação por seleção e por bolha, fatorial e Fibonacci recursivos e uma primeira noção de custo.","availability":"AVAILABLE","text":{"body":"Um **algoritmo** é uma receita precisa para resolver um problema. Para o mesmo problema existem algoritmos melhores e piores. Neste texto, os exemplos usam vetores fixos dentro do programa, para que você se concentre na ideia de cada algoritmo.\n\n#### Busca binária\n\nA busca linear olha um elemento por vez. Se o vetor estiver **ordenado**, dá para fazer muito melhor: olhe o elemento do meio. Se ele for o procurado, terminou. Se for maior, o procurado só pode estar na metade da esquerda; se for menor, na metade da direita. A cada passo, metade do vetor é descartada.\n\n```c\n#include <stdio.h>\n\nint busca_binaria(const int v[], int n, int x) {\n    int ini = 0;\n    int fim = n - 1;\n    while (ini <= fim) {\n        int meio = ini + (fim - ini) / 2;\n        if (v[meio] == x) {\n            return meio;\n        } else if (v[meio] < x) {\n            ini = meio + 1;\n        } else {\n            fim = meio - 1;\n        }\n    }\n    return -1;\n}\n\nint main(void) {\n    int v[8] = {2, 5, 8, 12, 16, 23, 38, 56};\n    printf(\"%d\\n\", busca_binaria(v, 8, 23));   // 5\n    printf(\"%d\\n\", busca_binaria(v, 8, 7));    // -1\n    return 0;\n}\n```\n\nProcurando 23: o meio é a posição 3 (valor 12), então a busca segue na direita; o novo meio é a posição 5 (valor 23), encontrado. Foram 2 comparações em vez de 6. O cálculo `ini + (fim - ini) / 2` dá o mesmo resultado que `(ini + fim) / 2`, mas evita estouro quando os índices são muito grandes.\n\nAtenção: a busca binária **só funciona em vetores ordenados**.\n\n#### Ordenação por seleção\n\nIdeia: encontre o menor elemento e coloque-o na posição 0; depois encontre o menor entre os restantes e coloque-o na posição 1; e assim por diante.\n\n```c\n#include <stdio.h>\n\nvoid ordena_selecao(int v[], int n) {\n    for (int i = 0; i < n - 1; i++) {\n        int menor = i;\n        for (int j = i + 1; j < n; j++) {\n            if (v[j] < v[menor]) {\n                menor = j;\n            }\n        }\n        int aux = v[i];\n        v[i] = v[menor];\n        v[menor] = aux;\n    }\n}\n\nint main(void) {\n    int v[6] = {29, 10, 14, 37, 13, 5};\n    ordena_selecao(v, 6);\n    for (int i = 0; i < 6; i++) {\n        printf(\"%d \", v[i]);\n    }\n    printf(\"\\n\");   // 5 10 13 14 29 37\n    return 0;\n}\n```\n\nA **troca** entre duas posições precisa de uma variável auxiliar: se você fizer `v[i] = v[menor]` direto, o valor antigo de `v[i]` se perde.\n\n#### Ordenação por bolha\n\nIdeia: percorra o vetor comparando vizinhos e troque os que estiverem fora de ordem. Ao fim de cada passada, o maior elemento ainda fora do lugar \"borbulha\" até o final.\n\n```c\n#include <stdio.h>\n\nvoid ordena_bolha(int v[], int n) {\n    for (int passada = 0; passada < n - 1; passada++) {\n        int trocou = 0;\n        for (int j = 0; j < n - 1 - passada; j++) {\n            if (v[j] > v[j + 1]) {\n                int aux = v[j];\n                v[j] = v[j + 1];\n                v[j + 1] = aux;\n                trocou = 1;\n            }\n        }\n        if (!trocou) {\n            break;   // nenhuma troca: já está ordenado\n        }\n    }\n}\n\nint main(void) {\n    int v[5] = {5, 1, 4, 2, 8};\n    ordena_bolha(v, 5);\n    for (int i = 0; i < 5; i++) {\n        printf(\"%d \", v[i]);\n    }\n    printf(\"\\n\");   // 1 2 4 5 8\n    return 0;\n}\n```\n\nO `n - 1 - passada` evita comparar a parte final, que já está no lugar. A variável `trocou` encerra cedo quando o vetor já está ordenado.\n\n#### Recursão\n\nUma função **recursiva** chama a si mesma para resolver uma versão menor do mesmo problema. Toda recursão precisa de duas partes:\n\n- um **caso base**, que responde diretamente, sem nova chamada;\n- um **passo recursivo**, que reduz o problema e chama a função de novo.\n\nO fatorial é o exemplo clássico: 0! vale 1, e n! vale n vezes (n - 1)!.\n\n```c\n#include <stdio.h>\n\nlong long fatorial(int n) {\n    if (n == 0) {\n        return 1;               // caso base\n    }\n    return n * fatorial(n - 1); // passo recursivo\n}\n\nint main(void) {\n    printf(\"%lld\\n\", fatorial(5));    // 120\n    printf(\"%lld\\n\", fatorial(20));   // 2432902008176640000\n    return 0;\n}\n```\n\nPara calcular `fatorial(3)`, o programa chama `fatorial(2)`, que chama `fatorial(1)`, que chama `fatorial(0)`. Essa última devolve 1, e as respostas voltam multiplicando: 1, depois 1, depois 2, depois 6. O tipo `long long` (formato `%lld`) guarda inteiros maiores que o `int`, mas mesmo ele estoura a partir de 21!.\n\nA sequência de **Fibonacci** começa com 0 e 1, e cada termo seguinte é a soma dos dois anteriores: 0, 1, 1, 2, 3, 5, 8, 13. A definição recursiva é direta: F(0) = 0, F(1) = 1 e F(n) = F(n - 1) + F(n - 2). O programa abaixo conta quantas chamadas a versão recursiva faz:\n\n```c\n#include <stdio.h>\n\nlong long chamadas = 0;\n\nlong long fib(int n) {\n    chamadas++;\n    if (n < 2) {\n        return n;\n    }\n    return fib(n - 1) + fib(n - 2);\n}\n\nint main(void) {\n    int testes[3] = {10, 20, 30};\n    for (int i = 0; i < 3; i++) {\n        chamadas = 0;\n        long long r = fib(testes[i]);\n        printf(\"F(%d) = %lld com %lld chamadas\\n\", testes[i], r, chamadas);\n    }\n    return 0;\n}\n```\n\nSaída:\n\n```text\nF(10) = 55 com 177 chamadas\nF(20) = 6765 com 21891 chamadas\nF(30) = 832040 com 2692537 chamadas\n```\n\nO número de chamadas explode porque os mesmos termos são recalculados muitas vezes: `fib(30)` calcula `fib(28)` duas vezes, `fib(27)` três vezes, e assim por diante. Uma versão com um laço, guardando apenas os dois últimos termos, faz cerca de n passos. Recursão é uma ferramenta poderosa, mas nem sempre é a mais eficiente.\n\n#### Noção de custo\n\nPara comparar algoritmos, contamos aproximadamente quantos passos eles fazem para uma entrada de tamanho n:\n\n| Algoritmo | Passos aproximados | n = 1000 | n = 1 000 000 |\n|---|---|---|---|\n| Busca linear | n | 1000 | 1 000 000 |\n| Busca binária | log₂ n | 10 | 20 |\n| Seleção e bolha | n² / 2 | 500 000 | 500 000 000 000 |\n\nA busca binária precisa de no máximo uns 20 passos num vetor de um milhão de elementos, porque cada passo corta o problema pela metade. Já as ordenações simples ficam lentas para entradas grandes, pois o custo cresce com o quadrado de n. Existem ordenações bem mais rápidas, como as que você verá em estudos de estruturas de dados.\n\n#### Erros comuns\n\n- **Usar busca binária em vetor não ordenado.** O resultado pode ser -1 mesmo com o valor presente.\n- **Atualizar `ini = meio` ou `fim = meio`** em vez de `meio + 1` e `meio - 1`, o que pode gerar laço infinito.\n- **Trocar valores sem variável auxiliar**, perdendo um deles.\n- **Recursão sem caso base**, ou com passo que não se aproxima do caso base. O programa faz chamadas até esgotar a memória da pilha e é encerrado.\n- **Estouro de inteiros**: fatoriais e termos de Fibonacci crescem rápido; `int` estoura em 13!.","published":true}},{"id":"ed53498f-0c54-40ed-ab42-ef1d77b99913","type":"QUIZ","title":"Revisão: algoritmos clássicos","position":5,"description":"Seis perguntas sobre busca binária, ordenação, recursão e custo.","availability":"AVAILABLE","assessmentId":"e1a18def-614f-4d4c-a769-6fcd60d4fa3c"},{"id":"99493663-d17c-4985-bbeb-958c6a19ba58","type":"QUIZ","title":"Prática: algoritmos clássicos","position":6,"description":"Desafios de programação em C com ordenação e busca binária.","availability":"AVAILABLE","assessmentId":"64fbf39b-0bfc-4109-b686-9b16bf38e014"}]},{"id":"2566fc5e-edcf-46cc-bc5b-a6596f6aa477","title":"Como o C enxerga a memória","description":"Veja o que acontece por baixo dos panos: onde as variáveis moram, o que é um endereço, como a pilha guarda as chamadas de função, o que são ponteiros, como vetores e strings ficam na memória e como pedir memória ao sistema com malloc e devolver com free. Este módulo explica vários comportamentos que você já viu, como o & do scanf e a função que altera um vetor, e mostra os erros clássicos de memória.","position":9,"contents":[{"id":"aecc4d60-59ca-414a-8233-c692335c93f9","type":"YOUTUBE","title":"Organização da memória: stack e heap","position":1,"description":"Como a memória de um programa em C se divide entre pilha (stack) e heap, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 10 minutos.","availability":"AVAILABLE","youtube":{"videoId":"_LLo0b0XFDw","url":"https://www.youtube.com/watch?v=_LLo0b0XFDw","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"d3f90021-8eb3-4e79-aee0-2b7cae3a5d03","type":"YOUTUBE","title":"Ponteiros em linguagem C","position":2,"description":"Endereços, o operador & e o operador *, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 16 minutos.","availability":"AVAILABLE","youtube":{"videoId":"sdPJSXzwpgo","url":"https://www.youtube.com/watch?v=sdPJSXzwpgo","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"951bca13-8145-40b8-bef2-84196c682e6e","type":"TEXT","title":"Endereços, pilha, ponteiros e malloc","position":3,"description":"Variáveis na memória, sizeof, endereços, a pilha de chamadas, ponteiros, aritmética de ponteiros, strings, malloc e free e os erros clássicos.","availability":"AVAILABLE","text":{"body":"Até aqui, uma variável foi tratada como uma caixa com nome. Por baixo, a memória do computador é uma longa sequência de **bytes**, cada um com um número: o seu **endereço**. Uma variável ocupa alguns bytes seguidos, e o nome dela é apenas um apelido para o endereço onde ela começa.\n\n#### Tamanho e endereço\n\nO operador `sizeof` diz quantos bytes um tipo ou uma variável ocupa. O operador `&` dá o endereço de uma variável, que pode ser impresso com `%p`:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int idade = 16;\n    double altura = 1.72;\n    char letra = 'C';\n    printf(\"int: %zu bytes\\n\", sizeof idade);\n    printf(\"double: %zu bytes\\n\", sizeof altura);\n    printf(\"char: %zu byte\\n\", sizeof letra);\n    printf(\"idade fica em %p\\n\", (void *) &idade);\n    printf(\"altura fica em %p\\n\", (void *) &altura);\n    return 0;\n}\n```\n\nNo GCC 14 em Linux de 64 bits, a saída mostra 4, 8 e 1 bytes. Os endereços aparecem em hexadecimal, como `0x7ffd5c3a1b2c`, e mudam a cada execução. O valor exato não importa; o que importa é que cada variável tem um.\n\nAgora o `&` do scanf faz sentido: `scanf(\"%d\", &idade)` entrega ao scanf o endereço de `idade`, para que ele escreva o número lido naquele lugar.\n\n#### A pilha de chamadas\n\nAs variáveis locais e os parâmetros moram numa região chamada **pilha** (stack). Cada vez que uma função é chamada, o programa reserva um bloco no topo da pilha, o **quadro** da chamada, com os parâmetros, as variáveis locais e o ponto para onde voltar. Quando a função termina, o quadro é descartado e aquelas variáveis deixam de existir.\n\n```c\n#include <stdio.h>\n\nint quadrado(int x) {\n    int r = x * x;     // x e r estão no quadro de quadrado\n    return r;\n}\n\nint main(void) {\n    int a = 4;         // a está no quadro de main\n    int b = quadrado(a);\n    printf(\"%d\\n\", b); // 16\n    return 0;\n}\n```\n\nPasso a passo: main cria `a`. Ao chamar `quadrado(a)`, um novo quadro é empilhado e o valor 4 é **copiado** para `x`. A função calcula `r`, devolve 16 e o quadro é desempilhado. `x` e `r` não existem mais; `b` recebe 16. Isso explica a passagem por valor do módulo de funções e também por que uma recursão sem caso base termina em erro: cada chamada empilha um quadro novo até a pilha acabar.\n\n#### Ponteiros\n\nUm **ponteiro** é uma variável que guarda um endereço. Ele é declarado com `*` e tem o tipo do que aponta:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int n = 10;\n    int *p = &n;       // p guarda o endereço de n\n    printf(\"%d\\n\", *p); // 10: o valor no endereço guardado em p\n    *p = 25;            // escreve 25 no endereço de n\n    printf(\"%d\\n\", n);  // 25\n    return 0;\n}\n```\n\nOs dois operadores são opostos: `&n` vai da variável para o endereço; `*p` vai do endereço para a variável. Escrever `*p = 25` altera `n`, porque `p` aponta para `n`.\n\nO uso mais importante é deixar uma função alterar variáveis de quem a chamou. Em vez de copiar o valor, passe o endereço:\n\n```c\n#include <stdio.h>\n\nvoid troca(int *a, int *b) {\n    int aux = *a;\n    *a = *b;\n    *b = aux;\n}\n\nint main(void) {\n    int x = 1, y = 2;\n    troca(&x, &y);\n    printf(\"%d %d\\n\", x, y);   // 2 1\n    return 0;\n}\n```\n\nA função continua recebendo cópias, só que agora são cópias dos **endereços**, e através deles ela chega às variáveis originais. É exatamente o que o scanf faz.\n\nUm ponteiro que não aponta para nada deve valer `NULL`. Antes de usar `*p`, tenha certeza de que `p` aponta para uma variável válida.\n\n#### Vetores e aritmética de ponteiros\n\nOs elementos de um vetor ficam **lado a lado** na memória. Na maior parte das expressões, o nome do vetor vira o endereço do primeiro elemento. Somar 1 a um ponteiro avança **um elemento**, não um byte:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    int v[4] = {10, 20, 30, 40};\n    int *p = v;                 // o mesmo que &v[0]\n    printf(\"%d\\n\", *p);         // 10\n    printf(\"%d\\n\", *(p + 2));   // 30, o mesmo que v[2]\n    printf(\"%td\\n\", &v[3] - &v[0]);   // 3 elementos de distância\n    for (int *q = v; q < v + 4; q++) {\n        printf(\"%d \", *q);\n    }\n    printf(\"\\n\");\n    return 0;\n}\n```\n\nEm C, `v[i]` é definido como `*(v + i)`. Por isso uma função que recebe um vetor recebe na verdade um ponteiro para o primeiro elemento, e por isso ela consegue alterar o vetor original, como no módulo de funções. Por isso também `sizeof` dentro da função mede o tamanho de um ponteiro, e não do vetor: o tamanho precisa ser passado à parte.\n\nE por isso sair dos limites é perigoso: `v[10]` num vetor de 4 posições é só um endereço adiante, que pode pertencer a outra variável. C não confere.\n\n#### Strings na memória\n\nUma string é um vetor de char, e o `'\\0'` é a única forma de saber onde ela termina. Funções como `printf` com `%s` e `strlen` avançam byte a byte até achar esse zero:\n\n```c\n#include <stdio.h>\n\nint main(void) {\n    char s[] = \"oi\";\n    printf(\"%zu\\n\", sizeof s);   // 3: 'o', 'i' e '\\0'\n    for (char *p = s; *p != '\\0'; p++) {\n        printf(\"%c=%d \", *p, *p);\n    }\n    printf(\"\\n\");   // o=111 i=105\n    return 0;\n}\n```\n\nSe o `'\\0'` faltar, essas funções continuam lendo a memória seguinte até encontrar, por acaso, um byte zero.\n\n#### O heap: malloc e free\n\nA pilha tem dois limites: é pequena (alguns megabytes) e as variáveis somem quando a função termina. Para guardar dados cujo tamanho só se conhece durante a execução, ou que precisam continuar existindo depois da função, use o **heap**, uma região que você administra com duas funções de stdlib.h:\n\n- `malloc(bytes)` reserva um bloco e devolve o endereço dele, ou `NULL` se não houver memória.\n- `free(ponteiro)` devolve o bloco ao sistema.\n\n```c\n#include <stdio.h>\n#include <stdlib.h>\n\nint main(void) {\n    int n;\n    if (scanf(\"%d\", &n) != 1 || n <= 0) {\n        return 1;\n    }\n    int *v = malloc((size_t) n * sizeof *v);\n    if (v == NULL) {\n        return 1;\n    }\n    for (int i = 0; i < n; i++) {\n        v[i] = i * i;\n    }\n    for (int i = 0; i < n; i++) {\n        printf(\"%d \", v[i]);\n    }\n    printf(\"\\n\");\n    free(v);\n    v = NULL;\n    return 0;\n}\n```\n\nCom a entrada `5`, a saída é `0 1 4 9 16`. Pontos importantes:\n\n- `n * sizeof *v` calcula os bytes: n elementos do tamanho do que `v` aponta.\n- Sempre confira se `malloc` devolveu `NULL`.\n- O bloco é usado como um vetor comum, com `v[i]`.\n- Todo `malloc` precisa de exatamente um `free` quando o bloco não for mais usado.\n- Depois do `free`, o ponteiro ainda guarda o endereço antigo; atribuir `NULL` evita usá-lo por engano.\n\nResumo das duas regiões:\n\n| | Pilha (stack) | Heap |\n|---|---|---|\n| O que guarda | variáveis locais e parâmetros | blocos pedidos com malloc |\n| Quem libera | automático, ao fim da função | você, com free |\n| Tamanho | pequeno, alguns MB | grande, limitado pela memória disponível |\n| Tempo de vida | enquanto a função executa | até o free |\n\n#### Erros clássicos de memória\n\nEsses erros muitas vezes **não** aparecem na compilação e nem sempre derrubam o programa na hora, o que os torna difíceis de achar. O C chama esse resultado de **comportamento indefinido**: qualquer coisa pode acontecer.\n\n- **Estouro de vetor**: ler ou escrever em `v[n]` ou além. Pode alterar outras variáveis em silêncio ou encerrar o programa com o erro *segmentation fault*.\n- **Ponteiro não inicializado**: declarar `int *p;` e escrever `*p = 5;`. O ponteiro contém lixo e aponta para um lugar qualquer.\n- **Vazamento de memória** (memory leak): esquecer o `free`, ou perder o único ponteiro para um bloco, por exemplo atribuindo outro endereço a ele. Num programa que roda por muito tempo, a memória usada só cresce.\n- **Ponteiro solto** (dangling pointer): usar um bloco depois do `free`, ou devolver o endereço de uma variável local, como `return &r;`. O quadro daquela função já foi descartado.\n- **Liberar duas vezes** o mesmo bloco, ou liberar algo que não veio de malloc.\n- **String sem `'\\0'`**, que faz strlen e printf lerem além do vetor.\n\nDuas ferramentas ajudam a encontrar esses erros ao testar no seu computador: compilar com `-fsanitize=address -g` no GCC, que interrompe o programa e mostra a linha do acesso inválido, e o Valgrind, no Linux, que aponta vazamentos.","published":true}},{"id":"88fb1e5b-e492-40b6-a997-ad9a6b4747e5","type":"YOUTUBE","title":"Ponteiros e vetores","position":4,"description":"A relação entre vetores e ponteiros e a aritmética de ponteiros, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 11 minutos.","availability":"AVAILABLE","youtube":{"videoId":"tkGt8sA2yGQ","url":"https://www.youtube.com/watch?v=tkGt8sA2yGQ","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"8e99b871-ab7d-440a-8e54-97dbec268d1c","type":"YOUTUBE","title":"Alocação dinâmica em linguagem C","position":5,"description":"Reservar e liberar memória no heap com malloc e free, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 13 minutos.","availability":"AVAILABLE","youtube":{"videoId":"OGnjCbyKNXg","url":"https://www.youtube.com/watch?v=OGnjCbyKNXg","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"f5f9a51d-786b-4907-a116-c070a30f70f9","type":"YOUTUBE","title":"Erros comuns em alocação dinâmica","position":6,"description":"Os enganos mais frequentes ao usar malloc e free, pelo Prof. Felipe Louza, Engenharia de Computação UFU. Cerca de 5 minutos.","availability":"AVAILABLE","youtube":{"videoId":"CEQd6-ktOZQ","url":"https://www.youtube.com/watch?v=CEQd6-ktOZQ","channelName":"Prof. Felipe Louza - Engenharia de Computação UFU","madeForKids":false,"availability":"AVAILABLE","channelId":"UCgVTWaxE68HXhEQSEdmQWAA","channel":{"handle":"@felipelouza","description":"Videoaulas do curso de Engenharia de Computação da Universidade Federal de Uberlândia (UFU).\n\nBons estudos!","avatarUrl":"https://yt3.ggpht.com/D8juzRxU2wAT885qmlnzmV8gvfNTGuY-5thzGzwjshrYF0zNYMA3VviTJgZuAuYnkls_YYg7z70=s240-c-k-c0x00ffffff-no-rj","subscriberCount":4350,"videoCount":368}}},{"id":"a118e755-a24f-4770-a6aa-a343a367c129","type":"EXTERNAL_ARTICLE","title":"Ponteiros no material do CPDEE/UFMG","position":7,"description":"Leitura complementar sobre declaração de ponteiros, ponteiros e vetores e cuidados no uso.","availability":"UNKNOWN","article":{"url":"https://www4.pucsp.br/~so-comp/cursoc/aulas/c600.html","sourceName":"CPDEE/UFMG, cópia hospedada pela PUC-SP"}},{"id":"5dbb78be-27e5-433a-88ad-592061c92758","type":"QUIZ","title":"Revisão: memória e ponteiros","position":8,"description":"Seis perguntas sobre endereços, pilha, ponteiros, malloc e free e erros de memória.","availability":"AVAILABLE","assessmentId":"f4a1f715-e571-46b9-9bf4-4f47c0c8a601"},{"id":"2745ab90-2190-4dd5-ade4-80d43786d7d7","type":"QUIZ","title":"Prática: memória e ponteiros","position":9,"description":"Desafios de programação em C com sizeof, ponteiros, aritmética de ponteiros e alocação dinâmica.","availability":"AVAILABLE","assessmentId":"aaec7565-9643-4b8b-be87-7c61ba7706b7"}]}],"communityAvailable":true,"contributionsEnabled":true,"creator":{"id":"48d11b36-3820-4bd3-ae47-633ab005f3e4","nickname":"lucascode","linkedinUrl":null,"instagramUrl":null,"avatarUrl":null},"contributors":[],"contributorCount":0}