domingo, 25 de outubro de 2009

Lendo valores digitados (scanf)

No final do post sobre o comando printf, eu deixei um desafio sobre o que fazia o seguinte comando:


printf("O resultado da soma de %03d + %3d eh igual a %d.\n",num1, num2, resultado);



Conseguiu descobrir? É muito simples! O 1º especificador de formato/largura de campo exibe um inteiro completando-o com zeros à esquerda para que ele tenha 3 caracteres, e o 2º exibe um inteiro completando com espaços para que ele tenha também 3 caracteres. São quase iguais; a diferença é que um completa com zeros e o outro com espaços.

Sei que você já tinha descoberto isso! Só coloquei aqui para confirmar.

A partir de agora, quando eu fizer algum desafio, só responderei nos comentários. Quem quiser confirmar as respostas pode perguntar nos comentários.

Vamos ao assunto de hoje.


Criando um programa interativo
Neste mesmo post sobre o comando printf, falei sobre a capacidade de imprimir valores desconhecidos; isto é, desconhecidos na hora em que se está escrevendo o código fonte do programa, mas que serão conhecidos quando o programa for executado. Usando os devidos termos técnicos, dados desconhecidos em tempo de compilação.
Esta é a base da interatividade; a capacidade do usuário interagir com o computador (através de um programa), fornecendo dados para que ele execute uma tarefa.
O comando usado em C para permitir esta entrada de dados é o scanf. Na verdade existem outros, mas este é o preferido da maioria dos programadores (eu, inclusive), pois permite a entrada formatada.

Formatada? Eu já ouvi esta palavra...
Se você está tentando lembrar de onde 'ouviu' esta palavra, dá uma olhada no post do qual falei no começo deste (sobre o printf).
O scanf é quase o inverso do printf. O printf imprime a saída formatada e o scanf permite a entrada formatada. Além disto, os especificadores de formato dos 2 são os mesmos.
Vamos ver isto na prática?
Você já sabe o caminho, correto? Esta é a última vez que falo isto (para ganharmos tempo, e economizar meus dedos, evitando digitar sempre a mesma coisa).
Abra o Dev C++, crie um novo Arquivo fonte e copie o código abaixo.




//Exemplo de scanf
#include <stdio.h>
#include "stdlib.h"


int main( )
{
float num1, num2, resultado;


printf("Digite o numero que sera dividido(dividendo)\n");
scanf("%f",&num1);
printf("Digite o numero que dividira o anterior (divisor), nao pode ser zero\n");
scanf("%f",&num2);
resultado = num1 / num2;
printf("O resultado da divisao de %.2f por %.2f eh igual a %.2f.\n",num1, num2, resultado);
system ("pause");
}


Compile e execute.



Esta é a versão interativa do 2º código que usei como exemplo para mostrar os parametros do printf.
Vamos a análise dele.
Na linha 7, declaramos todas as variáveis com o tipo float, o que significa que o usuário pode digitar números com casas decimais.
Nas linhas 9 e 11, informamos ao usuário o que ele deve fazer para entrar os dados que o programa precisa para executar uma divisão.
Na linha 13, o resultado da divisão é armazenado na variável resultado.
Na linha 14, são impressos os números e o resultado da operação.
Acredito, que você já sabe o que fazem as linhas 1, 2, 3, 5, 6, 15 e 16! Se não sabe leia a série de posts sobre código fonte (começa aqui).
A novidade deste código está nas linhas 10 e 12. Que utilizam o comando scanf e com os seus devidos parametros.
Repare o uso do "%f", que indica que desejamos ler valores com casas decimais. Lembra em alguma coisa o comando printf? O scanf usa os mesmos especificadores de formato do printf. Especificadores de formato e não de largura de campo. Tentar usar um especificador de largura de campo junto com o comando scanf retorna valores 'malucos'. (Duvida? Faça alguns testes e veja por si mesmo).
Depois da vírgula, temos a variável que vai armazenar o valor digitado.
E que & é este na frente do nome da variável?

Alterando o conteúdo de uma variável
Diferente do printf, o scanf precisa alterar o conteúdo da variável que é 'passada' para ele.
Para fazer esta alteração, ele precisa saber (além do nome) do endereço (na verdade, sabendo o endereço, o nome é irrelevante).
Este & na frente do nome da variável, significa que estamos passando o endereço da variável para o comando scanf. O nome técnico disto é passagem por referência, que como a maioria das coisas mais complicadas que falo aqui, veremos depois (rsrsrs), quando virmos funções; embora não tenha muito mais o que falar sobre isto. Entendeu o porquê do &? Então vamos prosseguir.

Lendo 2 valores de uma vez
O printf pode imprimir várias variáveis, que são passadas como parametro, num mesmo comando. E o scanf? Pode ler mais de uma variável por vez?
A resposta é SIM. Observe o comando abaixo:

scanf("%f %f", &num1, &num2);

