terça-feira, 29 de maio de 2012

Vetores – Parte 1 – O que é um vetor?

Já imaginou fazer um programa que processe mil números inteiros? Que ainda necessite calcular a média desses números e apresentar quantos números estão acima dessa média?
Se você pensou em criar mil variáveis então sugiro repensar seus conceitos. :-P
A nossa velha linguagem C possui uma estrutura de dados chamada vetor, a qual agrupa um conjunto de variáveis, fazendo com que elas atendam por um único identificador. O que mantém a individualidade de cada uma dessas variáveis é o índice pelo qual elas respondem. Veja a figura abaixo:


O vetor identificado por vet contém dez elementos, os quais possuem um índice variando de 0 a 9. Cada posição do vetor se comporta de forma independente das demais, como se fosse uma variável isolada.
Se vet fosse um vetor de inteiros, sua declaração seria:

int vet[10];

Generalizando a criação do vetor temos:

tipo_de_dado identificador [capacidade];

Onde:
  • tipo_de_dado é qualquer tipo de dado possível para a linguagem C, seja ele básico, estendido ou definido pelo usuário;
  • Identificador é um identificador válido para a linguagem C;
  • capacidade é uma constante inteira definida pelo programador a qual define o número de elementos de um vetor.
Como o vetor é um tipo de dado estático, sua capacidade é atribuída pelo programador e sua alteração exige uma nova compilação do programa. Essa característica faz com que o vetor fique limitado aquele número de elementos.
Acho que está bom para esse primeiro papo né? Espero que aquela idéia triste de criar mil variáveis deva ter abandonado a sua cabeça. ;-)
A nossa próxima conversa será sobre a inicialização e acesso as posições do vetor. Fique a vontade em divulgar, comentar e sugerir....
Abraços.

segunda-feira, 1 de novembro de 2010

Outros operadores de atribuição.

Como assim? Existem mais operadores de atribuição além do =?
A linguagem C fornece mais cinco operadores de atribuição, além do tradicional =.
Vamos ao exemplo. Suponha que uma variável a é incrementada em 3 unidades, portanto, a linha de código que define esse incremento é


a = a + 3;


Essa linha pode ser substituída por


a += 3;

Ambas produzem o mesmo resultado, mas a escrita da segunda é facilitada, pois a utilização do valor da variável está implícita no operador de atribuição. Os programadores C utilizam largamente esses operadores de atribuição, os quais existem um para cada operação aritmética definida.
A tabela abaixo apresenta um resumo das expressões e os operadores aritméticos envolvidos.
OperadorExpressão originalExpressão equivalente
+=a = a + n;a += n;
-=a = a - n;a -= n;
*=a = a * n;a *= n;
/=a = a / n;a /= n;
%=a = a % n;a %= n;


Espero ter incrementado o vocabulário da linguagem C com esses novos operadores.

terça-feira, 26 de outubro de 2010

Pré ou pós? Quando usar?

No post anterior falei dos operadores de incremento e decremento. Em todos os exemplos, os operadores aplicados foram pós-fixados, ou seja, aparecem logo após a variável. Naqueles exemplos tanto faz a posição do operador porque o resultado obtido é sempre o mesmo.
Quando utilizamos os operadores de incremento e decremento dentro de comandos mais complexos existe a diferença entre o uso pré-fixado ou pós-fixado. Vejamos o código abaixo para o operador pós-fixado:

int a = 5, b;

b = a++;


Qual o valor das variáveis a e b?
O valor esperado para a é 6 e para b é 5.

Se utilizarmos o operador pré-fixado, conforme exemplo abaixo:

int a = 5, b;

b = ++a;


O valor esperado para ambas as variáveis é 6.
Notaram a diferença?
Quando o operador é pós-fixado, o valor da variável é utilizado no comando e após a conclusão desse comando o valor será atualizado. No primeiro exemplo, o comando é de atribuição, seguido da atualização da variável pelo operador de incremento, uma vez que ele é pós-fixado. Com isso o valor de a, que é cinco, é atribuído à variável b e então a variável a é atualizada.
Quando o operador é pré-fixado, primeiro a variável é atualizada para então utilizar o seu valor. No segundo exemplo percebemos que a variável a é atualizada para seis e então o comando de atribuição é executado, passando para a variável b o valor 6.
Esse comportamento é análogo para os operadores de decremento, só que diminuindo o valor em uma unidade ;)
Em linhas gerais:
Operador pré-fixado, atualiza (incrementa ou decrementa) e depois usa o valor.
Operador pós-fixado, usa o valor e depois atualiza (incrementa ou decrementa).
Espero que isso ajude vocês a compreender melhor esses operadores.

