Aula 03 – Entrada e Saída: printf e scanf

Exibindo e lendo dados com precisão — especificadores de formato, largura, casas decimais e locale

A função printf

O printf (print formatted) é a principal função de saída em C. Ela imprime texto na tela com suporte a formatação precisa de valores numéricos, larguras de coluna e alinhamento.

printf("string de formato", var1, var2, ...);

A string de formato pode conter texto comum, sequências de escape (\n, \t) e especificadores de formato que começam com % e indicam o tipo e a apresentação de cada valor a ser impresso.
#include <stdio.h>

int main() {
    int    idade  = 22;
    float  altura = 1.75;
    char   inicial = 'A';

    printf("Idade: %d anos\n", idade);
    printf("Altura: %.2f m\n", altura);    // 2 casas decimais
    printf("Inicial: %c\n", inicial);
    printf("Idade=%d  Altura=%.2f  Inicial=%c\n", idade, altura, inicial);

    return 0;
}

Idade: 22 anos

Altura: 1.75 m

Inicial: A

Idade=22 Altura=1.75 Inicial=A

Múltiplos valores em um único printf: É possível inserir vários especificadores na mesma string de formato. Os valores correspondentes são passados na mesma ordem após a string, separados por vírgulas.

Especificadores de Formato

Um especificador de formato é composto de vários campos opcionais, nessa ordem:

% [flags] [largura] [.precisão] [modificador] tipo

Tipos principais

Especificador Tipo Exemplo de uso Saída
%d ou %i int printf("%d", 42) 42
%u unsigned int printf("%u", 3000000000U) 3000000000
%ld long printf("%ld", 2000000000L) 2000000000
%lld long long printf("%lld", 9000000000LL) 9000000000
%f float / double printf("%f", 3.14) 3.140000
%e float / double (notação científica) printf("%e", 0.000123) 1.230000e-04
%g float / double (formato mais compacto) printf("%g", 3.14) 3.14
%c char printf("%c", 'Z') Z
%s String (char[]) printf("%s", "Olá") Olá
%p Ponteiro (endereço de memória) printf("%p", &x) 0x7fff5a...
%o Inteiro em octal printf("%o", 8) 10
%x Inteiro em hexadecimal (minúsculo) printf("%x", 255) ff
%X Inteiro em hexadecimal (maiúsculo) printf("%X", 255) FF
%% Imprime o símbolo % literal printf("100%%") 100%

Largura de Campo e Precisão Decimal

O printf permite controlar a largura mínima do espaço ocupado pelo valor impresso e o número de casas decimais — muito útil para alinhar colunas em tabelas.

Largura de campo

Um número entre % e o tipo define a largura mínima. O valor é alinhado à direita por padrão:

#include <stdio.h>

int main() {
    printf("%5d\n",  42);     // "   42"  — 5 chars, alinhado à direita
    printf("%5d\n",  1234);   // " 1234"
    printf("%5d\n",  99999);  // "99999"  — ultrapassa a largura, sem corte
    printf("%-5d|\n", 42);    // "42   |" — flag - alinha à esquerda
    return 0;
}

   42

 1234

99999

42   |

Precisão decimal

O ponto seguido de um número após a largura define as casas decimais:

#include <stdio.h>

int main() {
    double pi = 3.141592653589793;

    printf("%.0f\n",  pi);   // "3"       — sem casas decimais
    printf("%.2f\n",  pi);   // "3.14"
    printf("%.5f\n",  pi);   // "3.14159"
    printf("%.10f\n", pi);   // "3.1415926536"
    printf("%10.3f\n", pi);  // "     3.142"  — largura 10, 3 decimais
    return 0;
}

3

3.14

3.14159

3.1415926536

     3.142

Preenchimento com zeros

A flag 0 preenche com zeros à esquerda em vez de espaços:

printf("%05d\n", 42);    // "00042"
printf("%08.2f\n", 3.14); // "00003.14"

00042

00003.14

Exemplo prático: tabela formatada

#include <stdio.h>

int main() {
    printf("%-12s %6s %8s\n", "Produto", "Qtd", "Preco");
    printf("%-12s %6d %8.2f\n", "Caneta",   10,  2.50);
    printf("%-12s %6d %8.2f\n", "Caderno",   3, 15.90);
    printf("%-12s %6d %8.2f\n", "Regua",     5,  4.75);
    return 0;
}

Produto        Qtd    Preco

Caneta          10     2.50

Caderno          3    15.90

Regua            5     4.75

A função scanf

O scanf (scan formatted) lê dados digitados pelo usuário e os armazena em variáveis. Sua sintaxe espelha a do printf, mas exige o operador & (endereço de memória) antes de cada variável — exceto strings.

scanf("string de formato", &var1, &var2, ...);

O & fornece ao scanf o endereço de memória de cada variável para que ele possa gravar o valor lido diretamente naquele local. Sem o &, o comportamento é indefinido — um dos erros mais comuns em iniciantes.

Lendo diferentes tipos

#include <stdio.h>

int main() {
    int    idade;
    float  altura;
    char   inicial;

    printf("Digite sua idade: ");
    scanf("%d", &idade);

    printf("Digite sua altura (ex: 1.75): ");
    scanf("%f", &altura);

    printf("Digite sua inicial: ");
    scanf(" %c", &inicial);   // espaço antes de %c — descarta o '\n' residual

    printf("\nIdade: %d | Altura: %.2f m | Inicial: %c\n",
           idade, altura, inicial);
    return 0;
}