Ele lê 2 valores digitados e armazena nas variáveis do tipo float num1 e num2.
A leitura é feita assim: Digite o 1º valor e tecle espaço ou enter, depois digite o 2º valor e encerre a entrada obrigatóriamente com enter. Se eu não digitar enter no final? O que acontece?
Teste e descubra.

Por hora, isto é o que você precisa saber sobre o scanf.
Faça seus testes. Quer um desafio?

Faça um programa em C que peça ao usuário que digite uma distância em quilometros e a quantidade de litros de combustível gastos por um carro para percorrer esta distância, e calcule quantos litros/Km este carro faz.

Quem conseguir pode postar nos comentários.

Abraços e até o próximo post.

3 comentários:

  1. #include

    main ()
    {
    float km, litros, result;

    printf ("Digite a distancia em quilometros e a quantiadade de litros de combustivel gastos, respectivamente: ");
    scanf ("%f%f", &km, &litros);

    result = litros/km;

    printf ("\nSeu carro gasta %.2f litro/s por quilometro.", result);

    getch ();
    }

    Ao invés de system ("pause"); usei o getch (); eu percebi que ele tem o mesmo efeito e não coloca mensagem na tela.
    Bom, tentei usar os exemplos que você deu.
    Espero que comentem para o meu aperfeiçoamento.

    Abraços.

    ResponderExcluir
  2. Faltou o "stdio.h" no meu código, descobri que quando vou publicar o comentário, o site não aceita o sinal de "Maior que" e "Menor que", juntamente com tudo que estiver entre eles, por isso não saiu no meu código.

    ResponderExcluir
  3. olá Edson, bom dia
    Meu nome é Alex e sou de Guarapari.Tenho uma dúvida em c++ builder 6:
    tenho programado o pic 16f877a para leituras analógicas, até ai tudo bem, porém, quando lanço o programa para visualiza-lo no C++ builder 6 as leituras entre os canais 1 e 2 são simultâneas no mesmo label e não consigo separa-las para leituras em label diferentes (há um interva-lo e o label lê o resultado da entrada analógica 1 e em seguida o da entrada 2, se eu coloco dois labels fica oscilando entre um e o outro, ora lê o valor do canal 1 e no mesmo label lê o valor do canal 2), preciso fazer com que cada label leia o valor correspondente a sua entrada analógica, pode me ajudar?

    veja os códigos:
    Aqui em C:

    setup_adc_ports(RA0_RA1_RA3_ANALOG);
    setup_adc(ADC_CLOCK_INTERNAL);


    set_adc_channel(0);
    set_adc_channel(1);

    while(true) //Loop infinito.

    {
    set_adc_channel(0);
    delay_ms(20);
    read_adc(adc_read_only);
    var_1 = Read_ADC();
    Temperatura_EvaPrincipal = 5* var_1*100/1023;
    printf("%04Lu\r\n",var_1); //Envia para a porta serial.
    delay_ms(100);

    {
    set_adc_channel(1);
    delay_ms(20);
    read_adc(adc_read_only);
    var_2 = Read_ADC();
    Temperatura_EvaAux = 5* var_2*100/1023;
    printf("%04Lu\r\n",var_2); //Envia para a porta serial.
    delay_ms(100);


    //------------

    Aqui em c++ buider 6

    void __fastcall TMultLinha::Execute()
    {
    while(true) //Loop infinito
    {
    {
    static DWORD BytesRecebidos;
    static String StrLumi;
    static unsigned int cont=0;
    FreeOnTerminate = true; //O objeto é destruído automaticamente quando a Thread terminar.
    while(!Terminated) //loop infinito. Vida do programa.
    {
    if(CONECTADO == true) //Se está conectado.
    {

    ftStatus = FT_Read(ftHandle,RxBuffer,BUF_MAX,&BytesRecebidos);

    if(ftStatus == FT_OK)
    {
    cont=0;

    if(BytesRecebidos > 0)
    {
    RxBuffer[BytesRecebidos] = '\0'; //Finaliza string.

    StrLumi += RxBuffer;

    //--------------------------------------------------------------------------------------
    while(cont < BytesRecebidos) //Enquanto houver bytes a serem lidos.
    {

    if( (RxBuffer[cont] == '\n') || (RxBuffer[cont] == '\0')) //Se achou o final da string.
    {
    strcpy(EvaAuxBuffer,StrLumi.c_str()); // Canal Analógico (AN0).
    EvaAuxBuffer[StrLumi.Length()-2] = '\0'; //Remove os caracteres '\r\n'.
    //-----------------------------------------------------------------------------------------------
    if( (RxBuffer[cont] == '\n') || (RxBuffer[cont] == '\0')) //Se achou o final da string.
    {
    strcpy(EvaAuxBuffer2,StrLumi.c_str()); // Canal Analógico (AN1).
    EvaAuxBuffer2[StrLumi.Length()-2] = '\0'; //Remove os caracteres '\r\n'.

    Synchronize(MostraString);

    StrLumi="\0"; //Limpa string.

    }
    }
    cont++;

    }
    }
    }
    }else{//Se não conectado.
    Sleep (1);//Para não consumir processo da CPU.
    }

    ResponderExcluir