Entrada e Saída

Entrada e saída são como uma conversa entre você e o computador — printf é o computador falando com você, scanf é você falando com o computador. Acerte o formato, ou vocês vão falar um passando pelo outro.

Saída Formatada com printf

printf vem de "print formatted" (impressão formatada). Seu primeiro argumento é uma string de formato, seguida dos valores a serem exibidos.

Especificadores de Formato Básicos

Especificador Finalidade Exemplo Saída
%d Inteiro decimal printf("%d", 42) 42
%f Ponto flutuante printf("%f", 3.14) 3.140000
%c Caractere único printf("%c", 'A') A
%s String printf("%s", "oi") oi
%x Hexadecimal printf("%x", 255) ff
%o Octal printf("%o", 8) 10
%p Endereço de ponteiro printf("%p", &a) Valor do endereço
%% Sinal de porcentagem literal printf("100%%") 100%
C
#include <stdio.h>

int main(void) {
    int idade = 25;
    float altura = 175.5f;
    char nota = 'A';
    printf("Idade: %d, Altura: %.1f, Nota: %c\n", idade, altura, nota);
    return 0;
}
TEXT
Idade: 25, Altura: 175.5, Nota: A

Largura e Alinhamento

Você pode inserir números entre % e o especificador de formato para controlar a largura de saída:

C
#include <stdio.h>

int main(void) {
    int num = 42;
    printf("[%5d]\n", num);
    printf("[%-5d]\n", num);
    printf("[%05d]\n", num);
    printf("[%+5d]\n", num);
    return 0;
}
TEXT
[   42]
[42   ]
[00042]
[  +42]

Precisão de Ponto Flutuante

C
#include <stdio.h>

int main(void) {
    double pi = 3.14159265358979;
    printf("Padrão:  %f\n", pi);
    printf("2 casas: %.2f\n", pi);
    printf("6 casas: %.6f\n", pi);
    printf("8.2:     %8.2f\n", pi);
    return 0;
}
TEXT
Padrão:  3.141593
2 casas: 3.14
6 casas: 3.141593
8.2:         3.14
💡 Dica: %f usa por padrão 6 casas decimais. Use %.0f para ocultar completamente a parte decimal.

Leitura de Entrada com scanf

scanf vem de "scan formatted" (leitura formatada). Ela lê dados da entrada padrão de acordo com a string de formato e os armazena em variáveis.

Uso Básico

C
#include <stdio.h>

int main(void) {
    int idade;
    float pontuacao;
    printf("Digite sua idade: ");
    scanf("%d", &idade);
    printf("Digite sua pontuação: ");
    scanf("%f", &pontuacao);
    printf("Idade: %d, Pontuação: %.1f\n", idade, pontuacao);
    return 0;
}
TEXT
Digite sua idade: 20
Digite sua pontuação: 92.5
Idade: 20, Pontuação: 92.5
⚠️ Atenção: Os argumentos de variáveis do scanf devem ser precedidos por & (o operador de endereço), dizendo ao scanf "armazene o valor neste endereço." Esquecer o & é o erro mais comum de iniciante — o programa não vai dar erro mas vai travar.

Lendo Múltiplos Valores

C
#include <stdio.h>

int main(void) {
    int a, b, c;
    printf("Digite três inteiros (separados por espaços): ");
    scanf("%d %d %d", &a, &b, &c);
    printf("Você digitou: %d, %d, %d\n", a, b, c);
    return 0;
}
TEXT
Digite três inteiros (separados por espaços): 10 20 30
Você digitou: 10, 20, 30

Por padrão, scanf usa espaços em branco (espaços, novas linhas, tabs) para separar valores diferentes.

Lendo Caracteres e Strings

C
#include <stdio.h>

int main(void) {
    char ch;
    char nome[20];
    printf("Digite um caractere: ");
    scanf(" %c", &ch);
    printf("Digite seu nome (sem espaços): ");
    scanf("%s", nome);
    printf("Caractere: %c, Nome: %s\n", ch, nome);
    return 0;
}
⚠️ Atenção: Adicionar um espaço antes de %c (" %c") ignora caracteres de espaço em branco, caso contrário ele vai ler a nova linha residual da entrada anterior. %s lê uma string mas para no espaço em branco. nome é um nome de array, que já é um endereço, então não precisa de &.

O Valor de Retorno do scanf

scanf retorna o número de variáveis lidas com sucesso. Esse recurso pode ser usado para validar a entrada:

C
#include <stdio.h>

int main(void) {
    int num;
    printf("Digite um inteiro: ");
    int resultado = scanf("%d", &num);
    if (resultado == 1) {
        printf("Lido com sucesso: %d\n", num);
    } else {
        printf("Entrada inválida!\n");
    }
    return 0;
}
TEXT
Digite um inteiro: abc
Entrada inválida!

getchar e putchar

getchar() lê um único caractere do teclado, e putchar() exibe um único caractere na tela. São mais simples e eficientes que scanf("%c") e printf("%c").

C
#include <stdio.h>

int main(void) {
    char ch;
    printf("Digite um caractere: ");
    ch = getchar();
    printf("Você digitou: ");
    putchar(ch);
    putchar('\n');
    return 0;
}
TEXT
Digite um caractere: X
Você digitou: X

Lendo uma Linha Inteira

