VOLPITI - Tecnologia da Informação
 
Busca
Tópicos
  Cadastre-se :: Hospedagem LinuxDicas :: Acessórios LinuxDicas :: Fórum LinuxDicas   

Usuários LinuxDicas
· AvantGO
· Backend XML (RSS)
· Contato/Publicidade
· Enviar Notícias/Artigos
· Fórum LinuxDicas
· Lista de Discussão
· Mensagens Privadas

Casa do Linux


Lista de Discussão
·[linuxdicas] quetão de linux
·Ferramenta de Backup
·redes
·Search Engine

Leia mais...

Artigos LinuxDicas
· Resistência ao Linux
· Guia para o Novato
· Licenciamento do SuSE
· Foca GNU/Linux - Iniciante
· Foca GNU/Linux - Intermediário
· Foca GNU/Linux - Avançadoe
· Curso C
· Outras Seções de Artigos

FAQ LinuxDicas
· Licença
· Servidores
· Ambiente X
· Hardware
· Instalação
· Internet
· Aplicativos
· Sistema
· StarOffice

Notícias Velhas
Segunda, abril 21
· MON - Monitorando a disponibilidade de serviços
Quinta, abril 17
· Últimos dias para Inscrições de Palestras no Flisol Campinas
· Acessando seus arquivos de sua máquina de qualquer computador do mundo
Terça, abril 15
· Artigo sobre o Moregroupware
Segunda, abril 14
· Análise do Mandriva Xtreme2 Pack
Terça, março 18
· Como migrar dados do msaccess para mysql
· A verdadeira razão para usarmos Linux
· usando o rsync 3.0.0 para fazer backup entre linux e xp
· Firefox3 : Como Instalar manualmente.
Sábado, fevereiro 09
· Configurando um DNS CHROOTED Primário e Reverso para o seu site.
Quinta, dezembro 27
· Censurando a internet com o OpenDNS
Domingo, outubro 14
· Bandwidth Monitoring Tools For Linux
Quinta, outubro 11
· Variáveis de ambiente
Quinta, agosto 02
· Rodando processos em múltiplos servidores, Cluster!!!
· Instalando XEN no seu Ubuntu/Debian
Domingo, junho 17
· Vovó, faz backup pra mim?
Quarta, junho 13
· Canetas: Idealismo Antártico
Quinta, junho 07
· CA confiável com certificados digitais
Domingo, junho 03
· Equações Matemáticas via Shell
Sábado, junho 02
· Permanent Link to Garimpar é preciso [2]: Confira seu e-mail

Notícias antigas

Versões Estáveis
· Kernel Linux
· *nix e *BSD ISOs da Unicamp
· Linux ISO
· FreeBSD Releases

Curso de C - 5. Entrada e Saída pelo Console

(2608 total de palavras neste texto)
(5742 vizualização(ões))   Imprimir




Curso de C - 5. Entrada e Saída pelo Console

Nesta aula vamos aprender a criar programas que interagem com o usuário, lendo dados do teclado e escrevendo dados no monitor de vídeo. Algumas funções já foram usadas e comentadas superficialmente, mas agora veremos estas mesmas a fundo.

O interessante em C é que as funções de entrada e saída, tanto pelo console como por arquivos, não são definidas como palavras-chave da linguagem. Todo sistema de entrada e saída em C é definido por bibliotecas, o que torna a linguagem bastante flexível neste aspecto.

Existem várias funções de entrada e saída pelo console que são exclusivas de um compilador ou de uma plataforma. Estas não serão vistas aqui, por não fazerem parte do padrão C ANSI. Por exemplo, as funções de entrada e saída da biblioteca ncurses, as funções da biblioteca conio.h da Borland, etc.

Desta aula em diante, os exercícios serão programas que vocês criarão com os recursos aprendidos até aqui.

5.1. Lendo e escrevendo caracteres

A função getchar() é usada para ler caracteres, um por vez, da entrada padrão.

Forma geral da função getchar():

  #include <stdio.h>

  
  int main()
  {
  	char ch;
  	
  	ch= getchar();
  	return 0;
  }

