C Formatos do printf
Na aula Saída com printf você usou o %d para mostrar um número inteiro. Ele é só um de uma família inteira de formatos: há um para números com vírgula, um para letras, um para textos, um para hexadecimal… e todos aceitam ajustes como "ocupe 5 espaços", "mostre 2 casas decimais" ou "complete com zeros". Nesta aula você vai conhecer cada formato, montar uma tabela alinhada (a lista de compras da Ana) e ver o que acontece quando o formato não combina com o valor, um dos erros mais comuns em C.
- As partes de um formato:
%, ajustes e a letra do tipo. - Os formatos de inteiros:
%d,%i,%u,%ld,%lld,%x,%X,%o. - Os de números com vírgula:
%f,%.2f,%e,%g. - Os de letras e textos (
%c,%s), os especiais%zue%p, e como mostrar o próprio%. - Largura e alinhamento:
%5d,%-10s,%05d,%+d. - O que acontece com um formato errado: os avisos do
-Walle a saída "lixo".
Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa. Você pode repetir cada um no editor do guia, que compila C de verdade no navegador.
A ideia: um formulário com lacunas
Pense num formulário de papel: "Nome: ______ Idade: ___ anos". O texto já está impresso; você só preenche as lacunas. E cada lacuna espera um tipo de resposta: na de idade vai um número, não um nome.
O primeiro texto do printf é esse formulário. Cada % abre uma lacuna, e a letra depois dele diz o que vai ali. Os valores que vêm depois da vírgula preenchem as lacunas, na ordem:
#include <stdio.h>
int main(void) {
printf("Nome: %s Idade: %d anos Altura: %.2f m\n", "Ana", 29, 1.65);
return 0;
}
$ gcc -std=c23 -Wall -Wextra ficha.c -o ficha $ ./ficha Nome: Ana Idade: 29 anos Altura: 1.65 m
| Lacuna | Preenchida por | Resultado |
|---|---|---|
%s (texto) | "Ana" | Ana |
%d (inteiro) | 29 | 29 |
%.2f (número com vírgula, 2 casas) | 1.65 | 1.65 |
O nome técnico de cada lacuna é especificador de formato (format specifier), ou só "formato". A regra de ouro desta aula inteira: o formato tem de combinar com o tipo do valor. O printf não confere isso sozinho; quem confere é o compilador, com os avisos do -Wall (seção 7).
1. As partes de um formato
Um formato pode ter até cinco partes. Só a primeira e a última são obrigatórias:
% [ajustes] [largura] [.precisão] [tamanho] tipo % - 10 .2 l f
- %
- Abre a lacuna. Tudo até a letra do tipo faz parte do formato.
- ajustes (flags)
- Símbolos que mudam o jeito de mostrar:
-(alinhar à esquerda),0(completar com zeros),+(sempre mostrar o sinal), espaço e#. Seção 6. - largura
- Quantos caracteres a lacuna ocupa no mínimo:
%5docupa 5. - .precisão
- Um ponto e um número. Para números com vírgula, quantas casas decimais:
%.2f. Para textos, quantas letras no máximo:%.3s. - tamanho
- Letras que avisam um tipo maior ou menor:
lparalong,llparalong long,zparasize_t. - tipo
- A letra que diz o que é o valor:
d(inteiro),f(com vírgula),s(texto)…
As próximas seções mostram cada tipo. Ao final, a tabela de referência junta tudo.
2. Números inteiros
Este programa mostra cada formato de inteiro ao lado do que ele produz. Repare num truque: para mostrar o próprio sinal % na tela, escreve-se %% (seção 5).
#include <stdio.h>
int main(void) {
int idade = 29;
unsigned int visitas = 3000000000u;
long populacao = 2147483647L;
long long estrelas = 100000000000LL;
printf("%%d -> %d\n", idade);
printf("%%i -> %i\n", idade);
printf("%%u -> %u\n", visitas);
printf("%%ld -> %ld\n", populacao);
printf("%%lld -> %lld\n", estrelas);
printf("%%x -> %x\n", 255);
printf("%%X -> %X\n", 255);
printf("%%o -> %o\n", 8);
return 0;
}
$ gcc -std=c23 -Wall -Wextra inteiros.c -o inteiros $ ./inteiros %d -> 29 %i -> 29 %u -> 3000000000 %ld -> 2147483647 %lld -> 100000000000 %x -> ff %X -> FF %o -> 10
- %d
- De decimal: um
intna base 10, a que usamos no dia a dia. É o formato que você mais vai usar. - %i
- De integer (inteiro). No
printf, é igualzinho ao%d. (Noscanfeles são diferentes; veja Entrada com scanf.) - %u
- De unsigned, "sem sinal": um
unsigned int, que não tem negativos e por isso vai mais longe (até 4294967295). Os tipos estão em Inteiros. - %ld
- O
l(de long) avisa que o valor é umlong. - %lld
- Dois
l: umlong long, o maior inteiro padrão (até 9223372036854775807). - %x e %X
- Mostra o número em hexadecimal (base 16, com os "algarismos" 0–9 e a–f).
255viraff; comXmaiúsculo,FF. Aparece muito em cores (#FF8800) e em endereços de memória. - %o
- Mostra em octal (base 8).
8vira10. Hoje quase só aparece nas permissões de arquivos do Linux (chmod 755).
u, L e LL
As letras no fim de 3000000000u, 2147483647L e 100000000000LL dizem ao compilador o tipo do número escrito: u = unsigned, L = long, LL = long long. A aula Inteiros explica quando são necessárias.
Negativo com %u: o número "dá a volta"
O formato não converte nada: ele só diz ao printf como ler os bits do valor. Um -1 lido como "sem sinal" vira o maior unsigned int:
$ cat volta.c
#include <stdio.h>
int main(void) {
printf("%d\n", -1);
printf("%u\n", -1);
return 0;
}
$ gcc -std=c23 -Wall -Wextra volta.c -o volta
$ ./volta
-1
4294967295
Nem o -Wall avisou. A explicação (como os negativos são guardados) está em Inteiros e em Conversão de Tipos. A lição aqui: use %u só para valores unsigned.
Uma letra é um número: %c × %d
Para o C, um char é um número pequeno (o código da letra na tabela ASCII, veja Caracteres). O formato decide se você vê a letra ou o número:
#include <stdio.h>
int main(void) {
char letra = 'A';
printf("%c %d\n", letra, letra);
printf("%c\n", 66);
printf("%x %X %o %d\n", 2026, 2026, 2026, 2026);
return 0;
}
$ gcc -std=c23 -Wall -Wextra letra.c -o letra $ ./letra A 65 « a mesma variável: como letra e como número B « 66 é o código do B 7ea 7EA 3752 2026 « 2026 em hexadecimal, hexadecimal maiúsculo, octal e decimal
3. Números com vírgula
Para double (e float), há três formatos, cada um com um jeito de escrever o número:
#include <stdio.h>
int main(void) {
double preco = 4.5;
printf("%%f -> %f\n", preco);
printf("%%.2f -> %.2f\n", preco);
printf("%%e -> %e\n", preco);
printf("%%g -> %g\n", preco);
printf("%g %g %g\n", 0.0001, 1234567.0, 100.0);
printf("%e\n", 1234567.0);
return 0;
}
$ gcc -std=c23 -Wall -Wextra reais.c -o reais $ ./reais %f -> 4.500000 %.2f -> 4.50 %e -> 4.500000e+00 %g -> 4.5 0.0001 1.23457e+06 100 1.234567e+06
- %f
- De floating point ("ponto flutuante", o nome técnico dos números com vírgula). Sem precisão, mostra sempre 6 casas:
4.500000. - %.2f
- Com precisão: exatamente 2 casas. É o formato de dinheiro:
4.50.%.1fdá uma casa,%.0fnenhuma. - %e
- Notação científica (exponent):
1.234567e+06quer dizer 1.234567 × 106, ou seja, 1234567. Bom para números enormes ou minúsculos. - %g
- De general ("geral"): escolhe sozinho entre
%fe%e, o que ficar mais curto, e tira os zeros inúteis do fim. Mostra até 6 algarismos significativos: por isso1234567virou1.23457e+06(arredondado).
O printf sempre usa ponto como separador decimal (4.50), como nos Estados Unidos, mesmo num computador em português. Mostrar 4,50 exige mudar a "localidade" do programa, assunto fora desta aula.
Arredondar com %.Nf
A precisão arredonda (não corta) o que mostra, e a variável não muda. Mas o arredondamento tem uma surpresa:
$ cat arredonda.c
#include <stdio.h>
int main(void) {
printf("%.0f %.0f %.0f\n", 2.5, 3.5, 2.6);
printf("%.2f\n", 1.005);
return 0;
}
$ gcc -std=c23 -Wall -Wextra arredonda.c -o arredonda
$ ./arredonda
2 4 3
1.00
2.5virou2, mas3.5virou4. Quando o número está exatamente no meio, a glibc arredonda para o vizinho par (é a regra padrão dos computadores, chamada "arredondamento do banqueiro").2.6não está no meio e vira3, como esperado.1.005virou1.00, e não1.01. O computador não consegue guardar 1.005 exato; guarda algo como 1.00499999…, que arredonda para baixo. A aula float e double explica por quê.
%f ou %lf?
No printf, tanto faz: %f e %lf mostram um double do mesmo jeito (um float é convertido para double antes de chegar ao printf). No scanf é diferente: lá, double exige %lf. A aula Entrada com scanf mostra o estrago de errar isso.
4. Letras e textos: %c e %s
#include <stdio.h>
int main(void) {
char inicial = 'A';
char nome[] = "Ana";
printf("Inicial: %c\n", inicial);
printf("Nome: %s\n", nome);
printf("Fruta: %.3s\n", "Banana");
return 0;
}
$ gcc -std=c23 -Wall -Wextra textos.c -o textos $ ./textos Inicial: A Nome: Ana Fruta: Ban
- %c
- De character: um caractere, guardado num
chare escrito entre aspas simples ('A'). - char nome[] = "Ana";
- Um texto guardado numa variável. Em C, texto é uma sequência de
char(aula Strings). - %s
- De string: um texto inteiro, até o fim. Pode receber uma variável de texto ou um texto entre aspas duplas.
- %.3s
- Com precisão, o
%smostra no máximo 3 letras:Ban.
5. Formatos especiais: %zu, %p e %%
#include <stdio.h>
int main(void) {
int idade = 29;
printf("Bytes de um int: %zu\n", sizeof idade);
printf("Endereço de idade: %p\n", (void *)&idade);
printf("Desconto: 10%%\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra especiais.c -o especiais $ ./especiais Bytes de um int: 4 Endereço de idade: 0x7fff58e00e44 Desconto: 10% $ ./especiais Bytes de um int: 4 Endereço de idade: 0x7ffd974cde64 « outro endereço a cada execução Desconto: 10%
- %zu
- Para o resultado de
sizeof(o tamanho de algo, em bytes), que tem o tiposize_t. Ozé o "tamanho" desize_t, e oué de unsigned: tamanho nunca é negativo. Aula Tamanho dos Tipos. - %p
- De pointer ("ponteiro"): um endereço de memória, em hexadecimal. O
&idadeé "o endereço deidade", e o(void *)é a forma correta de entregá-lo ao%p. Tudo isso é explicado em Memória e Endereços. - %%
- Como o
%abre uma lacuna, para mostrar um%de verdade escreva dois.
O editor roda o programa em WebAssembly de 32 bits, então o %p mostra endereços curtos (como 0x7ffff8), diferentes dos do gcc no Linux de 64 bits. O %zu funciona igual. Endereços nunca são iguais entre computadores e execuções: não escreva programas que dependam deles.
6. Largura e alinhamento
Até aqui, cada lacuna ocupou exatamente o espaço do valor. Com uma largura, ela passa a ocupar um mínimo de caracteres, completando com espaços. Os colchetes no programa abaixo só servem para você enxergar onde a lacuna começa e termina:
#include <stdio.h>
int main(void) {
printf("[%5d]\n", 42);
printf("[%-5d]\n", 42);
printf("[%05d]\n", 42);
printf("[%+d] [%+d]\n", 42, -42);
printf("[%10s]\n", "Ana");
printf("[%-10s]\n", "Ana");
printf("[%8.2f]\n", 3.14159);
printf("[%2d]\n", 12345);
return 0;
}
$ gcc -std=c23 -Wall -Wextra largura.c -o largura $ ./largura [ 42] [42 ] [00042] [+42] [-42] [ Ana] [Ana ] [ 3.14] [12345]
| Formato | Saída | O que aconteceu |
|---|---|---|
%5d | [ 42] | 5 espaços no mínimo; o número fica à direita (3 espaços + 42). |
%-5d | [42 ] | O - alinha à esquerda; os espaços vão para o fim. |
%05d | [00042] | O 0 antes da largura completa com zeros em vez de espaços. |
%+d | [+42] [-42] | O + mostra o sinal sempre, também nos positivos. |
%10s / %-10s | [ Ana] / [Ana ] | Funciona igual com texto. Textos costumam ir à esquerda, números à direita. |
%8.2f | [ 3.14] | Largura e precisão juntas: 8 caracteres no total (contando o ponto), 2 casas. |
%2d com 12345 | [12345] | A largura é um mínimo: um valor maior nunca é cortado. |
Uma tabela alinhada
A largura serve para fazer colunas. A lista de compras da Ana, com o nome à esquerda e os números à direita:
#include <stdio.h>
int main(void) {
printf("%-10s %5s %8s\n", "Item", "Qtd", "Preço");
printf("%-10s %5d %8.2f\n", "Arroz", 2, 6.5);
printf("%-10s %5d %8.2f\n", "Feijão", 1, 8.9);
printf("%-10s %5d %8.2f\n", "Café", 3, 15.75);
return 0;
}
$ gcc -std=c23 -Wall -Wextra compras.c -o compras $ ./compras Item Qtd Preço Arroz 2 6.50 Feijão 1 8.90 Café 3 15.75
Quase deu certo, mas as linhas de Feijão, Café e o título Preço saíram tortas, um espaço a menos. Não é erro seu: o printf conta a largura em bytes, e cada letra acentuada (ã, é, ç) ocupa 2 bytes no UTF-8, a codificação usada no Linux. "Feijão" tem 6 letras, mas 7 bytes; o printf acha que já ocupou 7 das 10 posições e põe só 3 espaços. A aula Acentos e UTF-8 explica a fundo; por ora, em tabelas alinhadas, prefira nomes sem acento ou compense a largura à mão.
Missão: a lista abaixo sai toda grudada. Use larguras para alinhar: o nome à esquerda em 10 posições, a quantidade à direita em 5 e o preço à direita em 8, com 2 casas (com um espaço entre as colunas, como no exemplo acima). A saída deve ficar assim:
Arroz 2 6.50 Leite 12 4.25 Ovos 30 18.00
#include <stdio.h>
int main(void) {
printf("%s %d %f\n", "Arroz", 2, 6.5);
printf("%s %d %f\n", "Leite", 12, 4.25);
printf("%s %d %f\n", "Ovos", 30, 18.0);
return 0;
}
#include <stdio.h>
int main(void) {
printf("%-10s %5d %8.2f\n", "Arroz", 2, 6.5);
printf("%-10s %5d %8.2f\n", "Leite", 12, 4.25);
printf("%-10s %5d %8.2f\n", "Ovos", 30, 18.0);
return 0;
}
Outros ajustes
$ cat ajustes.c
#include <stdio.h>
int main(void) {
printf("[%*d]\n", 6, 42);
printf("[%#x] [%#o]\n", 255, 8);
printf("[% d] [% d]\n", 42, -42);
printf("Pedido nº %03d\n", 7);
return 0;
}
$ gcc -std=c23 -Wall -Wextra ajustes.c -o ajustes
$ ./ajustes
[ 42]
[0xff] [010]
[ 42] [-42]
Pedido nº 007
- %*d
- O
*no lugar da largura diz: "a largura vem de um valor". O primeiro valor (6) é a largura; o segundo (42) é o número. Útil quando a largura é calculada pelo programa. - %#x e %#o
- O
#acrescenta o prefixo que identifica a base:0xpara hexadecimal,0para octal. São os mesmos prefixos que o C usa para escrever números nessas bases no código. - % d
- Um espaço como ajuste: põe um espaço no lugar do
+dos positivos, para alinhar com os negativos. - %03d
- Zeros à esquerda até 3 dígitos: o jeito de numerar pedidos, notas fiscais e arquivos (
foto007.jpg).
7. O formato errado
O printf confia no formato. Se você diz %f e entrega um int, ele vai procurar um double onde não há, e mostra o que encontrar. Por sorte, o gcc confere os formatos quando o texto está escrito direto no printf, e o -Wall liga esse aviso:
#include <stdio.h>
int main(void) {
int idade = 29;
double preco = 4.5;
printf("Idade: %f\n", idade);
printf("Preço: %d\n", preco);
printf("Dois números: %d %d\n", idade);
return 0;
}
$ gcc -std=c23 -Wall -Wextra errado.c -o errado
errado.c: In function ‘main’:
errado.c:6:21: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
6 | printf("Idade: %f\n", idade);
| ~^ ~~~~~
| | |
| | int
| double
| %d
errado.c:7:21: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
7 | printf("Preço: %d\n", preco);
| ~^ ~~~~~
| | |
| int double
| %f
errado.c:8:31: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
8 | printf("Dois números: %d %d\n", idade);
| ~^
| |
| int
$ ./errado
Idade: 0.000000
Preço: 2140133728
Dois números: 29 -2016665569
$ ./errado
Idade: 0.000000
Preço: -1266114704 « muda a cada execução
Dois números: 29 835022879
- format ‘%f’ expects argument of type ‘double’
- "O formato
%fespera um valor do tipodouble…" - but argument 2 has type ‘int’
- "…mas o argumento 2 é um
int." Os argumentos são contados a partir do texto do formato, que é o argumento 1. - os desenhos com
| - O gcc liga cada lacuna ao valor que a preenche e escreve o tipo de cada lado:
doubleembaixo do%f,intembaixo deidade. - %d (na última linha do aviso)
- A sugestão de conserto: "troque por
%d". - expects a matching ‘int’ argument
- "Espera um argumento
intcorrespondente": há duas lacunas e só um valor. - [-Wformat=]
- A regra de aviso que conferiu os formatos. Ela vem no
-Wall.
São só avisos, então o programa foi gerado, e a saída mostra o estrago: 0.000000 no lugar de 29, um número sem sentido no lugar de 4.5 e um "segundo número" que ninguém passou. Ler um valor com o formato errado é comportamento indefinido: a linguagem não promete nada (aula Comportamento Indefinido). Os números mudam a cada execução e de um computador para outro.
O Clang avisa a mesma coisa com outras palavras: format specifies type 'double' but the argument has type 'int' [-Wformat] ("o formato indica o tipo double, mas o argumento é int") e more '%' conversions than data arguments ("mais lacunas % do que valores"). A saída errada também é diferente: no editor saiu Preço: 0 e Dois números: 29 0. Lixo é lixo, em qualquer computador.
Quando o lixo derruba o programa
Com %s, o estrago é maior: o printf trata o valor como o endereço de um texto e vai ler a memória nesse endereço.
$ cat cliente.c
#include <stdio.h>
int main(void) {
int codigo = 65;
printf("Cliente: %s\n", codigo);
return 0;
}
$ gcc -std=c23 -Wall -Wextra cliente.c -o cliente
cliente.c: In function ‘main’:
cliente.c:5:23: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
5 | printf("Cliente: %s\n", codigo);
| ~^ ~~~~~~
| | |
| | int
| char *
| %d
$ ./cliente
Falha de segmentação (imagem do núcleo gravada) ./cliente
$ echo $?
139
O endereço 65 não pertence ao programa, e o sistema o derrubou: Falha de segmentação (segmentation fault) é o aviso do Bash de que o programa tentou mexer numa memória proibida; o código de saída 139 confirma. O char * da mensagem é o tipo "endereço de texto" (aula Ponteiros e Strings). Regra: nunca ignore um aviso -Wformat; ele aponta um erro de verdade.
Missão: rode e leia os avisos: os três formatos estão trocados e a saída sai errada. Conserte só os formatos (as letras depois do %), sem mexer nas variáveis, para o programa mostrar Idade: 29 anos, Preço: R$ 4.50 e Inicial: A, sem nenhum aviso.
#include <stdio.h>
int main(void) {
int idade = 29;
double preco = 4.5;
char inicial = 'A';
printf("Idade: %f anos\n", idade);
printf("Preço: R$ %d\n", preco);
printf("Inicial: %s\n", inicial);
return 0;
}
#include <stdio.h>
int main(void) {
int idade = 29;
double preco = 4.5;
char inicial = 'A';
printf("Idade: %d anos\n", idade);
printf("Preço: R$ %.2f\n", preco);
printf("Inicial: %c\n", inicial);
return 0;
}
Formas diferentes: qual usar
Muitas vezes há mais de um formato que "funciona". Esta tabela mostra a escolha do guia:
| Para mostrar… | Opções | Use | Por quê |
|---|---|---|---|
Um int | %d, %i | %d | Os dois são iguais no printf, mas %d é o que todo mundo usa, e no scanf o %i tem uma pegadinha. |
| Dinheiro | %f, %g, %.2f | %.2f | Sempre 2 casas: 4.50, e não 4.500000 nem 4.5. |
| Um resultado de conta, sem saber o tamanho | %f, %g | %g | Tira zeros inúteis e muda sozinho para notação científica quando o número é enorme ou minúsculo. |
| Números de ciência (distâncias, massas) | %f, %e | %e | 1.989000e+30 é legível; %f escreveria 31 algarismos. |
Um sizeof | %d, %lu, %zu | %zu | É o formato feito para size_t; os outros dão aviso em algum computador. |
| Um texto fixo, sem lacunas | printf("Oi\n"), puts("Oi") | Qualquer um | puts ("put string") já põe o \n no fim. O printf é mais flexível. Se o texto tiver um %, no printf ele vira %%. |
Quando dá errado
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’
O que significa: o formato não combina com o tipo do valor. O programa vai mostrar lixo naquela lacuna.
Como consertar: troque o formato pelo do tipo certo (a sugestão aparece na última linha do aviso) ou, se você quer mesmo o valor em outro tipo, converta de propósito: (int)preco (aula Conversão de Tipos).
warning: format ‘%d’ expects a matching ‘int’ argument
O que significa: há mais lacunas % do que valores depois da vírgula. A lacuna sem valor mostra lixo. (Se for o contrário, mais valores que lacunas, o gcc avisa too many arguments for format, e os valores a mais são ignorados.)
Como consertar: conte as lacunas e os valores: tem de ser um para um, na mesma ordem.
0.000000, sem aviso nenhum
O que significa: provavelmente você compilou sem -Wall, e o aviso de formato não apareceu.
Como consertar: compile sempre com gcc -std=c23 -Wall -Wextra e leia os avisos -Wformat.
Falha de segmentação numa linha com %s
O que significa: o %s recebeu algo que não é um texto (um número, um char sozinho), e o printf tentou ler a memória num endereço inválido.
Como consertar: para um char, use %c; para números, %d ou %f. O aviso expects argument of type ‘char *’ já tinha apontado a linha.
O que significa: a largura (%-10s) conta bytes, e letras acentuadas ocupam 2 bytes em UTF-8.
Como consertar: use nomes sem acento nas colunas alinhadas, ou aumente a largura em 1 para cada acento. Detalhes em Acentos e UTF-8.
Referência
Os tipos (a letra do fim)
| Formato | Tipo do valor | Exemplo | Saída |
|---|---|---|---|
%d ou %i | int (e char, short) | printf("%d", 29) | 29 |
%u | unsigned int | printf("%u", 3000000000u) | 3000000000 |
%ld / %lu | long / unsigned long | printf("%ld", 100L) | 100 |
%lld / %llu | long long / unsigned long long | printf("%lld", 100000000000LL) | 100000000000 |
%hd / %hhd | short / signed char (raros) | printf("%hd", (short)7) | 7 |
%x / %X | inteiro sem sinal, em hexadecimal | printf("%x %X", 255, 255) | ff FF |
%o | inteiro sem sinal, em octal | printf("%o", 8) | 10 |
%f (ou %lf) | double (e float) | printf("%f", 4.5) | 4.500000 |
%e / %E | double, notação científica | printf("%e", 1234567.0) | 1.234567e+06 |
%g / %G | double, o mais curto entre %f e %e | printf("%g", 4.5) | 4.5 |
%Lf | long double | printf("%Lf", 4.5L) | 4.500000 |
%c | um caractere (char) | printf("%c", 'A') | A |
%s | texto (char[] ou char *) | printf("%s", "Ana") | Ana |
%zu | size_t (resultado de sizeof) | printf("%zu", sizeof(int)) | 4 |
%p | endereço (void *) | printf("%p", (void *)&x) | 0x7ffc… (muda) |
%% | nenhum: mostra um % | printf("10%%") | 10% |
Os ajustes, a largura e a precisão
| Escrita | Efeito | Exemplo | Saída |
|---|---|---|---|
%5d | largura mínima 5, à direita | printf("[%5d]", 42) | [ 42] |
%-5d | largura 5, à esquerda | printf("[%-5d]", 42) | [42 ] |
%05d | completa com zeros | printf("[%05d]", 42) | [00042] |
%+d | sinal sempre | printf("%+d", 42) | +42 |
% d | espaço no lugar do + | printf("[% d]", 42) | [ 42] |
%#x / %#o | prefixo da base | printf("%#x", 255) | 0xff |
%.2f | 2 casas decimais (arredonda) | printf("%.2f", 3.14159) | 3.14 |
%8.2f | largura 8 e 2 casas | printf("[%8.2f]", 3.14159) | [ 3.14] |
%.3s | no máximo 3 letras | printf("%.3s", "Banana") | Ban |
%-10s | texto em 10 posições, à esquerda | printf("[%-10s]", "Ana") | [Ana ] |
%*d | largura vinda de um valor | printf("[%*d]", 6, 42) | [ 42] |
A página printf e scanf, na seção de referência, junta esta tabela com os formatos do scanf.
Exercícios
1. O formato do dinheiro
Complete para mostrar R$ 12.90, com exatamente 2 casas:
2. Zeros à esquerda
Complete para que o pedido 7 apareça como Pedido 0007:
3. O sinal de por cento
Complete para mostrar Desconto: 15%:
4. O que printf("[%-6s]", "Ana"); mostra?
5. Qual o formato certo para o resultado de sizeof(double)?
6. double nota = 7.5; e printf("%d\n", nota);. Compilando com -Wall, o que acontece?
Missão final: o cupom da lojinha
Missão: complete os printf do cupom (troque cada ??? pelo formato certo) para a saída ficar exatamente como abaixo, sem avisos. Dicas: o pedido tem 4 dígitos com zeros; o nome do produto ocupa 12 posições à esquerda; a quantidade, 4 à direita; o preço, 8 à direita com 2 casas.
Pedido nº 0042 Cliente: Ana Caderno 3 x R$ 12.90 Desconto: 10% Total: R$ 34.83
#include <stdio.h>
int main(void) {
int pedido = 42;
char cliente[] = "Ana";
char produto[] = "Caderno";
int quantidade = 3;
double preco = 12.90;
int desconto = 10;
double total = quantidade * preco * (100 - desconto) / 100;
printf("Pedido nº ???\n", pedido);
printf("Cliente: ???\n", cliente);
printf("??????? x R$ ???\n", produto, quantidade, preco);
printf("Desconto: ???\n", desconto);
printf("Total: R$ ???\n", total);
return 0;
}
#include <stdio.h>
int main(void) {
int pedido = 42;
char cliente[] = "Ana";
char produto[] = "Caderno";
int quantidade = 3;
double preco = 12.90;
int desconto = 10;
double total = quantidade * preco * (100 - desconto) / 100;
printf("Pedido nº %04d\n", pedido);
printf("Cliente: %s\n", cliente);
printf("%-12s%4d x R$ %8.2f\n", produto, quantidade, preco);
printf("Desconto: %d%%\n", desconto);
printf("Total: R$ %.2f\n", total);
return 0;
}
A conta do total usa operadores da próxima parte do guia (Operadores Aritméticos): 3 × 12.90 = 38.70, menos 10% = 34.83.
Resumo
- Cada
%abre uma lacuna; a letra do fim diz o tipo; os valores preenchem as lacunas na ordem. O formato tem de combinar com o tipo. - Inteiros:
%d(ou%i),%u(sem sinal),%ld,%lld; em outras bases,%x/%X(hexadecimal) e%o(octal). - Com vírgula:
%f(6 casas),%.2f(2 casas, arredonda),%e(científica),%g(o mais curto). Noprintf,%lf=%f. %c= um caractere,%s= texto,%zu=sizeof,%p= endereço,%%= o próprio%.- Largura:
%5d(direita),%-10s(esquerda),%05d(zeros),%+d(sinal). A largura é mínima, conta bytes (acentos contam 2) e nunca corta. - Formato errado = aviso
-Wformatdo-Walle saída lixo (ou atéFalha de segmentaçãocom%s). Nunca ignore esse aviso.