Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

✦   Lição

Seu primeiro programa

Todo programa em C começa pela função main. Quando você executa o binário, o sistema chama main, que roda as instruções de cima para baixo e, ao terminar, devolve um número: 0 significa sucesso.

C Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
C / Fundamentos

Seu primeiro programa

por Huxley Sterling
Iniciante

Entenda o conceito

Todo programa em C começa pela função main. Quando você executa o binário, o sistema chama main, que roda as instruções de cima para baixo e, ao terminar, devolve um número: 0 significa sucesso.

Para escrever na tela, usamos funções da biblioteca padrão declaradas em <stdio.h>. A diretiva #include <stdio.h> traz essas declarações; sem ela, o compilador não sabe o que é printf nem puts.

puts imprime um texto e já pula a linha. printf é mais flexível: ela só quebra a linha quando encontra \n e aceita especificadores de formato como %d (inteiro), %.2f (número com duas casas) e %s (texto), que são trocados pelos valores passados depois da vírgula.

C é compilada: o código-fonte vira um executável antes de rodar. Com o GCC, gcc -Wall -Wextra ola.c -o ola compila e ./ola executa. Os avisos de -Wall -Wextra apontam boa parte dos erros de iniciante.

↳ Pontos-chave
  • A execução começa em int main(void) e o return 0; avisa ao sistema que deu tudo certo.
  • #include <stdio.h> é obrigatório para usar printf e puts.
  • puts quebra a linha sozinha; printf só quebra com \n no texto.
  • Em printf, cada especificador (%d, %.2f, %s) recebe o próximo argumento, na ordem e no tipo certos; %% imprime o próprio %.
  • Compile com gcc -Wall -Wextra arquivo.c -o programa e rode com ./programa.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Olá, mundo com printf e puts

ola.c
/* ola.c: o menor programa útil em C */

/* #include traz as declarações de printf e puts */
#include <stdio.h>

/* Todo programa em C começa a rodar pela função main */
int main(void)
{
    /* printf escreve o texto; \n é a quebra de linha */
    printf("Olá, mundo!\n");

    /* puts escreve o texto e já acrescenta a quebra de linha */
    puts("Bem-vindo à loja Daily.");
    puts("Hoje tem cupom na vitrine.");

    /* 0 avisa ao sistema que tudo correu bem */
    return 0;
}

O programa mínimo: um #include, a função main e um return 0. Ele mostra as duas formas mais comuns de escrever na tela: printf, que precisa do \n para pular a linha, e puts, que pula sozinha.

Os comentários /* ... */ são ignorados pelo compilador e servem só para quem lê o código.

02Receita com várias linhas e caracteres especiais

receita.c
/* receita.c: várias linhas, tabulação e caracteres especiais */
#include <stdio.h>

int main(void)
{
    puts("=== Bolo de caneca ===");

    /* \t insere uma tabulação, útil para recuar itens */
    printf("Ingredientes:\n");
    printf("\t- 4 colheres de farinha\n");
    printf("\t- 2 colheres de açúcar\n");
    printf("\t- 1 ovo\n");

    /* Para mostrar aspas dentro da string, escape com \" */
    printf("Dica: use a caneca \"grande\" do armário.\n");

    /* Uma única chamada pode imprimir várias linhas */
    printf("Modo de preparo:\n"
           "1. Misture tudo na caneca.\n"
           "2. Leve ao micro-ondas por 3 minutos.\n");

    /* Para imprimir o próprio %, escreva %% */
    printf("Rendimento: 100%% de uma porção.\n");
    return 0;
}

Strings em C aceitam sequências de escape: \n quebra a linha, \t insere uma tabulação e \" coloca aspas dentro do texto. Já o % tem significado especial no printf, por isso o símbolo é escrito como %%.

O exemplo também mostra que strings vizinhas são unidas pelo compilador, o que permite quebrar um texto longo em várias linhas do código com uma única chamada de printf.

03Resumo de compra com especificadores de formato

cupom.c
/* cupom.c: printf com especificadores de formato */
#include <stdio.h>
#include <stdlib.h>   /* EXIT_SUCCESS */