Quando executamos o programa acima, a função getchar() obtém o próximo caractere da entrada padrão, só terminando a leitura após o pressionamento da tecla ENTER. É importante lembrar que getchar() lê um caractere por vez, não sendo usado para ler cadeias de caracteres (strings).

Existe um problema com getchar(): quando esta função efetua a leitura, fica uma "sujeira" no buffer de entrada, o que pode atrapalhar e resultar em erros no programa. Uma forma de contornar isso é colocar, após a leitura, o próprio comando getchar():

  #include <stdio.h>
  
  int main()
  {
  	char ch;
  	
  	ch= getchar();
  	getchar();	  /* isto limpa o buffer de entrada, eliminando as "sujeiras" deixadas pela leitura. */
  	return 0;
  }

Em um programa simples como esse não dá para ver o problema, mas se usar getchar() em um loop, por exemplo, será visível.

Para imprimir um caractere por vez, temos a função putchar().

Forma geral da função putchar():

  #include <stdio.h>
  
  int main()
  {
  	char ch;
  	
  	printf("Digite um caractere: ");
  	ch= getchar();		
  	putchar(ch);
  	return 0;
  }

O programa acima efetuará a leitura do caractere e imediatamente o imprimirá, tendo a seguinte saída:


  $ Digite um caractere: a
  $ a

Assim como getchar(), putchar() imprime um caractere somente por vez, não sendo possível usá-lo para imprimir strings.

5.2. Escrevendo com printf()

Como já vimos em vários exemplos, a função printf() é uma função genérica de impressão. Pode-se imprimir na tela qualquer tipo de dados, controlar o tamanho do campo de impressão, número de casas decimais, etc.

A forma geral da função printf() consiste em uma string de controle e uma lista de argumentos (que podem ser variáveis, expressões, etc.). No caso de imprimir somente uma string, não é necessário argumentos (da mesmo forma que fizemos na aula 2).

Forma geral de printf():

  printf("string de controle", argumentos);

A string de controle pode consistir de dois itens: o texto a ser exibido e comandos de controle que definem o formato do(s) tipo(s) a ser(em) impresso(s). Vamos ver alguns exemplos:

  printf("Inteiro com sinal: %d", num);
  printf("Caractere: %c", ch);
  printf("String: %s", str);
  printf("Ponto flutuante decimal: %f", fp);
  printf("Ponto flutuante em notação científica: %e", fp);

Os argumentos num, ch, str e fp são variáveis. Os caracteres %d, %c, %s, etc, são os comandos de controle para cada tipo específico. Veja a seguir uma tabela desses comandos de controle:

Comando Tipo a ser impresso
%c caractere
%d ou %i inteiro com sinal
%u inteiro sem sinal
%ld decimal longo
%x ou %X hexadecimal
%o octal
%f ponto flutuante decimal
%lf ponto flutuante longo (double)
%e ou %E ponto flutuante notação científica
%g ou %G usa %e ou %E ou %f, o que for mais curto
%n escreve o número de caracteres impresso até esse ponto
%p escreve um endereço
%s escreve uma string
%% escreve o caractere %

Como vocês já viram em vários exemplos, para imprimir uma variável usando printf() basta colocar o comando de controle referente ao tipo no lugar a ser impresso, e colocar a variável correspondente na lista de argumentos. Veja este programinha de exemplo:

  #include <stdio.h>
  
  int main()
  {
  	int num= 10;
  	float fp= 3.28;
  	char ch= 'a';
  	char str[20]= "linuxdicas";
  	
  	printf("%d %f %c %s", num, fp, ch, str);
  	return 0;
  }

A ordem dos comandos de controle deve ser a mesma dos argumentos. No exemplo acima, na lista de argumentos, deve-se colocar a variável inteira primeiro, porque %d aparece primeiro; a variável ponto flutuante em segundo, porque %f aparece em segundo, e assim por diante.

Você pode usar também alguns caracteres especiais na string de controle. Estes caracteres auxiliam na formatação da impressão. Já vimos o caractere de controle \n, que "pula" uma linha. Vamos ver mais alguns:

Caractere Função
\n pular linha
\t tabulação
\b retrocesso
\r retorno do cursor
\" imprimir aspas
\\ imprimir barra
\0 nulo