Digite sua idade: 22

Digite sua altura (ex: 1.75): 1.75

Digite sua inicial: A

 

Idade: 22 | Altura: 1.75 m | Inicial: A

Lendo múltiplos valores em um único scanf

É possível ler vários valores de uma vez, separando os especificadores. O usuário deve digitar os valores separados por espaços ou Enter:

#include <stdio.h>

int main() {
    int a, b;
    printf("Digite dois inteiros: ");
    scanf("%d %d", &a, &b);
    printf("Soma: %d\n", a + b);
    return 0;
}

Digite dois inteiros: 10 25

Soma: 35

Atenção ao buffer do teclado: Após um scanf("%d"), o caractere \n (Enter) fica no buffer de entrada. Se o próximo scanf usa %c, ele captura esse \n em vez do caractere desejado. A solução é adicionar um espaço antes de %c:
scanf(" %c", &letra); — o espaço instrui o scanf a descartar qualquer espaço em branco residual, incluindo o \n.

scanf para double: use %lf

Atenção a uma diferença importante: no printf, tanto float quanto double usam %f. No scanf, double exige obrigatoriamente %lf:

Tipo scanf printf
float %f %f
double %lf ⚠️ %f
long double %Lf %Lf

Suporte a Acentos: locale.h

Por padrão, o C usa o locale "C" (inglês), que pode não exibir corretamente caracteres acentuados como ã, é, ç. Para ativar o suporte ao idioma do sistema operacional, usa-se a função setlocale da biblioteca <locale.h>:

#include <stdio.h>
#include <locale.h>

int main() {
    setlocale(LC_ALL, "");   // ativa o locale do sistema (suporte a acentos)

    printf("Olá, bem-vindo ao Curso de C!\n");
    printf("Atenção: leia as instruções com cuidado.\n");

    return 0;
}

Olá, bem-vindo ao Curso de C!

Atenção: leia as instruções com cuidado.

DICA: A string "" passada para setlocale significa "use o locale padrão do sistema operacional". Você também pode especificar explicitamente, por exemplo "pt_BR.UTF-8" no Linux ou "Portuguese_Brazil.1252" no Windows, mas usar "" é a forma mais portável.

Exemplo Completo do Material de Referência

O programa abaixo, diretamente da seção 4 do livro de referência do curso, demonstra na prática a leitura e escrita dos três tipos básicos — inteiro, ponto flutuante e caractere — com suporte a acentuação:

#include <stdio.h>
#include <locale.h>

void main() {
    setlocale(LC_ALL, "");  // Permite usar acentos

    printf("Olá \n");

    // ─── Lendo valor inteiro ───────────────────────────────
    int a = 50;
    printf("O valor de a é = %d \n", a);
    printf("Informe o novo valor de a: ");
    scanf("%d", &a);
    printf("O valor de a mudou para %d \n", a);

    // ─── Lendo valor com casas decimais ────────────────────
    float b = 5.5;
    printf("O valor de b é = %f \n", b);
    printf("Informe o novo valor de b: ");
    scanf("%f", &b);
    printf("O valor de b mudou para %f \n", b);

    // ─── Lendo letra ────────────────────────────────────────
    char letra = 't';
    printf("O valor de c é = %c \n", letra);
    printf("Informe o novo valor de c (letra): ");
    scanf(" %c", &letra);  // espaço antes de %c
    printf("O valor de c mudou para %c\n", letra);
}
Nota sobre void main(): O material de referência usa void main(), o que é aceito por alguns compiladores (como o MinGW no Code::Blocks), mas tecnicamente a forma padrão ANSI C é int main() com return 0; ao final. Para novos programas, prefira sempre int main().

printf em C versus Java

O Java também possui o método printf (na classe PrintStream), e ele usa os mesmos especificadores de formato. A principal diferença na leitura de dados é o uso de Scanner em Java versus scanf com & em C:

Operação C Java
Imprimir inteiro printf("%d\n", x) System.out.println(x)
Imprimir com 2 decimais printf("%.2f\n", x) System.out.printf("%.2f%n", x)
Ler inteiro scanf("%d", &x) x = sc.nextInt()
Ler double scanf("%lf", &x) x = sc.nextDouble()
Ler char scanf(" %c", &c) c = sc.next().charAt(0)
Suporte a acentos setlocale(LC_ALL, "") Nativo (Unicode)

Exercícios — Aula 03

Responda às questões abaixo para fixar printf, scanf e especificadores de formato:

1. Qual será a saída do seguinte código?

printf("%8.2f\n", 3.14159);

2. Para ler um valor do tipo double com scanf, qual especificador deve ser usado?

3. O que a flag - faz em um especificador como %-10s?

4. Por que é necessário adicionar um espaço antes de %c no scanf, como em scanf(" %c", &c)?

5. Qual será a saída do código abaixo?

printf("%05d\n", 42);

6. Para que serve a chamada setlocale(LC_ALL, "") no início de um programa C?

7. Analise o código. Qual será a saída?

printf("%.0f%%\n", 97.6);

8. Qual das alternativas lê corretamente dois inteiros em um único scanf?