sexta-feira, 29 de maio de 2009

Operadores de incremento e decremento

Operadores de incremento e decremento

A linguagem C é cheia de atalhos para o programador.
Um dos atalhos mais utilizados é o operador de incremento (++). Esse operador é largamente utilizado no for.
Esse operador incrementa a variável em uma unidade.
Um exemplo prático pode ser visto logo abaixo:

int a;
a = 7;
a++;
printf("%d\n", a);

A saída produzida por esse programa é 8. Como esperado, o operador de incremento funciona como

a = a + 1;

incrementando a variável a.
Análogamente ao operador de incremento a linguagem C disponibiliza o operador de decremento --.
Aplicando o operador de decremento ao código de exemplo temos:

int a;
a = 7;
a--;
printf("%d\n", a);

Como é de se esperar a saída apresentada foi 6.
Esses operadores utilizados isoladamente não são complexos, mas quando utilizado dentro de expressões aritméticas tornam o código complexo.
Brevemente falaremos do uso dos operadores de incremento e decremento pré-fixado ou pós-fixado.

sábado, 9 de agosto de 2008

Do while

Do while

O do while é um laço de repetição que executa primeiro o bloco de comandos e depois testa a condição. Caso a condição seja verdadeira, o laço é executado novamente. Quando a condição é falsa, a execução do laço é terminada.
Essa característica de executar e depois testar, garante que o laço será executado ao menos uma vez, diferentemente do while, o qual não executa quando sua condição é falsa.
A validação de entrada é um exemplo pertinente para o uso do do while, uma vez que a leitura do dado deverá ser executada ao menos uma vez. Quando o dado não é consistente com o conjunto de dados esperados, uma nova leitura é solicitada.
Veja o exemplo abaixo:



001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char * argv[])
005:  {
006:    char sexo;
007:
008:    do
009:    {
010:      printf("Digite o sexo: ");
011:      fflush(stdin); scanf("%c", &sexo);
012:      if(sexo != 'M' && sexo != 'F')
013:      {
014:        printf("Digite M ou F\n");
015:      }
016:    }while(sexo != 'M' && sexo != 'F');
017:    system("PAUSE");
018:    return 0;
019:  }



Note que o código é feito para importunar o usuário de forma que ele digite M para masculino ou F para feminino. Em outras palavras, o programa ficará em loop até que M ou F seja digitado. Baseado nisso, posso afirmar que a condição de saída do laço é M ou F.
Com este post finalizei a trilogia de laços de repetição, o que não quer dizer que esgotei o assunto...

quinta-feira, 7 de agosto de 2008

While

Retomando o assunto Laços de Repetição, abordado em abril/2008, hoje vamos tratar do while.
A forma geral desse laço é:

while


while(condicao)
{
  comandos...
}


É importante saber que dentro do bloco de comandos do while é necessário tornar a condicao falsa. Caso isso não ocorra, o while entrará em loop infinito.

Vamos recorrer a um exemplo simples:
Suponha que uma cidade A possua 1.500.000 habitantes e taxa de crescimento anual de 1%. Suponha também que uma cidade B com 500.000 habitantes cresce anualmente a 3%. Você deseja saber em quantos anos, mantendo-se as taxas de crescimento, a população de B será maior que a população de A.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char * argv[])
005:  {
006:    int anos=0;
007:    float popA=1.5, popB = 0.5;
008:
009:    while(popA >= popB)
010:    {
011:      popA = 1.01 * popA;
012:      popB = 1.03 * popB;
013:      anos += 1;
014:    }
015:    printf(“Quantidade de anos necessaria: %d\n”, anos);
016:    system("PAUSE");
017:    return 0;
018:  }