Faça testes com os programas já vistos até aqui usando estes caracteres. Treine bastante...

Especificador de Precisão

Você deve ter visto que ao imprimir um float, imprime-se várias casas decimais, muitas vezes até desnecessárias. Você pode especificar o tamanho da casa decimal utilizando o especificador de precisão de printf(). Basta colocar, entre o % e o f, um ponto (.) e o número de casas. Assim:

  float fp= 3.15;
  printf("%.2f", fp);

Neste exemplo, será impresso 3.15, e não 3.150000, porque você especificou que o printf() deveria imprimir 2 casas decimais de precisão.

Este mesmo especificador pode ser usado em outros tipos de dados. Em uma string, determina-se o comprimento mínimo e máximo do campo a ser impresso:

  char str[20]= "linuxdicas";
  printf("%3.5s", str);

Neste exemplo será impressa um string de no mínimo 3 e no máximo 5 caracteres.

Em inteiros, o especificador determina o número mínimo de dígitos, completando com zeros à esquerda quando necessário:

  int num= 800;
  printf("%.8d", num);

No exemplo acima, será impresso 00000800 (8 dígitos).

Especificador de Largura Mínima

De forma semelhante ao especificador de precisão, o especificador de largura mínima adiciona espaços ao campo para assegurar que atinja o comprimento mínimo. Se a largura especificada for menor que o tamanho do número, nada será feito (o número será impresso normalmente).

Para especificar a largura do campo de impressão, basta colocar um número entre o % e o comando de formato. Exemplo:

  int x, y, z;
  x= 20;
  y= 200;
  z= 2000;
  printf("%5d %5d %5d\n", x, y, z);
  printf("%5d %5d %5d\n", y, z, x);

Imprimiria:

     20   200  2000
    200  2000    20

Como você pode ver, a saída é toda alinhada, ou justificada, à direita. Você pode justificar à esquerda colocando um sinal de menos (-) antes do número que especifica a largura do campo.

  printf("%-5d", num);

Isto imprimiria um inteiro, com 5 dígitos no mínimo e justificado à esquerda.

Você está INTIMADO a refazer os exemplos das aulas anteriores, usando os modificadores e códigos de formatação vistos nesta aula. Só assim, na prática, você aprenderá.

5.3. Lendo com scanf()

De modo semelhante a printf(), a função scanf() é a função genérica de leitura em C, podendo ler praticamente qualquer tipo de dados primitivo. Sua sintaxe é parecida com printf(), onde há uma string de controle e uma lista de argumentos (variáveis). Uma diferença importante é que scanf() recebe o endereço das variáveis nos argumentos, e não o valor, como em printf(). Vamos ver um exemplo:

  int num;
  scanf("%d",&num);

Percebeu a diferença? Aqui a função scanf() está lendo um inteiro do teclado e armazenando em uma variável inteira num. Porque esse & antes de num? Ele especifica que está sendo passado o endereço da variável para a função. Essa é uma forma de passagem de parâmetros por referência, e veremos com detalhes na aula de funções. Nesta aula, basta você saber que esse & é necessário antes das variáveis na qual scanf() armazenará o valor lido.

Os comandos de controle são praticamente os mesmos de printf():

Comando Função
%c lê UM caractere
%d lê um inteiro com sinal
%ld lê um inteiro longo com sinal
%u lê um inteiro sem sinal
%lu lê um inteiro longo sem sinal
%x lê um número hexadecimal
%lx lê um número hexadecimal longo
%o lê um número octal
%lo lê um número octal longo
%f, %g ou %e lê um ponto flutuante
%p lê um ponteiro
%s lê uma string
%n atribui o número de caracteres lidos até este ponto à variável correspondente
%[] busca por um conjunto de caracteres

Pode-se usar os caracteres especiais de controle (\n, \t, etc) para auxiliar na formatação, da mesma forma que printf().

Agora, vários exemplos. Supondo que a variável p é do tipo correspondente em cada caso:

Lendo um caractere:

  scanf("%c", &p);

Lendo um inteiro com sinal:

  scanf("%d", &p);

Lendo um inteiro sem sinal:

  scanf("%u", &p);

Lendo um hexadecimal:

  scanf("%x", &p);