int main(void)
{
    /* %s recebe texto, %d um inteiro e %.2f um número com 2 casas */
    printf("Cliente: %s\n", "Ana");
    printf("Itens no carrinho: %d\n", 3);
    printf("Subtotal: R$ %.2f\n", 149.90);

    /* Os valores entram na ordem dos especificadores */
    printf("Cupom %s: %d%% de desconto\n", "BEMVINDO", 10);

    /* Contas podem ser feitas direto nos argumentos */
    printf("Desconto: R$ %.2f\n", 149.90 * 0.10);
    printf("Total: R$ %.2f\n", 149.90 - 149.90 * 0.10);

    /* %-12s alinha o texto à esquerda em 12 colunas; %6.2f usa 6 */
    printf("%-12s%6.2f\n", "Frete", 15.00);
    printf("%-12s%6.2f\n", "A pagar", 149.90 * 0.90 + 15.00);

    /* EXIT_SUCCESS é o nome padrão para "terminou sem erro" */
    return EXIT_SUCCESS;
}

Aqui o printf recebe valores: %s para o nome, %d para a quantidade e %.2f para os preços, sempre na ordem em que aparecem na string. As contas, como o desconto, são feitas direto nos argumentos.

Nas duas últimas linhas, %-12s reserva 12 colunas para o texto alinhado à esquerda e %6.2f reserva 6 para o número, o que deixa os valores alinhados. O return EXIT_SUCCESS, de <stdlib.h>, é um nome mais legível para o mesmo 0.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Cartão do leitor da bibliotecaFácil

Escreva um programa que imprima o cartão de um leitor da biblioteca, com uma informação por linha, exatamente como na saída esperada.

↳ Requisitos
  • Incluir <stdio.h> e escrever todo o código dentro de int main(void).
  • Usar puts para cada uma das quatro linhas.
  • Terminar com return 0;.
código inicial
#include <stdio.h>

int main(void)
{
    /* Imprima as quatro linhas do cartão aqui */

    return 0;
}
saída esperada
Biblioteca Central
Leitor: Marcos Lima
Livros emprestados: 2
Devolução até: 20/10
Ver dica

Cada puts gera exatamente uma linha e já coloca a quebra no fim; você não precisa de \n.

Ver resposta
#include <stdio.h>

int main(void)
{
    /* puts já coloca a quebra de linha no fim */
    puts("Biblioteca Central");
    puts("Leitor: Marcos Lima");
    puts("Livros emprestados: 2");
    puts("Devolução até: 20/10");

    /* 0 indica que o programa terminou bem */
    return 0;
}

Passo a passo

  1. #include <stdio.h> traz a declaração de puts; sem ela o compilador não conhece a função e recusa a chamada.
  2. int main(void) é o ponto de entrada: o sistema chama main ao iniciar o programa, e void diz que ela não recebe argumentos.
  3. Cada puts("...") escreve o texto e acrescenta uma quebra de linha, então cada chamada vira exatamente uma linha da saída.
  4. As linhas aparecem na mesma ordem das chamadas, porque o C executa as instruções de cima para baixo.
  5. return 0; encerra main e devolve 0 ao sistema, o código que significa "terminou sem erro".

Por que funciona

Um programa em C é uma sequência de instruções dentro de main, executadas na ordem em que foram escritas. O cartão é só texto fixo, então basta uma chamada de saída por linha.

puts foi escolhida porque o texto não tem nenhum valor variável: ela é mais simples que printf e já cuida da quebra de linha, o que evita esquecer o \n no fim.

Erros comuns

  • Esquecer o #include <stdio.h>: em C23 o GCC para com implicit declaration of function 'puts'. Coloque o include na primeira linha.
  • Escrever puts("Leitor: Marcos Lima\n");: o \n extra soma-se à quebra que puts já coloca e aparece uma linha em branco. Com puts, não use \n no fim.
  • Esquecer o ponto e vírgula depois de uma chamada: o compilador acusa expected ';' before ... na linha seguinte. Toda instrução termina com ;.
  • Usar aspas simples (puts('Biblioteca Central');): aspas simples são para um único caractere; texto vai sempre entre aspas duplas.

Outra forma de resolver

Dá para usar printf com \n explícito em cada linha, ou até uma única chamada com strings vizinhas, que o compilador junta:

printf("Biblioteca Central\n"
       "Leitor: Marcos Lima\n"
       "Livros emprestados: 2\n"
       "Devolução até: 20/10\n");

Essa forma é preferível quando o bloco de texto é grande e fixo, como um menu ou um aviso.

Saída esperada

Biblioteca Central
Leitor: Marcos Lima
Livros emprestados: 2
Devolução até: 20/10