O exemplo mostra que enquanto a condição for verdadeira, ou seja, a população de A for maior ou igual a B, os anos passam (linha 13), e a população cresce (linhas 11 e 12).
Os dados de população e taxa de crescimento possibilitam que em algum ano, a população da cidade B será maior que a de A.
Caso a taxa de crescimento de A fosse maior que a de B, nunca a condição de saída seria atingida.
Sempre que trabalhar com o while, verifique a condição e identifique quais linhas tornarão seu resultado falso e se isso acontecerá. Com essa verificação seu laço não entrará em loop infinito.
Agora farei algumas considerações com relação aos cálculos praticados nas linhas 11 e 12, os quais podem parecer obscuros a alguém.
A linha 11 poderia ser reescrita como:


popA = popA + 1.0/100 * popA;



Dividindo 1.0/100 temos:



popA = popA + 0.01 * popA;



Colocando popA em evidência temos:



popA = (1 + 0.01) * popA;



Efetuando a soma 1 + 0.01 fica:



popA = 1.01 * popA;



Bendita ou maldita matemática. :D

quarta-feira, 23 de abril de 2008

For

No tópico Laços de Repetição foram abordados de forma geral os três laços possíveis na linguagem C.
Esse tópico trata do laço for.
Como visto, a forma geral desse laço é:

for


for(variavel = valor_inicial; condicao_envolvendo_variavel; incremento/decremento de variavel)
{
  comandos...
}


Vamos vê-lo na prática:


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char * argv[])
005:  {
006:    int i;
007:
008:    for(i = 0; i < 10; i++)
009:    {
010:      printf("%d\n", i);
011:    }
012:    system("PAUSE");
013:    return 0;
014:  }


O exemplo, embora simples, ilustra que o início do for é bem definido, bem como seu fim. Note que a variável i inicia com 0 e termina com 10.
Quando estou em sala de aula sempre pergunto quantas vezes o for será executado. A resposta é 10 vezes, com i variando de 0 a 9 (i < 10).
Se não confia em mim, execute o código acima e verifique as impressões do valor de i. Deverá aparecer 0, 1, ..., 9.
Outra pergunta que costumo fazer é qual o valor de i após a execução do laço for, em outras palavras, se imprimisse o valor de i na linha 012, o que seria impresso? A resposta correta é 10, lembre-se que existe uma condição para o for ser abandonado (i < 10). Quando i valer 10, o laço termina a sua execução.
Agora vamos ao exemplo prático. Vamos calcular o fatorial de um número inteiro.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int fat = 1, n, i;
007:
008:    printf("Digite o numero: ");
009:    fflush(stdin); scanf("%d", &n);
010:
011:    if (n < 0)
012:    {
013:      printf("Nao existe fatorial de numero negativo.\n");
014:    }
015:    else
016:    {
017:        for(i = n; i > 1; i--)
018:        {
019:            fat *= i;
020:        }
021:        printf("%d! = %d\n", n, fat);
022:    }
023:    system("PAUSE");
024:    return 0;
025:  }


Verifique o início e o fim do laço, novamente bem definidos! Inicia em n e termina em 1.
A linguagem C permite que você altere, dentro do laço, os valores da variável de controle (i). Essa não é uma prática recomendável porque esse laço perde sua característica de executar um número determinado de vezes. Se você alterar os valores da variável de controle, não poderá garantir quantas vezes o laço será executado.

Laços de repetição

Os laços de repetição são ferramentas poderosas para o controle do fluxo de execução do programa. Eles permitem que um determinado trecho de código seja executado até que uma condição específica seja satisfeita.
A linguagem C possui três tipos de laço de repetição, a saber, o for (para), o while (enquanto) e o do while (faça enquanto).
O for deve ser utilizado quando você sabe o número de vezes em que o laço será executado. Por exemplo, o cálculo do fatorial de n, no qual sabe-se de antemão que o laço será executado n-1-vezes.
O while e o do while devem ser empregados quando não sabemos o número de vezes em que o laço será executado, por exemplo, quando pretende-se saber em quantos anos a população da cidade A será maior que a população da cidade B.
Existe uma particularidade entre o while e o do while. O bloco while pode nunca ser executado, caso a condição seja falsa logo na primeira tentativa. O do while executa o bloco e depois verifica a condição, portanto, ele será executado ao menos uma vez.
A forma geral de cada um dos laços é apresentada a seguir:

for


for(variavel = valor_inicial; condicao_envolvendo_variavel; incremento/decremento de variavel)
{
  comandos...
}



while


while(condicao)
{
  comandos...
  /*Não esqueça de que os comandos devem, de alguma forma, alterar condicao*/
}



do while