Lendo um octal:

  scanf("%o", &p);

Lendo um número em ponto flutuante:

  scanf("%f", &p);
  	ou
  scanf("%e", &p);
  	ou
  scanf("%g", &p);

Lendo um ponteiro:

  scanf("%p", &p);

Lendo uma string:

  char p[20];
  scanf("%s", p);

Você deve estar pensando: pô, o cara esqueceu de digitar o & no último exemplo (strings)... A leitura de strings é uma excessão onde não se deve colocar o & antes da variável. Isto porque quando se declara uma string (um vetor de caracteres) a variável sozinha já é um ponteiro para o início da string na memória (isto é, já é um endereço, não precisando colocar o & antes). Calma, veremos nesta aula mesmo que scanf() não é a função ideal para a leitura de strings, e aprenderemos que fgets() é uma boa escolha. Veremos mais também sobre endereços na aula de ponteiros.

O comando de controle %n faz o seguinte: ele atribui à variável associada o número de caracteres lidos até aquele ponto.

  scanf("%d%n", &p, &num);

Suponhamos que você digite 1234. A variável p armazenará 1234 e a variável num armazenará 4 (1234 possui 4 caracteres).

Scanset

Um scanset funciona como um leitor seletivo de strings: ele só lê os caracteres que estão definidos no scanset e, quando encontra um caractere que não está definido neste conjunto, ele pára a leitura ali, ignorando os caracteres restantes.

Como um exemplo vale mais que mil palavras, vejam este:

  #include <stdio.h>
  
  /* Teste do scanset */
  
  int main()
  {
  	int num;
  	char s1[20], s2[20];
  	
  	scanf("%d%[aeiou]%s", &num, s1, s2);
  	printf("%d %s %s", num, s1, s2);
  	return 0;
  }

Compile e execute esse programa. Digite como entrada 915eiammst.

A saída será:

  915 eia mmst

Perceba que a variável s1 só armazenou os caracteres que estavam definidos no scanset. Os restantes (mmst) foram atribuídos a s2.

Existe a versão "negada" do scanset, onde tudo pode ser lido, menos o que está no conjunto. Basta começar a lista com um ^:

  scanf("%[^A-Z]", str);

Na linha acima, matamos três coelhos com uma cajadada só:

1) Neste exemplo, todos os caracteres são aceitos, menos os maiúsculos (A-Z);

2) Também podemos ver que um scanset aceita uma faixa de caracteres (A-Z, a-z, 0-9, etc);

3) De quebra, podemos sacar que, como a linguagem C, um scanset diferencia MAIÚSCULAS de minúsculas.

Modificadores de Formato

scanf() também possui modificadores de formato, como em printf(). No caso de ler uma string, podemos fazer que uma variável leia somente até um determinado número de caracteres. Isto ajuda evitar um vazamento de memória, que poderia comprometer a segurança do seu programa.

Para especificar o tamanho do campo a ser lido, basta colocar o número entre o % e o código de controle. Por exemplo: suponhamos que no trecho abaixo

  char str[15];
  scanf("%s", str);

o usuário digite otorrinolaringologista. Isso fatalmente causaria um erro.

Utilizando o modificador de formato:

  char str[15];
  scanf("%14s", str);

Mesmo que o usuário digite otorrinolaringologista, só seriam armazenados os 14 primeiros caracteres, ou seja, otorrinolaring. Os outros caracteres ficariam na memória, e se houver outra chamada a scanf(), os caracteres que não foram lidos ("ologista") serão atribuídos a variável.

Controlando a entrada

Você pode também especificar que determinado campo será lido, mas não armazenado. Basta colocar um * entre o % e o código do formato. Por exemplo:

  scanf("%c%*c%c", &ch1, &ch2);

Se você digitar a-c, o hífen (-) será lido, mas não será atribuído a nenhuma variável.

Um problema com scanf()

Agora pode ser que não seja notado, mas scanf(), em alguns compiladores ou sistemas, pode deixar algum "vestígio" no buffer de entrada, o que atrapalharia uma eventual próxima leitura. Isto é notado principalmente dentro de loops, lendo várias vezes seguidas. Lembra que getchar() sofria do mesmo mal? Então, o remédio é o mesmo... Basta colocar um getchar() solitário após a leitura com scanf() que o buffer é limpo. Assim:

  scanf("%d", &num);
  getchar();           /* o faxineiro getchar() limpa a sujeira do scanf() */

