quarta-feira, 27 de fevereiro de 2008

Verdadeiro e falso

A linguagem c não possui um tipo de dado booleano, então de que forma ele trada o que é verdadeiro e falso?
Sabe-se que para a linguagem C tudo o que tiver valor 0 é falso e tudo o que for diferente de 0 é verdadeiro.
Para fins de demonstração recorrerei a dois exemplos.
O primeiro exemplo apresenta o valor numérico de duas expressões lógicas, uma verdadeira e outra falsa.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char sexo = 'F';
007:    
008:    printf("sexo igual a F: %d\n", sexo == 'F');
009:    printf("sexo igual a M: %d\n", sexo == 'M');
010:    system("PAUSE");
011:    return 0;
012:  }


A saída produzida pelo programa deve ser


sexo igual a F: 1
sexo igual a M: 0


Como o sexo vale F, quando é feita a relação entre sexo e M, o resultado é falso(0). Quando a relação é estabelecida entre sexo e F, o resultado é verdadeiro (diferente de 0, nesse caso 1).
O segundo exemplo é para provar que valores diferentes de zero são considerados verdadeiros.
A estrutura de decisão if (se) avalia uma variável ou expressão e decide se executará seu bloco verdade ou seu bloco falsidade.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int valor;
008:    
009:    printf("Digite um valor inteiro: ");
010:    fflush(stdin);scanf("%d", &valor);
011:    if(valor)
012:    {
013:      printf("Valor diferente de zero: %d\n", valor);
014:    }
015:    else
016:    {
017:      printf("Valor igual a zero: %d\n", valor);
018:    }
019:    system("PAUSE");
020:    return 0;
021:  }


Na execução do programa, se você digitar 0, a saída do programa é


Valor igual a zero: 0


ou seja a instrução if (valor), pode ser traduzida para if(0), ou ainda, em português estruturado se falso então. Isso sempre executara o bloco else do if.
Quando você digita um valor diferente de zero, suponha 5, a saída esperada é


Valor diferente de zero: 5


então a instrução if (valor), é equivalente a if (5), que equivale a se verdade então.
Espero que as demonstrações sejam suficientes para você guardar que 0 é falso e diferente de zero é verdadeiro. :-D

Operadores relacionais

Os operadores relacionais estabelecem uma relação (Não poderia ser mais óbvio!) entre seus operandos.
Essa relação pode ser de:
  1. (==) igualdade
  2. (!=) diferença
  3. (>) maior que
  4. (<) menor que
  5. (>=) maior ou igual a
  6. (<=) menor ou igual a

É interessante saber que o resultado de uma expressão relacional é sempre lógico, ou seja, retorna verdadeiro ou falso.
Analisando a equação relacional


X == 7;


concluímos que o resultado será verdadeiro para X igual a 7 e falso para X diferente de 7.
Algumas vezes a análise não é tão simples assim. Por exemplo:


X > 7;


O resultado será verdadeiro para qualquer valor real maior ou igual a 7.
Quando o resultado será falso? Alguns respondem, de primeira, quando X for menor que 7 e esquecem que quando X é igual a 7 o resultado da expressão também é falso.
A resposta correta é quando X for menor ou igual a 7.
Sempre que deparar com uma relação, tente identificar os conjuntos de valores que a tornam verdadeira e falsa, assim você terá domínio maior sobre o problema.

segunda-feira, 25 de fevereiro de 2008

O scanf engana

Quando falei sobre a função scanf, chamei a atenção para a limpeza do buffer do teclado.
Naquele momento enfatizei que limpar o buffer do teclado evitaria algumas dores de cabeça.
Execute o código abaixo e verifique o seu funcionamento.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char chr1, chr2;
007:    
008:    printf("Digite o primeiro caractere: ");
009:    scanf("%c", &chr1
010:    printf("Digite o segundo caractere: ");
011:    scanf("%c", &chr2);
012:    printf("Primeiro caractere %c\nSegundo caractere: %c\n", chr1, chr2);
013:    system("PAUSE");
014:    return 0;
015:  }


Não fique nervoso tentando digitar o segundo caractere. Esse problema é bastante comum nos códigos de programadores pouco experientes. Tente limpar o buffer do teclado, utilizando a instrução fflush(stdin) antes de cada scanf. Você verá que agora o segundo caractere é lido.
Por que isso ocorre? Imagine o buffer do teclado como um arquivo seqüencial, onde o scanf retira os dados.
Para o exemplo anterior, na linha 9, o scanf espera que você digite um byte (estamos lendo variáveis do tipo char). O que você faz? Digita o caractere e em seguida o enter. Supondo que você digitou o caractere V, o buffer do teclado fica:


V\n


O \n representa o enter.
Após a execução da linha 9, o caractere V é armazenado na variável chr1, deixando o \n no buffer do teclado. Adivinhe que receberá o \n? Correto, a variável chr2. Por esse motivo ela não é lida!
Quando você usa a instrução fflush(stdin), e limpa o buffer do teclado, o \n sai do buffer, deixando ele limpo para a próxima leitura.