do
{
  comandos...
  /*Não esqueça de que os comandos devem, de alguma forma, alterar condicao*/
} while(condicao);



Nas estruturas while e o do while você deve alterar a condição, dentro do bloco, para que de alguma forma o laço tenha fim. Se isso não ocorrer, o programa entrará no chamado loop infinito.
Seu poder sobre o destino dos dados estão aumentando. Use-o com cautela.

terça-feira, 22 de abril de 2008

Está indeciso?

Esse não é um tópico de auto-ajuda e muito menos de auto-conhecimento. :-)
A intenção aqui é mostrar que quando possuímos várias decisões, podemos utilizar um comando especial, chamado de switch.
Esse comando avalia uma variável e toma uma decisão de acordo com seu valor.
Um exemplo vale mais que mil palavras. Suponha que você deve construir uma pequena calculadora de quatro operações básicas. É natural que sua calculadora tenha uma variável para armazenar qual operação ela deverá fazer. Avaliando essa variável ('+', '-', '*', '/') você procederá com a operação.
Você poderá fazer da seguinte forma:


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    char op;
007:    int v1, v2;
008:
009:    printf("Digite a operacao: ");
010:    fflush(stdin);scanf("%c", &op);
011:    printf("Digite o primeiro valor: ");
012:    fflush(stdin);scanf("%d", &v1);
013:    printf("Digite o segundo valor: ");
014:    fflush(stdin);scanf("%d", &v2);
015:    if(op == '+')
016:    {
017:      printf("Soma: %d\n", v1 + v2);
018:    }
019:    else if(op == '-')
020:    {
021:      printf("Subtracao: %d\n", v1 - v2);
022:    }
023:    else if(op == '*')
024:    {
025:      printf("Multiplicacao: %d\n", v1 * v2);
026:    }
027:    else if(op == '/')
028:    {
029:      if (v2 != 0)
030:      {
031:        printf("Divisao: %d\n", v1 / v2);
032:      }
033:      else
034:      {
035:        printf("Denominador igual a zero.\n");
036:      }
037:    }
038:    else
039:    {
040:      printf("Operacao invalida\n.");
041:    }
042:    system("PAUSE");
043:    return 0;
044:  }


Que festival de else ifs! O código não fica muito elegante. Com a estrutura switch a coisa muda de figura.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char * argv[])
005:  {
006:    char op;
007:    int v1, v2;
008:
009:    printf("Digite a operacao: ");
010:    fflush(stdin);scanf("%c", &op);
011:    printf("Digite o primeiro valor: ");
012:    fflush(stdin);scanf("%d", &v1);
013:    printf("Digite o segundo valor: ");
014:    fflush(stdin);scanf("%d", &v2);
015:
016:    switch(op)
017:    {
018:      case '+': printf("Soma: %d\n", v1 + v2);
019:                break;
020:      case '-': printf("Subtracao: %d\n", v1 - v2);
021:                break;
022:      case '*': printf("Multiplicacao: %d\n", v1 * v2);
023:                break;
024:      case '/': if(v2 != 0)
025:                {
026:                  printf("Divisao: %d\n", v1 + v2);
027:                }
028:                else
029:                {
030:                  printf("Denominador igual a zero.\n");
031:                }
032:                break;
033:      default:
034:                printf("Operacao invalida!\n");
035:
036:    }
037:    system("PAUSE");
038:    return 0;
039:  }


Note que existe um caso (case) para cada valor de op. Note também que cada bloco de comandos inicia com um case constante: e termina com um break. Se o valor avaliado não existe na lista de opções, será executado o bloco de comandos padrão, chamado de default.
Muitos alunos me questionam se o default é necessário. A resposta é "Se o seu problema exigir um tratamento padrão, use o default, caso contrário não é necessário".
É importante saber que o switch funciona somente com variáveis do tipo inteiro, lembre-se que o char é um deles.
Aproveite essa estrutura para melhorar seus códigos.

E o else if?

Quando abordo as questões relativas aos comandos de decisões, muitos alunos me perguntam como devem proceder para escrever o camando else if.
Primeiramente respondo que não existe esse comando. Mas como explicar construção abaixo?


if(condicao)
{
  comandos...
} else if (condicao 2)
{
   mais comandos...
}