02Etiqueta de preço da lojaMédio

Imprima a etiqueta de um caderno com nome, estoque, preço, porcentagem de promoção e preço final com desconto. O preço final deve ser calculado pelo programa, não digitado.

↳ Requisitos
  • Usar printf com %s para o nome, %d para estoque e promoção e %.2f para os preços.
  • Mostrar o símbolo de porcentagem com %%.
  • Calcular o preço final (18.50 com 20% de desconto) no argumento do printf.
código inicial
#include <stdio.h>

int main(void)
{
    printf("Produto: %s\n", "Caderno");
    /* Complete: estoque, preço, promoção e preço final */

    return 0;
}
saída esperada
Produto: Caderno
Estoque: 42 unidades
Preço: R$ 18.50
Promoção: 20% off
Preço final: R$ 14.80
Ver dica

Pagar com 20% de desconto é o mesmo que pagar 80% do preço.

Ver resposta
#include <stdio.h>

int main(void)
{
    /* %s para texto, %d para inteiro */
    printf("Produto: %s\n", "Caderno");
    printf("Estoque: %d unidades\n", 42);

    /* %.2f mostra o número com duas casas decimais */
    printf("Preço: R$ %.2f\n", 18.50);

    /* %% imprime o caractere % */
    printf("Promoção: %d%% off\n", 20);

    /* A conta é feita no próprio argumento */
    printf("Preço final: R$ %.2f\n", 18.50 * 0.80);
    return 0;
}

Passo a passo

  1. printf("Produto: %s\n", "Caderno") troca o %s pelo texto passado depois da vírgula.
  2. %d recebe o inteiro 42; o restante da string (" unidades") é impresso como está.
  3. %.2f mostra 18.50 com duas casas decimais; sem o .2, o padrão seria seis casas (18.500000).
  4. Em "Promoção: %d%% off\n", o %d vira 20 e o %% vira um único %, porque um % sozinho seria lido como início de especificador.
  5. 18.50 * 0.80 é calculado antes da chamada e o resultado (14.80) entra no %.2f.
  6. Cada string termina com \n, já que, diferente de puts, printf não quebra a linha sozinho.

Por que funciona

printf lê a string de formato da esquerda para a direita: o texto comum vai direto para a saída e cada especificador (%s, %d, %.2f) é substituído pelo próximo argumento da lista. Por isso a ordem e o tipo dos argumentos precisam combinar com os especificadores.

O desconto de 20% é o mesmo que pagar 80% do preço, e a multiplicação com double resulta em 14.8, que %.2f exibe como 14.80.

Erros comuns

  • Trocar o tipo: printf("Estoque: %d\n", 42.0); passa um double para %d. O comportamento é indefinido e costuma imprimir lixo; o -Wall avisa. Use %d para inteiros e %f para números com vírgula.
  • Escrever % sozinho ("%d% off"): o printf tenta ler % o como especificador e a saída sai errada. Para o símbolo, use %%.
  • Esquecer o \n: as linhas grudam (Produto: CadernoEstoque: 42 unidades). Termine cada string com \n.
  • Usar %.2d: a precisão em %d significa número mínimo de dígitos, não casas decimais. Para preço, use %.2f.

Outra forma de resolver

Os valores podem ficar em variáveis com nome, o que deixa a conta mais legível:

double preco = 18.50;
int desconto = 20;
printf("Preço final: R$ %.2f\n", preco * (100 - desconto) / 100.0);

É a melhor escolha quando o mesmo valor aparece em mais de uma linha, como aqui o preço.

Saída esperada

Produto: Caderno
Estoque: 42 unidades
Preço: R$ 18.50
Promoção: 20% off
Preço final: R$ 14.80

03Placar alinhado da rodadaDesafio

Monte o placar de uma rodada de jogo em forma de tabela, com colunas alinhadas para jogador, pontos e partidas, uma linha de total e a média de pontos com uma casa decimal.

↳ Requisitos
  • Usar o mesmo formato %-10s%8d%10d (ou %-10s%8s%10s no cabeçalho) em todas as linhas da tabela.
  • Separadores com 28 traços, a soma das larguras das colunas.
  • Calcular total e média nos argumentos do printf, sem digitar os resultados.
  • Mostrar a média com %.1f, sem perder a parte decimal na divisão.
código inicial
#include <stdio.h>