Operadores aritméticos

A linguagem C disponibiliza cinco operadores aritméticos binários.
  1. (+) soma
  2. (-) subtração
  3. (*) multiplicação
  4. (/) divisão
  5. (%) resto de uma divisão entre inteiros

Os operadores binários recebem esse nome porque necessitam de dois operandos para que a operação exista.


x = a + b;


Nem todas as operações são binárias. A linguagem C disponibiliza a operação menos unário, a qual necessita somente de um operando para existir.


x = -a;


O menos unário é equivalente a multiplicação por -1. Estere aí! Na multiplicação por -1 não estamos empregando o menos unário no operando 1. Olhe o código abaixo e conclua!


x = -1 * a;


Todas as operações são aplicadas a números inteiros e de ponto flutuante, com exeção do resto.
O conceito de resto de uma divisão só existe quando falamos em números inteiros, portanto o operador % exige que seus operandos sejam do tipo int ou char.
De todas as operações, a mais ingrata é a divisão.
Você é capaz de responder o que será impresso pelo seguinte código?


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int a = 5, b = 2;
007:    float c;
008:    c = a/b;
009:    printf("O resultado da divisao e: %f", c);
010:    system("PAUSE");
011:    return 0;
012:  }


Se você pensou em 2.5, você pensou errado! O resultado é 2.0. Na linguagem C, a divisão entre dois inteiros, resulta em resultado inteiro, portando o resultado da divisão entre cinco e dois, é dois.
Se a sua intensão é apresentar o resultado real da divisão então, ao menos um dos operados deverá ser de ponto flutuante. Para isso recorro a utilização do cast que faz a conversão momentânea do dado.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int a = 5, b = 2;
007:    float c;
008:    c = (float)a/b;
009:    printf("O resultado da divisao e: %f", c);
010:    system("PAUSE");
011:    return 0;
012:  }


Você pode ver a utilização do cast (float) na linha 8. Isso transforma o dado da variável a em float então este dado é dividido por 2. O resultado dessa operação é o 2.5.
Em resumo, os operadores aritméticos são tranqüilos de usar. O cuidado maior está sempre na divisão.

sexta-feira, 22 de fevereiro de 2008

lendo dados - a função scanf

Agora que você sabe como funciona o operador de endereço &, posso apresentar a você a função scanf (leia-se scanEFE).
Essa função, como a printf, está localizada na biblioteca stdio.h e serve como entrada de dados em seu programa. Tudo aquilo que você digita no teclado será lido por essa função.
É claro que para o scanf você deverá informar duas coisas:
  1. Em qual formato o dado será lido?
  2. Onde ele será armazenado?

Para informar o formato do dado para o scanf é necessário recorrer a tabela abaixo:
CódigoFormatação
%cLê um caractere
%dLê um inteiro positivo ou negativo (base decimal)
%iLê um inteiro positivo ou negativo (base decimal)
%eLê um número de ponto flutuante em notação científica
%fLê um número de ponto flutuante
%gLê um número de ponto flutuante podendo ser expressa em notação científica
%oLê um número em octal
%sLê uma cadeia de caracteres (string)
%uLê um inteiro sem sinal
%xLê um número hexadecimal
%nRecebe um valor inteiro correspondente ao número de caracteres lidos até então
%[]Busca por um conjunto de caracteres

A resposta genérica para a segunda pergunta é a memória. Devemos especificar para o scanf qual o endereço de memória ele deve guardar o dado inserido. Para essa operação utiliza-se o operador de endereço &.
A forma geral do scanf é:


scanf("código de formatação", lista de endereços);


Para ler duas variáveis, sexo e anoNascimento podemos fazer como no programa abaixo.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char sexo;
007:    int anoNascimento;
008:    printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\n");
009:    scanf("%c",&sexo);
010:    printf("Digite o ano de nascimento: ");
011:    scanf("%d",&anoNascimento);
012:    system("PAUSE");
013:    return 0;
014:  }


Note que nas linhas 9 e 11 o código de formatação indica somente o tipo de dado a ser lido.
O scanf permite ler mais de uma variável na mesma instrução. Adaptando o programa acima para ler em apenas uma instrução fica da seguinte forma:


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char sexo;
007:    int anoNascimento;
008:    printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\nEm seguida digite o ano de nascimento.");
009:    scanf("%c%d",&sexo, &anoNascimento);
010:    system("PAUSE");
011:    return 0;
012:  }


Particularmente não gosto dessa segunda opção porque não permite a limpeza do buffer do teclado entre uma leitura e outra. A limpeza é importante pois garante que nenhuma sujeira presente no buffer contaminará suas variáveis.
Para fazer a limpeza do buffer basta inserir a instrução


fflush(stdin);