Lembra-se que no tópico Lá vêm as chaves, chaves, chaves... eu disse que as chaves são opcionais quando temos apenas uma linha de comando?
Então, o tal comando else if nada mais é do que uma utilização desse conceito. Veja dessa forma:


if(condicao)
{
  comandos...
} else
  if (condicao 2)
  {
     mais comandos...
  }


O que temos após o else é um comando de uma linha somente, o if, o qual pode ter n linhas dentro de seu bloco.
Usem a construção else if da primeira forma apresentada, ela tem melhor legibilidade.

quinta-feira, 20 de março de 2008

La vêm as chaves, chaves, chaves....

O título é uma brincadeira com o nome do personagem da tv.
As chaves delimitam um bloco de comandos na linguagem C e isso foi comentado no post Anatomia do programa em C.
Elas voltaram a aparecer na estrutura condicional, e é claro, delimitando um bloco de comandos tanto para o if quanto para o else.
Quando uma expressão condicional, localizada no if, é verdadeira, o bloco de comandos (que fica entre chaves) logo abaixo do if é executado. Na verdade, as chaves são obrigatórias quando o bloco de comando possui mais de uma linha de comando a ser executada. Quando existe somente uma linha de comando, as chaves passam a ser opcional. Isso, isso, isso, isso, .... Opcional!
Recorrendo novamente a divisão, temos:


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    float numerador, denominador;
007:    
008:    printf("Digite o numerador: ");
009:    fflush(stdin);scanf("%f", &numerador);
010:    printf("Digite o denominador: ");
011:    fflush(stdin);scanf("%f", &denominador);
012:    if(denominador != 0)
013:      printf("Resultado da divisao: %f\n", numerador/denominador);
014:    else
015:      printf("Nao e possivel fazer divisao por zero!\n");
016:    system("PAUSE");
017:    return 0;
018:  }


Na minha opinião, o uso das chaves auxilia a leitura do código e ainda insere um fator de segurança quando uma manutenção do código inclui mais linhas nos blocos de comando. Essa prática minimiza a ocorrência do esquecimento desenvolvedor em incluir as chaves quando ele insere as novas linhas. Esquecer as chaves quando necessárias causam grandes aborrecimentos e afinal, o esquecimento "foi sem querer, querendo!".
Eu uso sempre as chaves, exceto no else if, porque não quero ficar chorando por aí. "Pi, pi, pi, pi, pi".

terça-feira, 18 de março de 2008

Condicional composto

O condicional simples resolve apenas uma pequena parte dos problemas de programação. É interessante testar uma condição e se ela for falsa, tomar alguma decisão. Isso é possível com o condicional composto.


SE condicao ENTAO
  comando_001;
  comando_002;
SENAO
  comando_003;
  comando_004;
FIM SE


Os comandos 001 e 002 serão executados sempre que o valor de condicao for verdadeiro e os comandos 003 e 004 serão executados sempre que a condição for falsa.
Na linguagem C, o condicional composto é expresso por:


if(condicao)
{
  comando_001;
  comando_002;
}
else
{
  comando_003;
  comando_004;
}


Tal como no condicional simples, utilizarei a divisão para ilustrar o funcionamento do condicional composto em linguagem C.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    float numerador, denominador;
007:    
008:    printf("Digite o numerador: ");
009:    fflush(stdin);scanf("%f", &numerador);
010:    printf("Digite o denominador: ");
011:    fflush(stdin);scanf("%f", &denominador);
012:    if(denominador != 0)
013:    {
014:      printf("Resultado da divisao: %f\n", numerador/denominador);
015:    }
016:    else
017:    {
018:      printf("Nao e possivel fazer divisao por zero!\n");
019:    }
020:    system("PAUSE");
021:    return 0;
022:  }


O código acima avalia se o denominador é diferente de zero para efetuar a divisão. Quando o denominador é igual a zero, o programa informa ao usuário que a divisão por zero é impossível.
Sugiro a leitura dos posts Qual a negação do maior e Qual a negação do OU por estarem intimamente ligados ao SENAO de uma estrutura SE.

sexta-feira, 14 de março de 2008

Qual a negação do OU?

Pense bem antes de responder!!!!
A negação da operação lógica OU não é a operação lógica E.
Vamos demonstrar por meio de um exemplo prático! Suponha a seguinte condição idade <= 10 || idade > 20 como necessária a uma pesquisa de opinião, que visa consultar pessoas fora da idade da adolescência.
A tabela verdade para a seguinte expressão é:
idade <= 10idade > 20idade <= 10 || idade > 20
FFF
FVV
VFV
VVV

