Linux slogan
Visite também: BR-Linux.org · Dicas-L · Doode · NoticiasLinux · SoftwareLivre.org · UnderLinux



» Screenshot
Linux: Consumo após o boot
Por vsmoraes
» Login
Login:
Senha:

Se você ainda não possui uma conta, clique aqui.

Esqueci minha senha



Artigo

Parâmetros interessantes do scanf e do printf em C
Linux user
elgio
06/08/2009
O scanf pode parecer chato ao ler strings pelo fato de não tratar espaços em branco e não retirar o ENTER do teclado. Seu domínio tem sido, junto com o printf, um dos maiores problemas para quem está aprendendo C. Mas eles são poderosos.
Por: Elgio Schlemer | Blog: http://gravatai.ulbra.tche.br/~elgio
[ Hits: 108615 ]
Conceito: 10.0   7 voto(s)7 voto(s)7 voto(s)7 voto(s)7 voto(s) + quero dar nota ao artigo

O velho e bom printf

O printf, velho "amigo" dos programadores C, é esquisito a primeira vista. Principalmente ao pessoal que está aprendendo lógica, acostumado com algoritmos, demora um pouco para entender seu jeito de ser.

Basicamente o printf do C é dividido em duas partes bem distintas, sendo que pelo menos a primeira delas deve existir.

A primeira parte é chamada de string de formato ou, do inglês, format string. Ela nada mais é do que dizer ao printf que faça alguma coisa.

Exemplo:

printf("Ola");

Isto pode ser interpretado como uma ordem ao printf:
  • imprima a letra 'O';
  • imprima a letra 'l';
  • imprima a letra 'a'.

Dentro da string de formato, algumas sequências especiais de caracteres são comandos, como o '\n' por exemplo:

printf("Ola\n");

Isto pode ser interpretado como uma ordem ao printf:
  • imprima a letra 'O';
  • imprima a letra 'l';
  • imprima a letra 'a'.
  • imprima uma quebra de linha ('\n')

Na verdade sempre que na string de formato for encontrada uma contra barra ('\') ou um porcento ('%') será um comando. Alguns comandos mais usados:
  • \t - imprima uma tabulação
  • \\ - imprima uma contra barra
  • %d - imprima um valor em formato decimal (e como tem gente que confunde o 'd' de double)
  • %c - imprima um caractere
  • %i - imprima um valor no formato inteiro
  • %f - imprima um valor no formato ponto flutuante
  • %% - imprima o caractere %

Se a string de formato tiver um comando que mande imprimir alguma coisa, esta "alguma coisa" deverá ser fornecida. Assim, a segunda parte do printf são os parâmetros que satisfazem a string de formato. Exemplo:

printf ("Val=%d\n", 345);

  • imprima o 'V';
  • imprima o 'a';
  • imprima o 'l';
  • imprima o '=';
  • imprima um número em formato decimal ('%d');
  • imprima uma quebra de linha ('\n')

A segunda parte possui apenas um valor, o 345, que será usado pelo único %d existente.

Para cada comando que necessite de um parâmetro, um valor a mais deve estar na segunda parte. Coisas "estranhas" ocorrem quando se passa parâmetros de menos ou de mais.

Mas o objetivo deste artigo não é explicar o printf. Ele tem muitas outras opções além destas. O objetivo é tratar alguns parâmetros interessantes, pouco explorados pela maioria dos programadores. Começando pelo retorno da função, que praticamente ninguém usa.

O printf retorna um número inteiro, que é justamente a quantidade de caracteres que foram impressos.

tot = printf("Ola %d", 300);

No trecho de código anterior, tot acabará tendo o valor 7, pois será impresso na tela "Ola 300" (sem quebra de linha) e isto totalizaram sete caracteres.

Mas é no quesito "formatação" que o printf mostra do que é capaz.

É possível colocar o número de casas reservadas para a impressão, junto com o printf. Exemplo:

printf("Valor = %5d\n", 3);
printf("Valor = %5d\n", 30);
printf("Valor = %5d\n", 300);
printf("Valor = %5d\n", 3000);
printf("Valor = %5d\n", 30000);

O %5d indica que será impresso um decimal usando cinco casas decimais. As casas não usadas serão preenchidas com espaço em branco. A sequência de comandos anterior irá gerar a seguinte saída:

Valor =     3
Valor =    30
Valor =   300
Valor =  3000
Valor = 30000

Observe que os números ficaram à direita. Caso seja do interesse que o número fique à esquerda, basta colocar um sinal de menos antes:

printf("a=[%5d]\n", 3);
printf("a=[%-5d]\n", 3);

Observe como o número 3 foi ajustado entre os colchetes nas duas versões do printf.

Em se tratando de números, é ainda possível usar o ZERO para preencher os espaços não usados:

printf("a = %05d\n", 3);
printf("a = %05d\n", 30);
printf("a = %05d\n", 300);

Estes parâmetros são até bem conhecidos. Mas o que poucos sabem é que o 5, número de casas, pode ser também uma variável!

Considere este exemplo:

char frases[4][200];
int i;

for (i = 0; i < 4; i++){
    /* lendo 4 frases */
    scanf("%s", frases[i]);
}

for (i = 0; i < 4; i++){
    /* imprimindo formatado as 4 frases */
    printf("%-10s %d\n", frases[i], i);
}

Se o usuário digitar as seguintes frases:

Apenas_Um_Teste
lixo
Vol
hehehe

Será impresso na tela:

Apenas_Um_Teste 0
lixo       1
Vol        2
hehehe     3

Veja que o "Apenas_um_teste" foi maior do que o tamanho 10 inicialmente pensado, por isto ele ficou desformatado.

No entanto, o seguinte código tem um aspecto bem melhor:

char frases[4][200];
int i, m=-1,x;

for (i = 0; i < 4; i++){
    /* lendo 4 frases */
    scanf("%s", frases[i]);
    x = strlen(frases[i]);
    if (x > m)
       m = x;
}

m = m + 1;
for (i = 0; i < 4; i++){
    /* imprimindo formatado as 4 frases */
    printf("%-*s %d\n", m, frases[i], i);
}

Agora o tamanho da maior string digitada é armazenado na variável m. Quando elas foram impressas, usou-se o comando:

printf("%-*s %d\n", m, frases[i], i);

Veja que tem um asterisco no lugar de onde estaria o valor 10. Isto indica ao printf para usar um dos parâmetros no lugar do *.

    Próxima página >>




Páginas do artigo
   1. O velho e bom printf
   2. Lendo com scanf
   3. Conclusão

Outros artigos deste autor

Leitura recomendada

Comentários
[1] Comentário enviado por fachmann em 07/08/2009 - 11:33h:

Excelente!
Vai quebrar um galhão!
Abraço.


[2] Comentário enviado por cesar em 07/08/2009 - 11:45h:

Boa elgio,

Parabéns, aproveitando vou fazer uma pergunta =P

quando eu tenho um printf assim por exemplo, printf ("Número"); palavras com acento(entre outras) dentro do printf ao executar a impressão saí "suja" com caracter especial (estranho), como posso resolver isto?

[]'s


[3] Comentário enviado por foguinho.peruca em 07/08/2009 - 22:11h:

^^''

Bom artigo!

Lembrou os bons e velhos tempos da faculdade, bem no começo, onde a gente aprendia logica e implementa em C ainda....
Uma pergunta: fflush(stdin) "suja" o buffer? Eu jurava que limpava... qdo eu tinha problemas pra ler algo da entrada padrão eu "limpava" com o fflsuh(stdin). Bom, sempre resolveu.... ;)