Ufa!! Chega de scanf()... Vamos ver agora as funções de leitura de strings.

5.4. Lendo e escrevendo strings

Nós vimos que scanf() é uma função para leitura de praticamente todos os tipos primitivos, até de strings. Mas existem funções de leitura e escrita de strings que facilitam a vida do programador e tornam o código mais seguro. Veremos a leitura com gets(), e porque não usá-la; leitura com fgets(), e porque usá-la; e a escrita com puts(),

Lendo com gets() e fgets()

Ler uma string com gets é muito fácil:


  char str[20];
  gets(str);

Como você viu, a função gets tem um único argumento, a variável string. Mas essa facilidade tem um preço. gets() é considerada uma função insegura, pois não controla se o usuário vai digitar além do que cabe na string. No exemplo acima, se o usuário digitar uma string de mais de 20 caracteres, a leitura é feita, mas ocorre um vazamento de memória, que pode ter graves consequências. O próprio compilador gcc "desencoraja" o uso da função gets(), com a seguinte mensagem:

  the 'gets' function is dangerous and should not be used.

Em contrapartida, temos a "salvadora da pátria": a função fgets(). Você, que já conhece C, me diria: "Mas essa função não serve para ler de um arquivo?". Na teoria sim. Mas em C, temos 3 arquivos especiais que são abertos quando um programa em C é executado: stdin, stdout e stderr.

No caso da função fgets(), é a stdin que nos interessa. Esse arquivo especial refere-se a entrada padrão (o teclado). Portanto, é esse o "arquivo" que fgets() usará para ler strings do teclado.

A forma geral da função fgets() é a seguinte:

  fgets(char *str, int tamanho, FILE *fp);

Portanto, para poder ler uma string fazemos assim:

  #include <stdio.h>
  
  int main()
  {
  	char str[20];
  	
  	fgets(str, 19, stdin); 
  	puts(str);
  	return 0;
  }

Neste caso, se você digitar otorrinolaringologista, fgets() armazenará somente otorrinolaringolog, ignorando o resto. Isto porque você especificou que fgets() só poderia ler uma string de no máximo 19 caracteres. Viu a vantagem? Tente fazer você mesmo e teste com várias entradas.

Escrevendo com puts()

Escrever strings com puts é muito fácil... puts() só possui um argumento, a própria string:

  char str[20]= "linuxdicas";
  puts(str);

Simples, fácil e rápido...

OBS: uma string em C é um vetor (ou matriz) de caracteres. Nós estudaremos sobre matrizes e vetores em breve, além de estudar as funções de manipulação de strings.

Nesta aula você aprendeu:

  • como ler caracteres com getchar() e escrever caracteres com putchar();
  • as vantagens e desvantagens de getchar() e putchar();
  • como escrever com printf(), suas vantagens e desvantagens;
  • como ler com scanf(), suas vantagens e desvantagens;
  • como ler strings com gets() e fgets();
  • porque não usar gets();
  • porque usar fgets();
  • como escrever strings com puts();

    Na próxima aula veremos as estruturas de decisão de C (if..else, switch, etc);


    === Exercícios ===

    1) Escreva um programa que leia 3 números inteiros, calcule a média aritmética e escreva a resposta para o usuário.

    2) Faça um programa que, dado o valor de uma compra, calcule o ICMS a ser pago; considere uma taxa de 12%.

    3) Dado um número com 3 algarismos, faça um programa para inverter a ordem de seus algarismos.

    4) Dado um valor em anos, faça um programa que converta para segundos.


    Powered by txt2tags

  

[ Voltar Curso C | Índice de Seções ]


Copyright © 2002 - 2007 LinuxDicas - Todos Os Direitos Reservados.
LinuxDicas: lucas.martinez @linuxdicas.com.br
Web site engine's code is Copyright © 2003 by PHP-Nuke. All Rights Reserved. PHP-Nuke is Free Software released under the GNU/GPL license.
Tempo para gerar esta página: 0.047 segundos.