Considerando idade uma variável inteira, para a primeira proposição temos valores de idade entre 10 e 19 anos, o que torna falso a expressão (condição de adolescentes).
Na segunda proposição temos valores de idade maiores que 20, ou seja, não existem (matematicamente falando) adolescentes cuja idade é superior a vinte anos.
Na terceira proposição temos valores de idade menores ou iguais a 10, ou seja crianças.
A quarta proposição é matematicamente impossível porque não existem valores de idade que satisfaçam a equação. Se você conhece um valor de idade que ao mesmo tempo é maior que 20 e menor ou igual a 10, por favor, me avise!
Agora vamos analisar a negação da expressão e ver o que acontece.
idade <= 10idade > 20!(idade <= 10 || idade > 20)
FFV
FVF
VFF
VVF

Como é de se esperar, o resultado final é invertido, em outras palavras, a negação é verdadeira para a faixa de idade que compreende a adolescência.
Comparando com a operação E, o resultado não é o mesmo! Veja a tabela verdade abaixo:
idade <= 10idade > 20idade <= 10 && idade > 20
FFF
FVF
VFF
VVV

Note que a primeira e a última linha da negação do OU e da operação E não coincidem, o que mostra que não são operações equivalentes. Uma outra curiosidade nesse caso, a operação E nunca será verdadeira porque não existe valor de idade que é menor ou igual a 10 E maior que 20.
Pelo exemplo, a negação da expressão limitou os valores que compreendem a adolescência, ou seja valores de idade maior que 10 E menor ou igual a 20, que expresso em linguagem C fica idade > 10 && idade <= 20
Vamos novamente recorrer a tabela verdade, considerando a nova expressão.
idade > 10idade <= 20idade > 10 && idade <= 20
VVV
VFF
FVF
FFF

Note o resultado dessa tabela verdade com a segunda... São iguais!!!
Agora note os operandos... Eles são os complementos lógicos dos operandos da segunda tabela!!!
O que ocorreu com a operação lógica? Veja que a operação lógica OU foi trocada pela E.
O que você acabou de verificar foi a aplicação da lei de De Morgan que diz:
!(A || B) == !A && !B
!(A && B) == !A || !B
Finalizando, a negação das operações lógicas E e OU é facilmente resolvida pela lei de De Morgan.

segunda-feira, 10 de março de 2008

Qual a negação do maior?

Se sua resposta é menor, então deverá ler esse post.
Essa é uma questão puramente matemática, mas de fundamental importância para compreender o famoso senão da estrutura condicional.
O conceito da negação de uma expressão condicional está ligado a operação lógica não, afinal a expressão relacional retorna verdadeiro ou falso, a negação dessa expressão é, na verdade, negar o seu resultado.
Voltando a pergunta, qual a negação do maior, a resposta é menor ou igual a.
A expressão idade > 30 será verdadeira quando idade (supondo uma variável inteira) valer 31, 32, 33, ..., +infinito; e falsa para 30, 29, 28, ..., -infinito.
Analisando !(idade > 30) os valores esperados são falso para valores de idade iguais a 31, 32, 33, ..., +infinito; e verdadeiro para 30, 29, 28, ..., -infinito. Acho um pouco ilegível esse tipo de expressão, porque você deve analisar a desigualdade e após negar o resultado. O mais correto é usar o complemento lógico, ou seja, idade <= 30.
Segue uma lista do complemento lógico das operações relacionais existentes:

operaçãocomplemento
==!=
><=
>=<
<>=
<=>

sexta-feira, 7 de março de 2008

Condicional simples

O mais interessante quando programamos é a sensação de poder que temos sobre o destino dos dados. Quando escrevemos um programa, nada mais fazemos do que determinar qual tratamento será dado para os dados que alimentam o programa.
Os dados sofrem transformações, são utilizados ou descartados de acordo com seu valor. Para inferir os valores, usamos as estruturas condicionais. Elas são capazes de desviar o fluxo de processamento de acordo com o valor de uma ou mais variáveis.
A mais simples das estruturas condicionais é o se.


SE condicao ENTAO
  comando_001;
  comando_002;
  ...
  comando_nnn;
FIM SE