Jeff


[4] Comentário enviado por elgio em 08/08/2009 - 10:21h:

Oi Jeff

Você não me entendeu.
Não quis dizer que o fflush "suja" o buffer. Ele limpa, como disseste.

Quis dizer que esta é uma solução "suja", no sentido de não tão boa. O jeito fácil de se fazer mas que não é a melhor.

Primeiro que o comportamento de fflush é distinto no Dos e no Linux.

Segundo que ao se usar o fflush PARA ESTE PROBLEMA inviabiliza completamente o uso de pipes e redirecionamentos.

Se no DOS tu criou um arquivo dados.txt:

Primeira linha
Segunda Linha
3455
34.5

E execucar:

C:\> teste.exe < dados.txt

O conteúdo o arquivo será jogado para o programa como se tivesse sido digitado.
Com a minha solução ele irá descartar as frases "Primeira linha", "Segunda linha" e irá ler o 3455 para o scanf("%d...

Com fflush ele irá descartar TUDO!

Então fflush é como explodir um prédio porque uma parede precisa ser refeita, entende! Neste caso!


[5] Comentário enviado por thiagoamm em 08/08/2009 - 23:33h:

Otimo artigo.
Bastante didatico e aborda algo fundamental.
Parabens!!!


[6] Comentário enviado por inacioalves em 30/10/2009 - 11:03h:

Excelente artigo professor Elgio.

Eu particularmente não conhecia estes parâmetros de scanf e printf. Para fazer a leitura de uma por exemplo, eu escrivia minha própria função indicando um caractere de quebra. Vou indicar este artigo para meus alunos usarem no próximo trabalho.


[7] Comentário enviado por tulios em 03/01/2010 - 13:34h:

Excelente Elgio!

Parabens...


[8] Comentário enviado por grammaton em 03/03/2010 - 10:37h:

Amigo, bom dia.

Preciso criar um prompt para uma aplicação no console do linux, mas usando o scanf quando aperto as teclas direcionais aparece lixo com :
^[[C^[[A^[[D^[[B

Tem como fazer o scanf não imprimir esse lixo, ou funcionar como um prompt normal de console, isto é, ao pressionar as teclas o cursor mover pelo texto digitado.

Caso não seja possivel via scanf, poderia me indicar alguma lib? Pode ser em C ou C++.

Grato


[9] Comentário enviado por mbcm94 em 14/10/2011 - 17:19h:

scanf("%VARIAVEL[^\n]s", frase);

Boa tarde, gostaria de saber se é possivel passar uma variavel dentro da string parametro do scanf.


[10] Comentário enviado por elgio em 14/03/2013 - 21:00h:


[9] Comentário enviado por mbcm94 em 14/10/2011 - 17:19h:

scanf("%VARIAVEL[^\n]s", frase);

Boa tarde, gostaria de saber se é possivel passar uma variavel dentro da string parametro do scanf.


Não, não é.



Contribuir com comentário


  
Para executar esta ação você precisa estar logado no site, caso contrário, tudo o que for digitado será perdido.
Responsável pelo site: Fábio Berbert de Paula - Conteúdo distribuído sob licença GNU FDL
Site hospedado por:

Viva o Linux

A maior comunidade Linux da América Latina! Artigos, dicas, tutoriais, fórum, scripts e muito mais. Ideal para quem busca auto-ajuda em Linux.