getchar() combinado com um loop pode ler uma linha inteira até encontrar uma nova linha:

C
#include <stdio.h>

int main(void) {
    char ch;
    printf("Digite uma linha de texto: ");
    while ((ch = getchar()) != '\n') {
        putchar(ch);
    }
    putchar('\n');
    return 0;
}
TEXT
Digite uma linha de texto: Olá Mundo!
Olá Mundo!
💡 Dica: while ((ch = getchar()) != '\n') é um idioma clássico: primeiro lê um caractere em ch, depois verifica se é uma nova linha. Note que os parênteses externos ao redor da atribuição são obrigatórios.

Problemas de Buffer

A entrada padrão de C usa buffer de linha: a linha inteira de dados só é entregue ao buffer para o programa ler depois que o usuário pressiona Enter. Isso pode causar alguns problemas confusos.

Problema: scanf %c Lê uma Nova Linha Residual

C
#include <stdio.h>

int main(void) {
    int num;
    char ch;
    printf("Digite um inteiro: ");
    scanf("%d", &num);
    printf("Digite um caractere: ");
    scanf("%c", &ch);
    printf("Inteiro=%d, Caractere=%d\n", num, ch);
    return 0;
}
TEXT
Digite um inteiro: 42
Digite um caractere: Inteiro=42, Caractere=10

Após digitar 42 e pressionar Enter, o buffer contém 42\n. scanf("%d") lê 42, e scanf("%c") imediatamente lê aquele \n residual (código ASCII 10), sem esperar você digitar um caractere.

Soluções

Solução 1: Adicionar um espaço antes de %c (recomendada)

C
scanf(" %c", &ch);

O espaço ignora todos os caracteres de espaço em branco (incluindo novas linhas, espaços e tabs).

Solução 2: Usar getchar() para absorver o residual

C
scanf("%d", &num);
getchar();
scanf("%c", &ch);

Solução 3: Limpar o buffer de entrada

C
int c;
while ((c = getchar()) != '\n' && c != EOF) {}
⚠️ Atenção: Não use fflush(stdin) para limpar o buffer de entrada — é comportamento indefinido em C padrão. Alguns compiladores suportam, mas não é portável.

Exemplo

Escreva um programa que leia tanto um inteiro quanto um caractere, tratando corretamente os resíduos do buffer:

C
#include <stdio.h>

int main(void) {
    int idade;
    char genero;
    printf("Digite sua idade: ");
    scanf("%d", &idade);
    printf("Digite seu gênero (M/F): ");
    scanf(" %c", &genero);
    printf("Idade: %d, Gênero: %c\n", idade, genero);
    return 0;
}
▶ Experimente
TEXT
Digite sua idade: 25
Digite seu gênero (M/F): M
Idade: 25, Gênero: M

Exemplo

Use getchar() para ler caractere por caractere e contar o número de letras e dígitos em uma linha:

C
#include <stdio.h>

int main(void) {
    char ch;
    int letras = 0;
    int digitos = 0;
    printf("Digite uma linha de texto: ");
    while ((ch = getchar()) != '\n') {
        if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {
            letras++;
        } else if (ch >= '0' && ch <= '9') {
            digitos++;
        }
    }
    printf("Letras: %d, Dígitos: %d\n", letras, digitos);
    return 0;
}
▶ Experimente
TEXT
Digite uma linha de texto: Olá 2024!
Letras: 3, Dígitos: 4

puts e fputs

puts() exibe uma string e adiciona automaticamente uma nova linha. É mais simples que printf e ideal para saída de texto puro:

C
#include <stdio.h>

int main(void) {
    puts("Olá, Mundo!");
    puts("Nova linha automática, sem precisar de \\n");
    return 0;
}
TEXT
Olá, Mundo!
Nova linha automática, sem precisar de \n
💡 Dica: puts() é mais eficiente que printf("%s\n", ...) porque não precisa analisar uma string de formato. Quando não precisa de formatação, prefira puts.

❓ Perguntas Frequentes

P: Por que as variáveis do scanf precisam de & na frente? R: scanf precisa saber onde armazenar o valor, e & pega o endereço da variável. Só nomes de arrays não precisam, porque um nome de array já é o endereço do seu primeiro elemento.

P: scanf("%c") pulou minha entrada — o que aconteceu? R: Há uma nova linha residual no buffer de uma entrada anterior. Adicione um espaço antes de %c: scanf(" %c", &ch) para ignorar espaços em branco.

P: Os especificadores de formato do printf e scanf podem ser maiúsculos? R: Alguns podem. %d minúsculo corresponde a int; %D maiúsculo não é padrão. Mas %x imprime hex minúsculo (abcdef) enquanto %X imprime maiúsculo (ABCDEF) — isso é válido.

P: Como leio uma string com espaços de forma segura? R: scanf("%s") para no espaço em branco. Use fgets(nome, sizeof(nome), stdin) para ler uma linha inteira — suporta espaços e é mais seguro.

📖 Resumo

📝 Exercícios

  1. Escreva um programa que leia o raio de um círculo e exiba sua área e circunferência usando o formato %.2f do printf.
  2. Escreva um programa que use getchar() para ler uma linha de entrada e conte quantas letras maiúsculas e minúsculas ela contém.
  3. Escreva um programa que leia um inteiro e o exiba nos formatos decimal (%d), hexadecimal (%x) e octal (%o).
100%