Os comandos serão executados sempre que o valor de condicao for verdadeiro.
condicao pode ser uma expressão relacional simples ou encadeada com vários operadores lógicos.
Na linguagem C, o condicional simples é expresso por:


if(condicao)
{
  comando_001;
  comando_002;
  ...
  comando_nnn;
}


Utilizarei a divisão para ilustrar o funcionamento do condicional simples em linguagem C.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    float numerador, denominador;
007:    
008:    printf("Digite o numerador: ");
009:    fflush(stdin);scanf("%f", &numerador);
010:    printf("Digite o denominador: ");
011:    fflush(stdin);scanf("%f", &denominador);
012:    if(denominador != 0)
013:    {
014:      printf("Resultado da divisao: %f\n", numerador/denominador);
015:    }
016:    system("PAUSE");
017:    return 0;
018:  }


O código acima avalia se o denominador é diferente de zero para efetuar a divisão. Sabe-se que na aritmética, não existe a divisão por zero, portanto implementamos essa regra de negócio para que a divisão ocorra sem problemas.
Apenas como curiosidade, o estudo de limites, trata da divisão por zero.
Parabéns, você acaba de receber um pequeno poder para definir o destino de alguns dados. Seja benevolente com eles....

quarta-feira, 5 de março de 2008

Operadores lógicos

Existem três operações lógicas básicas, a operação E, a OU e a NÃO, as quais operam com valores lógicos verdadeiro(V) ou falso(F).
A operação E e a OU, exigem dois operandos, já a NÃO exige somente um.
A operação E será verdadeira quando os dois operandos forem verdadeiros, elá valerá falso quando ao menos um dos operandos for falso.
ABA E B
FFF
FVF
VFF
VVV

A operação OU retornará verdadeiro quando pelo menos um dos operandos for verdadeiro, elá retornará falso quando os dois operandos forem falsos.
ABA OU B
FFF
FVV
VFV
VVV

A operação lógica NÃO, inverte o valor lógico do operando, ou seja, será verdadeira quando o operando for falso e falso quando o operando valer verdadeiro. Essa operação é também chamada de complemento.
ANÃO A
VF
FV

Os operadores lógicos são representados em liguagem C pelos seguintes tokens.
  1. (&&) E
  2. (||) OU
  3. (!) NÃO

Os operandos podem ser números, expressões relacionais, etc...
O programa abaixo mostra o resultado das operações E, OU e NÃO para valores de A e B digitados pelo usuário.


001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    int A, B;
008:
009:    printf("Digite o valor de A: ");
010:    fflush(stdin);scanf("%d", &A);
011:    printf("Digite o valor de B: ");
012:    fflush(stdin);scanf("%d", &B);
013:    printf("A E B: %d\n", A && B);
014:    printf("A OU B: %d\n", A || B);
015:    printf("NAO A: %d\n", !A);
016:    printf("NAO B: %d\n", !B);
017:    system("PAUSE");
018:    return 0;
019:  }


A saída esperada para A valendo 0 (Falso) e B valendo 1 (Verdadeiro)


Digite o valor de A: 0
Digite o valor de B: 1
A E B: 0
A OU B: 1
NAO A: 1
NAO B: 0

segunda-feira, 3 de março de 2008

Aqui vírgula é ponto!

Os iniciantes em linguagem C costumam confundir vírgula com ponto ou vice-e-versa.
Para os norte americanos, criadores da linguagem, o separador decimal é ponto e o de milhar é vírgula.
O número 10.326 para a linguagem C é dez inteiros e trezentos e vinte e seis milésimos, ou 10 + (float)326/1000.
Você se enganou se pensou que o número é dez mil e trezentos e vinte e seis.
Quando você programar, não utilize separador de milhar. A linguagem C utiliza a vírgula de forma reservada, portanto não dará certo;
Para separador de decimal, utilize o ponto.



001:  #include <stdio.h>
002:  #include <stdlib.h>
003:
004:  int main(int argc, char *argv[])
005:  {
006:    float decimal, milhar;
007:    
007:    decimal = 10.326;
007:    milhar = 10326;
008:    printf("Decimal: %f\nMilhar: %f", decimal, milhar);
009:    system("PAUSE");
010:    return 0;
011:  }


A saída esperada é:


Decimal: 10.326000
Milhar: 10326.000000


Espero que fique bem claro que aqui, vírgula é ponto. :D

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.