antes de cada scanf.
Veja o primeiro programa escrito de uma forma mais segura.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char sexo;
007:    int anoNascimento;
008:    printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\n");
009:    fflush(stdin);
010:    scanf("%c",&sexo);
011:    printf("Digite o ano de nascimento: ");
012:    fflush(stdin);
013:    scanf("%d",&anoNascimento);
014:    system("PAUSE");
015:    return 0;
016:  }


Agora sim, ler dados ficou ainda mais fácil!

quinta-feira, 21 de fevereiro de 2008

Operador de endereço

Quando falei sobre criação e inicialização de variáveis, falei também que cada variável recebe uma casa, chamada de memória.
Como toda casa possui um endereço (Rua, número, bairro, cidade, estado, país, CEP), a memória possui um endereçamento, muito mais simplificado, composto por números.
Esses números indexam a memória byte-a-byte.
Vamos recorrer ao exemplo abaixo para compreender melhor:

Endereço204820492050
IdentificadorsexoanoNascimento
Valor'F'1982

O exemplo representa um fragmento de memória, na qual estão presentes duas variáveis identificadas por sexo e anoNascimento. Pelo número de bytes alocados para cada variável e, com o auxílio da tabela de limites mínimos de variáveis, pode-se concluir que sexo é do tipo char e anoNascimento é inteiro.
Quando pergunto qual o endereço de sexo, a resposta deve ser 2048. Quando pergunto qual o endereço de anoNascimento, a dúvida impera!
Alguns respondem 2049, outros 2050, um grupo isolado arrisca 2049 e 2050. A resposta correta é 2049. O endereço de uma variável que ocupa mais de um byte é o menor endereço do bloco de memória ocupado pela variável. O bloco ocupado por anoNascimento é 2049-2050, portanto o menor endereço desse bloco é 2049.
Na linguagem C a forma utilizada para descobrir o endereço de uma variável é por meio do operador &.
O programa abaixo ilustra como se utiliza o operador & para imprimir na tela o endereço de uma variável.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char sexo = 'F';
007:    int anoNascimento = 1982;
008:
009:    printf("O endereco de sexo e %p\n", &sexo);
010:    printf("O endereco de anoNascimento e %p\n", &anoNascimento);
011:    system("PAUSE");
012:    return 0;
013:  }


Com base no fragmento de memória apresentado anteriormente, a saída esperada para esse programa é:


O endereço de sexo e 2048
O endereço de anoNascimento e 2049


Você deve estar se perguntando... Quando usarei esse operador?
Primeiramente na função scanf, utilizada na leitura de dados do teclado, e mais a frente em passagem de parâmetros por referência (o que é feito na função scanf) e no uso de ponteiros.
A propósito, a passagem de parâmetro por referência é feita utilizando ponteiros. :D

segunda-feira, 18 de fevereiro de 2008

A função printf()

No post Meu primeiro programa em C, apresentei o uso da função printf em sua forma mais ordinária. Aquela em que a utilizamos para apresentar mensagens fixas, como a apresentada abaixo.


printf("Uma mensagem para voce!");


Nessa forma não existem códigos de formatação.
Os códigos mais básicos servem para controlar tabulações, quebras de linhas, impressão de aspas, etc..., e são iniciados pela barra invertida seguida de um caractere.
A tabela abaixo apresenta esses códigos.

CódigoSignificado
\nQuebra de linha (Pula para a próxima linha)
\rRetrocede o cursor para o início da linha
\tInsere uma tabulação no texto
\bRetrocede o cursor uma posição
\"Imprime a aspas
\\Imprime uma barra invertida

Existem códigos de formatação para a impressão de variáveis. Não seria ótimo apresentar um número no meio de uma mensagem, por exemplo:


O numero 2 e par.


O programa que gera essa saída pode ser dado por:


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int num = 2;
007:
008:    printf("O numero %d e par\n", num);
009:    system("PAUSE");
010:    return 0;
011:  }


Esse raciocínio é válido para todos os tipos de dados. A tabela abaixo apresenta o código de formatação e o formato impresso:

CódigoFormatação
%cCaractere
%dinteiros com sinais (base decimal)
%iinteiros com sinais (base decimal)
%eNotação científica (e minúsculo)
%Enotação científica (E maiúsculo)
%fponto flutuante
%gusa %f ou %e, o que for mais curto graficamente
%Gusa %f ou %E, o que for mais curto graficamente
%oimprime um número em base octal
%scadeia de caracteres (string)
%uinteiros sem sinal
%ximprime um número na base hexadecimal. As letras serão minúsculas.
%Ximprime um número na base hexadecimal. As letras serão maiúsculas.
%pApresenta endereço de memória.

Se você é um pouco perspicaz estará se perguntando como fazer para imprimir o sinal de %. Isso é fácil, basta duplicar o sinal de percentual (%%) no printf.
Se você acha que acabou, aguarde o post sobre a formatação de precisão e campos utilizando o printf.