int main(void)
{
    puts("PLACAR DA RODADA");
    /* Cabeçalho, separador, três jogadores, separador, total e média */

    return 0;
}
saída esperada
PLACAR DA RODADA
Jogador     Pontos  Partidas
----------------------------
Lia           1250         5
Davi           980         4
Bia           1430         6
----------------------------
Total         3660        15
Média de pontos: 1220.0
Ver dica

O número entre % e a letra é a largura da coluna; o - alinha à esquerda. Para a média, pense no que acontece ao dividir dois inteiros.

Ver resposta
#include <stdio.h>

int main(void)
{
    puts("PLACAR DA RODADA");

    /* Mesmo formato no cabeçalho e nas linhas: as colunas ficam alinhadas */
    printf("%-10s%8s%10s\n", "Jogador", "Pontos", "Partidas");
    puts("----------------------------");

    /* %-10s: texto à esquerda em 10 colunas; %8d e %10d: números à direita */
    printf("%-10s%8d%10d\n", "Lia", 1250, 5);
    printf("%-10s%8d%10d\n", "Davi", 980, 4);
    printf("%-10s%8d%10d\n", "Bia", 1430, 6);
    puts("----------------------------");

    /* Totais calculados nos argumentos do printf */
    printf("%-10s%8d%10d\n", "Total", 1250 + 980 + 1430, 5 + 4 + 6);

    /* Dividir por 3.0 (não 3) mantém as casas decimais */
    printf("Média de pontos: %.1f\n", (1250 + 980 + 1430) / 3.0);
    return 0;
}

Passo a passo

  1. puts("PLACAR DA RODADA") imprime o título; não há valores a formatar, então puts basta.
  2. O cabeçalho usa %-10s%8s%10s: o - alinha "Jogador" à esquerda em 10 colunas, e %8s e %10s alinham os títulos à direita em 8 e 10 colunas.
  3. O separador tem 28 traços, exatamente 10 + 8 + 10, a largura somada das três colunas.
  4. Cada jogador usa %-10s%8d%10d, as mesmas larguras do cabeçalho, então os números ficam sob os títulos, alinhados pela direita.
  5. A linha de total soma os valores direto nos argumentos (1250 + 980 + 1430); o resultado é um int e casa com %8d.
  6. A média divide por 3.0: com um operando double, a divisão mantém a parte decimal e o resultado combina com %.1f.
  7. %.1f arredonda para uma casa decimal, o que dá 1220.0.

Por que funciona

O alinhamento sai de graça da largura de campo do printf: o número entre % e a letra diz quantas colunas o valor ocupa, completando com espaços. Usar as mesmas larguras em todas as linhas faz cada coluna começar e terminar no mesmo lugar, como numa tabela.

A largura mínima nunca corta o valor; se ele for maior, a coluna simplesmente cresce. Por isso as larguras foram escolhidas com folga para o maior número (1430) e o maior nome (Total). Os nomes estão sem acento de propósito: letras como á ocupam 2 bytes em UTF-8 e o printf conta bytes, o que desalinharia a coluna.

Erros comuns

  • Larguras diferentes no cabeçalho e nas linhas: com %-10s%6s no título e %-10s%8d nos dados, os números ficam deslocados dois espaços. Use exatamente as mesmas larguras.
  • Esquecer o - em %-10s: %10s alinha o nome à direita e a tabela fica Lia 1250. O - é o que encosta o texto à esquerda.
  • Dividir por 3: (1250 + 980 + 1430) / 3 é divisão inteira e resulta em 1220 do tipo int; passar isso para %.1f é comportamento indefinido e imprime lixo (o -Wall avisa). Divida por 3.0.
  • Contar os traços errado: um separador de 26 ou 30 traços não fecha com a tabela. Some as larguras das colunas (10 + 8 + 10 = 28).

Outra forma de resolver

A largura pode vir de um argumento com *, o que evita repetir números mágicos:

printf("%-*s%*d%*d\n", 10, "Lia", 8, 1250, 10, 5);

Ela compensa quando a largura muda com os dados, por exemplo calculada a partir do maior nome. Para uma tabela fixa como esta, as larguras escritas na string são mais fáceis de ler.

Saída esperada

PLACAR DA RODADA
Jogador     Pontos  Partidas
----------------------------
Lia           1250         5
Davi           980         4
Bia           1430         6
----------------------------
Total         3660        15
Média de pontos: 1220.0

Últimas lições

Ver o arquivo completo →