segunda-feira, 30 de novembro de 2009

Juntos somos mais eficientes! (vetores)

Até agora vimos somente os tipos básicos do C (aqui), e fizemos muita coisa com eles. Mas chega um momento em que eles não são eficientes para resolver alguns problemas. Quer um exemplo?
Imagine um programa que receba 100 valores inteiros digitados por um usuário. Imaginou? Se não, veja como ele seria usando o que vimos até agora.


//PROGRAMA QUE RECEBE 100 NÚMEROS INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int val001, val002, val003, val004, val005, ... , val100;
 
 printf("Digite 100 numeros inteiros:\n");
 scanf("%d",&val001);
 scanf("%d",&val002);
 scanf("%d",&val003);
 scanf("%d",&val004);
 scanf("%d",&val005);
    .
    .
    .
 scanf("%d",&val100);
 system("pause");
}


Percebeu a quantidade de linhas que esse programa teria? Sabia que é possível fazer este mesmo programa com 16 linhas (até menos) e de forma muito mais inteligente?
Dê uma olhada nesse exemplo.


//PROGRAMA QUE RECEBE 100 NÚMEROS INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int vetor[100], i;
 
 printf("Digite 100 numeros inteiros:\n");
 for(i=0; i < 100; i++){
    printf ("Valor %d: ",i+1);
    scanf("%d",&vetor[i]);
 }
 
 system("pause");
}


Este código acima está completo e funciona perfeitamente (não faz muita coisa, é verdade, mas funciona ;). Vamos ver o 'segredo' por trás disto.

Observe a linha 6. Nela é declarado um vetor de 100 inteiros. Vetor???

Um grupo de iguais.

Um vetor é um tipo estruturado homogêneo.(???)
Estruturado significa que ele é uma composição de tipos básicos, ou seja, tipos básicos organizados em um grupo/agrupamento. E homogêneo, significa que esses tipos básicos são iguais; no nosso exemplo, são 100 inteiros (é possível criar agrupamentos heterogêneos, como veremos em outro momento).
Não entendeu ainda? Quer que eu desenhe?



A figura acima representa um vetor de 4 inteiros armazenado na memória. Observe que o armazenamento é consecutivo, ou seja, cada valor inteiro está armazenado num endereço da memória, e estes endereços estão em sequência. Se tivéssemos declarado 4 variáveis inteiras não poderíamos garantir que elas ficariam armazenadas em sequência na memória.
Por estarem armazenados em sequência na memória, podemos acessar o conteúdo de cada endereço também em sequência. Esse é o 'truque' do vetor.
Mas como é feito esse acesso?

Leia o índice!

Com certeza você já teve contato com algum livro (se não, aconselho que o faça rsrs). Podemos generalizar um livro como uma sequência de páginas (escritas ou não) agrupadas. Todas as páginas tem o mesmo tamanho (não me lembro de ter visto algum em que isto não fosse verdadeiro).
Quando queremos encontrar alguma informação específica num livro temos duas opções: ou folheamos o livro, página por página, analisando uma a uma; ou vamos ao seu índice e localizamos o número exato da página onde está a informação que procuramos. Qual delas você considera mais eficiente?
Em termos de comparação, tirando as muitas diferenças, um vetor se assemelha muito a um livro. São posições de memória do mesmo tamanho agrupadas contendo algum valor válido (ou não). Já que são tão parecidos, por que não usar um índice também com um vetor? Facilitaria muito, não concorda? Pois é exatamente assim que funciona.
Vamos a outro desenho.



Para acessar o conteúdo da 1a posição do vetor da figura acima, é só se referir ao nome do vetor e ao índice 0 (zero). Os vetores em C SEMPRE começam com o índice 0 (zero).
Digamos que o nome do vetor da figura acima seja vet. Para exibir o conteúdo da sua 1a posiçao, usamos o comando:

 printf("%d", vet[0]);

Seria impresso o valor 67.

Fácil, não? Só devemos prestar atenção a 2 pontos importantíssimos:

1o. O primeiro índice de um vetor em C SEMPRE começa em 0 (zero)
2o. O último índice de um vetor em C é SEMPRE o tamanho do vetor menos 1.

Isso não significa que não se possa acessar um elemento fora do vetor.
Se usássemos no vetor dos desenhos acima o comando:

 printf("%d",vet[4]);

Algo seria impresso na tela. Não temos como saber o que seria, mas que funcionaria, funcionaria. Por quê?

Um nome de um vetor seguido de um índice i significa que queremos acessar o endereço que está i posições depois do endereço inicial do vetor.
Se um vetor de 4 inteiros está armazenado na memória, por exemplo, a partir do endereço 44 e o tamanho de um inteiro é 4 bytes; o elemento de índice 3 deste vetor estará no endereço 56.

 endereço inicial do vetor(44) + 3 * (tamanho do tipo do vetor (4)

Se tentarmos acessar o índice 4, que sabemos 'não existir', na verdade estaremos acessando o endereço 60 da memória, e 'interpretando' o seu conteúdo como um valor inteiro (este conteúdo pode ser qualquer coisa que esteja na memória, possivelmente deixada por algum outro programa, frequentemente no referimos a ele como 'lixo').
Algumas linguagens de programação não permitem esse tipo de acesso, mas o C não faz restrições. É sua responsabilidade como programador evitar esse tipo de coisa.

Agora que conhecemos o tipo vetor, ficou fácil entender o código do nosso exemplo. Certo?

quarta-feira, 25 de novembro de 2009

Um passo de cada vez... Algoritmos (fatorial/fibonacci)

Apesar do título do post ser um passo de cada vez, hoje veremos 2 algoritmos clássicos: Fatorial e Números de Fibonacci.
A razão para vermos os 2 ficará clara mais adiante em nossos estudos. Sem mais conversa vamos a eles.

Fatorial
Se você não sabe do que se trata, veja aqui.
Um exemplo de código que calcula o fatorial de um número em C, pode ser visto abaixo.


//PROGRAMA PARA CALCULAR A FATORIAL DE UM NUMERO DIGITADO
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int cont = 1, num, fatorial = 1;
 printf("Digite um numero inteiro:\n");
 scanf("%d",&num);
 while (cont <= num){
    fatorial *= cont;
    cont++;
 }
 printf("O fatorial de %d e %d\n",num,fatorial);
 system("pause");
}


Definimos e inicializamos uma variável inteira que chamamos de fatorial. Na linha 10, armazenamos nela o seu valor anterior multiplicado pelo valor da variável inteira contador, que teve o seu valor inicial definido como 1 (um), e é incrementado a cada repetição até alcançar o valor digitado pelo usuário.
Se o usuário digitar o número 4, por exemplo, haverá 4 repetições do bloco de comandos controlado pelo while, que resultará em:
 1 * 2 * 3 * 4
O resultado desta operação será o valor 24, que o fatorial do número 4.
Simples assim ;).

Sequência de Fibonacci
Antes de olhar o código, dê uma olhada aqui.
Agora que você já sabe o que é (sabe mesmo?), vamos a um exemplo em C.


//PROGRAMA QUE IMPRIMA OS N PRIMEIROS TERMOS
//DA SEQUENCIA DE FIBONACCI.
#include <stdio.h>
#include <stdlib.h>
 
int main(){
  int i, termos, termo, par = 1, impar = 1;
 
 printf("Digite o numero de termos desejado:\ ");
 scanf("%d",&termos);
 printf("\n");
 if (termos > 0){
    printf("0");
    i = 1;
    while (i<termos){
       if (i<3)
          printf(",1");
       else{
          termo = par + impar;
          printf(",%d",termo);
          if (i%2 == 0)
             par = termo;
          else
             impar = termo;
       }
       i++;
    }
 }
 else
    printf("NUMERO INVALIDO!!!\n");
 printf(".\n");
 system("pause");
}


Não sei se você reparou, mas observando a sequência de Fibonacci podemos ver que os termos de ordem par são a soma do termo ímpar e do termo par imediatamente anteriores a ele, exceto para os 2 primeiros termos, que por definição são 0 e 1.
Observe a figura abaixo.



Partindo desta observação, definimos duas variáveis inteiras chamadas de par e ímpar para armazenar os termos par e ímpar atuais, e assim, executar a soma dos mesmos para obter o próximo termo. Se este próximo termo for par, armazenamos ele em par, se for ímpar, em ímpar (acredito que isto seja lógico ;).
O if da linha 16 é para garantir que os 2 primeiros termos sejam 0 e 1, atendendo a definição.

Alguma dúvida? Pode perguntar nos comentários.
Por hoje é só. Até a próxima.

quarta-feira, 18 de novembro de 2009

Um passo de cada vez... Algoritmos (números primos)

Hoje vamos analisar um algoritmo para determinar se um número é primo.
Você sabe o que é um número primo? Veja aqui.
Agora que sabemos o que é um número primo, vamos ao algoritmo?
Antes, uma pequena observação: o algoritmo apresentado aqui tem como único e exclusivo objetivo ensinar o princípio do seu funcionamento, portanto, não está focado na velocidade e eficiência. Ok?
Dito isto, vamos ao código.


//PROGRAMA PARA VERIFICAR SE UM NÚMERO É PRIMO
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int num, nao_primo=0, divisoes=0, i;
 
 printf("Digite um numero inteiro: ");
 scanf("%d",&num);
 if ((num == 1) || (num % 2 == 0) && (num != 2))
    nao_primo = 1;
 else
    for(i = 1; (i <= num) && (divisoes <= 2); i += 2){
       if (num % i == 0)
          divisoes++;
    }
 if ((nao_primo == 0) && (divisoes <= 2))
    printf("O numero %d eh primo!\n",num);
 else
    printf("O numero %d nao eh primo!\n",num);
 system("pause");
}


Na linha 10 verificamos se o número digitado é 1 ou se é um número par diferente de 2. Se for, já sabemos, por definição, que não é um número primo, e informamos isto na linha 11.
Se o número digitado não se encaixar em nenhuma das opções anteriores, iremos testar, usando um comando de repetição for (linha 13), a quantidade de divisões exatas do número pelos números ímpares de 1 até o próprio número. A cada divisão exata incrementamos uma variável divisoes na linha 15. Se houverem mais de duas divisões exatas nem precisamos continuar testando, pois um número primo só é divisível por 1 e por ele mesmo, ou seja, duas divisões exatas.
Observou a forma que usamos para fazer a divisão somente pelos números ímpares? Incrementando a variável i que controla a quantidade de repetições do for de 2 em 2 (i += 2). Inteligente, não?
As outras linhas do código são apenas para informar se o número é primo ou não.
Viu como um código que parecia difícil, se tornou fácil?

Está gostando do blog? Comente, marque sua opinião nas reações abaixo, seja um seguidor do blog, siga o nosso twitter... Sua opinião é importante para sabermos se estamos no caminho certo, que é tornar o C mais fácil.
Até a próxima.

terça-feira, 17 de novembro de 2009

Um passo de cada vez... Algoritmos (palíndromo)

Agora que já conhecemos bastante coisa sobre o C, gostaria de tocar num ponto que complica a vida de muita gente que está iniciando em programação: os algoritmos.
Já comecei a falar sobre isso (aqui), e inclusive já vimos(?) na prática, embora eu não tenha falado sobre, como criar um algoritmo.
No último post da série sobre comandos de repetição, em um dos exemplos eu mostrei como criar um programa a partir de uma situação proposta. Quem vai executar as operações não somos nós, e sim o computador. O algoritmo é o 'roteiro' dos passos que ele irá seguir para executar essa função. E quem tem que 'dizer' a ele o que fazer somos nós, afinal, computadores não pensam (ainda!).

Pensando em algoritmos
Como já é costume nosso, vamos à prática.
Nosso 1o algoritmo consiste em verificar se um número digitado pelo usuário é palíndromo.
Antes de abrir o Dev e começar a digitar os includes, vamos entender o que é um número palíndromo. Veja aqui.
Muito bem agora que sabemos o que é um número palíndromo, como descobrir se o número digitado é ou não um deles?
Vamos usar o número 171 como exemplo (logo esse?). Este número tem 3 dígitos.

Se invertermos a ordem dos dígitos, teremos o mesmo número.

Então é só comparar o número com o seu 'inverso'.
Comparar números é fácil, já vimos isso com o if e os operadores relacionais.
Mas, como inverter o número?

Aprendendo a usar os restos
Para inverter os dígitos de um número, primeiro precisamos separar estes dígitos. No caso do nosso número com 3 dígitos, primeiro precisamos retirar 2 dígitos e ficar com 1 dígito que resta. Depois, dos 2 dígitos que retiramos antes, precisamos tirar 1 dígito e ficar com o outro dígito que resta. No final, só restará 1 dígito.
Percebeu a repetição de palavras derivadas de resto (resta e restará). O segredo está aí!
Vejamos um número menor, com 2 dígitos, por exemplo 17.
Se retirarmos o 1o dígito, neste caso o 1, restará o 2o digito, neste caso o 7.
Mas como 'retirar' um dígito do número? O resto é a resposta!
Se dividirmos o número 17 por 10, teremos como resultado 1 e um resto igual a 7. Melhor ainda, se utilizarmos o operador de módulo teremos o resto desta divisão fácilmente.
 digito = 17 % 10
O comando acima armazenará em digito o valor 7, que é o último dígito do número 17.
Uma vez que já temos o dígito que nos interessa, podemos eliminá-lo do número, para poder usar o mesmo artifício afim de 'retirar' outros dígitos. Para eliminar o último dígito de um número é só dividir este número por 10.
 num = 17 / 10
O comando acima armazenará em num o valor 1, desprezando o último dígito do número 17, neste caso o 7.
Se usarmos o módulo de 10 na variável num, que agora contém o valor 1, teremos um resultado 0 e um resto 1.
Viu como é fácil fazer com um número de 2 dígitos? Com números com mais dígitos a lógica é a mesma, só tem que ser repetida outras vezes dependendo da quantidade de dígitos.
Podemos usar o módulo de 10 para obter o último dígito do número, e depois dividir o número por 10 para eliminar este dígito que já foi obtido, e ir repetindo este processo até que o resultado da divisão do número por 10 seja 0 (zero), o que significa que acabaram os dígitos do número.
Já aprendemos como 'retirar' os dígitos de um número. E agora? Como inverter este número?
Vamos voltar ao nosso exemplo com o número 17. O inverso de 17 é 71. Que é o último dígito, neste caso o 7, multiplicado por 10, somado com o 1o digito, neste caso o 1.
Agora ficou fácil mesmo!
É só pegar o último dígito, neste caso o 7, obtido usando o módulo de 10 do número 17, multiplicar por 10, e somar com o 1o dígito, neste caso o 1, obtido usando o módulo de 10 no resultado da divisão do número 17 por 10.
Com números com mais dígitos a lógica é exatamente a mesma.
Vamos ver como vai ficar o nosso código?

//PROGRAMA PARA DETERMINAR SE UM NUMERO É PALINDROMO
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int digitado,num,invertido,digito;
 printf("Digite numero inteiro: ");
 scanf("%d",&digitado);
 num = digitado;
 invertido = 0;
 while(num != 0){
    digito = num % 10;
    invertido = (invertido * 10) + digito;
    num = num / 10;
 }
 if(digitado == invertido)
    printf("Palindromo !!!\n");
 else
    printf("Nao eh Palindromo!!!\n");
 system ("pause");
}


Os nomes das variáveis já falam por si. Note que não trabalhamos diretamente com o número digitado, e sim com uma variável num. Por quê?
Se tivéssemos usado diretamente o número digitado, ele seria perdido nas 'retiradas' dos dígitos e não teríamos como compará-lo com o seu inverso.
É mais fácil do que parece. Não é?
Até a próxima.

quinta-feira, 12 de novembro de 2009

De novo! De novo!... Final (curiosidades)

Para encerrar nossa série sobre os comandos de repetição, hoje vamos conhecer algumas 'curiosidades' sobre eles.

Tá faltando alguma coisa aí?
Acredito que você deve ter reparado no comando de repetição for, onde os comandos de controle de repetição do bloco ficam dentro de () separados por ;. Pois bem, você sabia que é possível usar um for sem que todas as suas partes estejam preenchidas? Lembra do exemplo que utilizamos para exemplificar o uso de um FLAG para sair de uma repetição (aqui)? Vamos refazer este exemplo, só que agora, utilizando o comando de repetição for, e você entenderá melhor como isto é possível.


//EXEMPLOS DE COMANDO DE REPETIÇÃO (FLAG)
#include <stdio.h>
#include <stdlib.h>
 
const int SAIR=0;
int main(){
 int num, total=0;
 
 printf("Digite um numero inteiro (0 (zero) para sair): ");
 scanf("%d",&num);
 for( ;num != SAIR; ){
    total += num;
    printf("Digite um numero inteiro (0 (zero) para sair): ");
    scanf("%d",&num);
 }
 printf("A soma dos valores informados eh igual a %d\n", total);
 system("pause");
}


O código deste exemplo é praticamente o mesmo que vimos antes, a única alteração está na linha 11, onde vemos o for.
Observe que não existe a inicialização de uma variável contadora, já que não temos um número de repetições determinado. Observe, também, que não existe um incremento.
Temos somente o comando que avalia se o bloco de comandos será repetido ou não.
Pode compilar e executar este código. Você verá que ele faz, exatamente, a mesma coisa que a versão utilizando o comando de repetição while.
Agora, vamos ir um pouco mais longe. Temos um comando dentro dos () do comando for. Poderíamos não ter nenhum?
Resposta: SIM. Um for sem nenhum comando dentro dos seus () cria o que se chama de loop infinito.
Por quê? Por quê? Por quê?
Já ouviu falar na Lei da Inércia? O loop infinito é basicamente isto. Se não dissermos ao comando for quando ele deve parar, ele vai continuar repetindo o bloco 'eternamente'.
E qual a utilidade disto??? Vamos a outro exemplo:


//EXEMPLO DE UTILIZAÇAO DE UM LOOP INFINITO
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int opcao, num, dobro, quadrado;
 
 for(;;){
    printf("Selecione uma das opcoes abaixo:\n");
    printf("1. Calcular o dobro de um numero\n");
    printf("2. Calcular o quadrado de um numero\n");
    printf("3. Encerrar o programa\n");
    printf("\nOpcao: ");
    scanf("%d",&opcao);
    system("cls");
    if (opcao == 1){
       printf("Digite um numero inteiro: ");
       scanf("%d",&num);
       printf("O dobro de %d eh %d.\n",num, num*2);
       system("pause");
       system("cls");
    }
    else
       if (opcao == 2){
          printf("Digite um numero inteiro: ");
          scanf("%d",&num);
          printf("O quadrado de %d eh %d.\n",num, num*num);
          system("pause");
          system("cls");
       }
       else
          if (opcao == 3){
             printf("\nO programa sera encerrado.\nObrigado por utilizar nossos sistemas!\n");
             system("pause");
             break;
          }
          else {
             printf("\nOPCAO INVALIDA!!! Tente novamente.\n");
             system("pause");
          }
    system("cls");
 }
}


Olhe bem para este código. Acredito que ele seja 'familiar' para você. Se não é, dê uma olhada aqui. Se você compilar e executar este código acima, verá que ele faz a mesma coisa que o exemplo que vimos para o comando de repetição do while.
Mas podemos notar várias diferenças entre eles, certo?
A 1a delas é que este não utiliza um do while, e sim, um loop infinito, utilizando um for 'sem comandos'.
A 2a é que este não utiliza um comando de decisão switch, e sim, vários comandos de decisão ifs aninhados.
Pergunta: Por que não usar o switch já que é muito mais prático?
A resposta para isto está na linha 35. É o comando break. O comando switch faz uso do comando break para sair do bloco de decisão depois que são executados os comandos referentes a uma única escolha. Só que neste caso, o comando break é usado para encerrar o loop infinito, e permitir o término do programa. Se tivéssemos usado o switch, o break nunca seria associado ao for do loop infinito, e sim, ao switch.
Olhando para este código, podemos ver porque o comando do while foi criado (rsrs).
Vamos a uma última 'curiosidade' (pelo menos por hoje).

Tem coisa demais aí?
Se por um lado, podemos não ter comando nenhum dentro dos () de um for; por outro, podemos ter mais de um comando entre os ; dentro dos () do for.
Antes de vermos o código de exemplo, vamos imaginar a seguinte situação:
Uma dupla está numa competição onde uma das provas consiste em encher um recipiente A de 3 litros com um líquido contido num recipiente B de 4,25 litros, percorrendo um circuito e utilizando dois outros recipientes menores de 500ml e 350ml, um para cada competidor da dupla respectivamente. Cada vez em que o líquido é levado do recipiente B para o A, é contada uma volta no circuito. A dupla tem que encher o recipiente A em no máximo 5 voltas. Os dois competidores podem levar o líquido do recipiente B para o A usando o seu respectivo recipiente na mesma volta. Devido as dificuldades no circuito, nem sempre os recipientes menores chegarão cheios ao recipiente A. Se algum dos competidores tentar fraudar a prova, informando um valor maior do que o seu recipiente pode transportar, o valor informado será ignorado. Como fazer um programa que controle isto???
Este é o nosso exemplo. Vamos a ele.


//PROGRAMA DE CONTROLE DA EXECUÇÃO DE UMA PROVA DE UMA COMPETIÇÃO
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int voltas;
 float liqA, total = 3000, rec500, rec350;
 
 for(voltas = 0, liqA = 0, rec500 = 0, rec350 = 0; liqA < total && voltas < 5; voltas++){
    printf("VOLTA %d:\n",voltas + 1);
    printf("Digite a quantidade em ml de liquido no recipiente de 500ml: ");
    scanf("%f",&rec500);
    if (rec500 <= 500)
       liqA += rec500;
    rec500 = 0;
    printf("Digite a quantidade em ml de liquido no recipiente de 350ml: ");
    scanf("%f",&rec350);
    if (rec350 <= 350)
       liqA += rec350;
    rec350 = 0;
    printf("\n");
 }
 if (liqA >= total)
    printf("\nA dupla cumpriu a tarefa em %d voltas e ganhou os pontos da prova.\n", voltas);
 else
    printf("\nA dupla so conseguiu transportar %.2f ml e nao ganhou os pontos da prova.\n", liqA);
 system ("pause");
}


Alguma dificuldade em entender este código?
Calma, vou explicar alguns detalhes dele.
Primeiro definimos as nossas variáveis. Com os nomes que demos a elas, não é difícil saber qual a função de cada uma delas.
Depois disto, dentro do nosso for, inicializamos todas que ainda não haviam sido inicializadas. Observe que para separar os vários comandos de inicialização de variáveis utilizamos a , (vírgula).
Depois definimos a condição para que o nosso for executasse a repetição do bloco de comandos, no caso, enquanto o líquido no recipiente A fosse menor que a volume desejado, e enquanto não tivessem acabado as 5 voltas.
No bloco de comandos do for, estão os comandos para receber os valores transportados e acumular no recipiente A. Os ifs asseguram que os valores de cada recipiente estão corretos, evitando uma possível fraude, já que só acumulam se eles estiverem corretos.
Os comandos após o for são para informar se a dupla conseguiu ou não completar a prova.
Viu como fica fácil depois que se sabe!!!
Até a próxima.

terça-feira, 10 de novembro de 2009

De novo! De novo!... Parte III (do while)

Vamos prosseguir nossa série sobre comandos de repetição. Hoje veremos o comando de repetição do while.

Faça primeiro. Avalie depois!
Existe um dito popular que fala que se deve pensar duas vezes antes de falar. Mas existem ocasiões em que é necessário executar algumas operações antes e avaliar o resultado delas depois. O exemplo mais clássico disto são as listas de opções ou menu (faça biquinho para pronunciar corretamente rsrs).
Nos comandos de repetição while e for, a avaliação é feita antes da 1a execução do bloco de comandos; já no comando de repetição do while, esta avaliação é feita depois que o bloco de comandos é executado a 1a vez, ou seja, pelo menos uma vez o bloco de comandos será executado.
A sintaxe do comando de repetição do while é esta:
 do {
    .
    .
    .
    } while (condição);


Como de costume, vamos a um código para exemplificar o uso do comando de repetição do while.


//EXEMPLO DE UTILIZAÇAO DO COMANDO DE REPETIÇÃO DO WHILE
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int opcao, num, dobro, quadrado;
 
 do {
    printf("Selecione uma das opcoes abaixo:\n");
    printf("1. Calcular o dobro de um numero\n");
    printf("2. Calcular o quadrado de um numero\n");
    printf("3. Encerrar o programa\n");
    printf("\nOpcao: ");
    scanf("%d",&opcao);
    system("cls");
    switch (opcao){
       case 1:
          printf("Digite um numero inteiro: ");
          scanf("%d",&num);
          printf("O dobro de %d eh %d.\n",num, num*2);
          system("pause");
          system("cls");
          break;
       case 2:
          printf("Digite um numero inteiro: ");
          scanf("%d",&num);
          printf("O quadrado de %d eh %d.\n",num, num*num);
          system("pause");
          system("cls");
          break;
       case 3:
          printf("\nO programa sera encerrado.\nObrigado por utilizar nossos sistemas!\n");
          system("pause");
          break;
       default:
          printf("\nOPCAO INVALIDA!!! Tente novamente.\n");
          system("pause");
    }
    system("cls");
 }while (opcao != 3);
}


Observe que todos os comandos do programa estão dentro do bloco de comandos do comando de repetição do while, que começa na linha 8 e só acaba na linha 40. Nesta linha 40 está a avaliação da opção escolhida pelo usuário.
Primeiro, são apresentadas as opções disponíveis ao usuário, nas linhas de 9 a 12.
A linha 14 recebe a opção digitada pelo usuário, que é avaliada pelo comando de decisão switch da linha 16.
Enquanto a opção for diferente de 3 (sair), o bloco de comandos será executado.
Os outros comandos dentro do bloco de comandos do comando de decisão switch são para realizar a operação escolhida, apresentar o resultado desta operação, e ainda, permitir que o usuário repita sua escolha se fizer uma escolha inválida.
Fácil, não é?

Até a próxima.

sábado, 7 de novembro de 2009

De novo! De novo!... Parte II (while/contador/for)

Continuando nossa série sobre comandos de repetição, hoje veremos como repetir um bloco de comandos por um determinado número de vezes.

Faça isto todas essas vezes!
No post anterior, vimos como realizar a repetição de um bloco de comandos por um número indeterminado de vezes. Finalizando esta repetição quando um determinado valor fosse digitado (o famoso FLAG).
E quando sabemos exatamente quantas vezes queremos que um bloco seja repetido?
Imagine um programa que calcule a média aritmética de 15 valores inteiros digitados pelo usuário.
Já sabemos a quantidade de valores que serão digitados, neste caso, 15. Esta é a quantidade de vezes que devemos pedir ao usuário que digite um valor inteiro, ler este valor e somá-lo a um total para que, depois, possamos fazer a média dos valores digitados.
Vamos a um código para exemplificar isto.


//PROGRAMA QUE CALCULA A MÉDIA ARITMÉTICA ENTRE 15 VALORES INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
const int MAXDIGIT=15;
int main(){
 int valor, total=0, contador;
 float media;
 
 contador=0;
 while (contador < MAXDIGIT){
    printf("Digite um valor inteiro positivo: ");
    scanf("%d",&valor);
    total += valor;
    contador++;
 }
 media = total / MAXDIGIT;
 printf("A media entre os %d valores digitados eh %.2f\n",MAXDIGIT, media);
 system ("pause");
}


Observe a utilização de uma constante inteira MAXDIGIT. Poderíamos usar diretamente o número 15, que é a quantidade de repetições que desejamos; no entanto, usar uma constante torna este código mais fácil de ser alterado. Se desejarmos mudar o valor de repetições de 15 para 10, por exemplo, só precisaríamos alterar a linha 5. Se tivéssemos usado o valor diretamente, teríamos que alterar as linhas 11, 17 e 18. Num código pequeno como este, isto não é tão vantajoso, mas imagine num código onde este valor aparecesse muitas outras vezes.
Dito isto, vamos ao que, no post de hoje, realmente nos interessa neste código: as linhas 10, 11 e 15.
Na linha 10 nós 'zeramos' uma variável inteira chamada contador. Esta variável poderia ter qualquer outro nome (o mais usado é i), mas escolhi este para deixar bem claro qual a função dela.
Para que o computador repita um bloco de comandos por um determinado número de vezes, ele deve saber quantas vezes este bloco já foi repetido para, assim, saber quando deve parar de repetí-lo. Por isto, o uso desta variável, que é chamada de variável contadora ou contador.
Na linha 15 esta variável é incrementada, depois que os comandos do bloco foram executados; ou seja, seria como se ele 'dissesse': fiz outra vez.
Na linha 11 é feita a verificação de quantas vezes a repetição já foi realizada. Se ainda não chegou ao número de vezes desejado, o bloco será repetido. Uma vez atingido o número de repetições desejado, o bloco é 'pulado' e o comando seguinte a ele é executado, neste caso, a linha 17 que calcula a média dos valores digitados.
A sintaxe do comando de repetição while com um número de repetições determinado é esta:

 contador = 0;
 while (contador < Número de repetições desejado){
    .
    .
    .
    contador++;
}


Existe uma outra forma de executar esta repetição no C. Utilizando um comando de repetição específico para uso com número de repetições determinado: o for.
A sintaxe do comando de repetições for é esta:

 for(contador = 0; contador < Número de repetições desejado; contador++){
    .
    .
    .
 }


Percebeu alguma coisa em comum com a sintaxe do comando de repetição while com um número de repetições determinado? Outra coisa que deve ser observada, são os ; dentro dos (). Eles indicam o fim de cada comando de controle da repetição.
Observe o mesmo código do exemplo anterior usando o comando de repetição for.


//PROGRAMA QUE CALCULA A MÉDIA ARITMÉTICA ENTRE 15 VALORES INTEIROS
#include <stdio.h>
#include <stdlib.h>
 
const int MAXDIGIT=15;
int main(){
 int valor, total=0, contador;
 float media;
 
 for(contador = 0; contador < MAXDIGIT; contador++){
    printf("Digite um valor inteiro positivo: ");
    scanf("%d",&valor);
    total += valor;
 }
 media = total / MAXDIGIT;
 printf("A media entre os %d valores digitados eh %.2f\n",MAXDIGIT, media);
 system ("pause");
}


Qual dos dois usar? Você decide! Uma grande maioria de programadores profissionais prefere esta 2ª versão, que utiliza o for.

Por hoje é só pessoal. Até a próxima.

quinta-feira, 5 de novembro de 2009

De novo! De novo!... Parte I (while/flag)

Hoje vamos começar a entender como funcionam os comandos de repetição.

Como fazer para que uma operação seja repetida?
Até agora vimos programas simples, em que são necessárias poucas interações do usuário. Pedimos que ele digite 2 ou 3 valores no máximo e, para isto, usamos um printf para informar o que ele deve digitar a cada vez. E se precisarmos que o usuário digite 30 valores? Já imaginou o tamanho do código? Quantas vezes será necessário digitar o mesmo trecho do printf? Não tem como fazer com que o computador execute essa repetição por nós? A resposta é SIM.
Antes de entender como fazer isto no C, vamos entender o que é uma repetição.

Repetir? O quê? E até quando?
Repetição é a execução de uma operação, que já foi realizada, outra vez.
Imagine que você tenha que colocar objetos dentro de uma caixa. Os passos para isto seriam:

abrir a caixa;
verificar se existem objetos para colocar na caixa;
se existir, pegar um objeto;
colocar o objeto dentro da caixa;
verificar se existem objetos para colocar na caixa;
se existir, pegar um objeto;
colocar o objeto dentro da caixa;
verificar se existem objetos para colocar na caixa;
se existir, pegar um objeto;
10º colocar o objeto dentro da caixa;
11º verificar se existem objetos para colocar na caixa;
12º se não existir;
13º fechar a caixa;

Repare que os 5º, 8º e 11º passos são idênticos ao 2º passo, os 6º e 8º passos são idênticos ao 3º passo, e o 7º e o 10º passos são idênticos ao 4º passo. Isto significa que as operações dos 2º, 3º e 4º passos se repetem. Pensando em termos de código fonte, logo vemos que os 2º, 3º e 4º passos fazem parte de um bloco. Já identificamos o o quê. Falta o até quando?
Olhando este roteiro acima, vemos que o nosso bloco se repete enquanto tiver objetos para colocar na caixa. Quando acabarem os objetos a serem colocados na caixa, não é mais necessário executar o nosso bloco.
Pronto! É assim que devemos pensar quando falarmos de repetição.
Um bloco de comandos que será repetido enquanto uma condição for verdadeira.
Neste caso, o bloco são os 2º, 3º e 4º passos, e a condição é que ainda hajam objetos para serem colocados na caixa. Se houverem 20 objetos, o bloco será repetido por 20 vezes, se houverem 5 objetos, será repetido por 5 vezes.
O comando C para isto é o while, e segue esta estrutura:

 while (condição){
            bloco de comandos
 }

Vamos criar um código fonte para exemplificar isto. Neste código vamos pedir que o usuário digite alguns valores, e vamos somar os valores digitados e exibir a soma deles quanto o usuário finalizar a digitação. Fazendo uma analogia com os objetos e a caixa, os objetos são os valores digitados e colocar esses objetos na caixa seria o mesmo que somá-los. Até aí está tranquilo, mas como vamos saber que 'acabaram os objetos'?

Quando se acena a bandeira, acaba a corrida
Para que o computador saiba quando o usuário finalizou a digitação de valores, alguém tem que informar isto a ele. Normalmente, quem deve fazer isto é o próprio usuário. Mas como ele vai fazer isto?
Você já viu uma corrida profissional de carros? Vários carros ficam dando voltas e voltas em uma pista de corridas. Essas corridas tem uma duração definida por quantas voltas serão realizadas, mas algumas vezes por causa de acidentes que podem acontecer, a quantidade de voltas pode ser reduzida. Quem define esta redução são os comissários de prova. O piloto do carro não tem idéia de que a corrida irá acabar antes do que foi determinado anteriormente. Para informar ao piloto que a corrida acabou é acenada um bandeira quadriculada. Ao ver esta bandeira quadriculada, o piloto sabe que é o fim da corrida.
O C utiliza o mesmo artifício. A isto se dá o nome de FLAG, que significa bandeira em inglês, e funciona assim:
Escolhemos um valor que, se for digitado, indicará que se deseja finalizar a entrada, e informamos isto ao usuário.
Geralmente este valor será definido como uma constante, já que será único e não será alterado durante a execução do programa.
No nosso exemplo usaremos o valor 0 (zero), já que somar 0 a um valor resultará no próprio valor.
Vamos ao código.


//EXEMPLOS DE COMANDO DE REPETIÇÃO (FLAG)
#include <stdio.h>
#include <stdlib.h>
 
const int SAIR=0;
int main(){
 int num, total=0;
 
 while (num != SAIR){
    printf("Digite um numero inteiro (0 (zero) para sair): ");
    scanf("%d",num);
    total += num;
 }
 printf("A soma dos valores informados eh igual a %d\n", total);
 system("pause");
}


Antes que você tente compilar este código, que parece estar correto, eu gostaria de informar que existe um erro grave nele. Sabe qual é?
Observe a linha 9. Nela está o nosso comando de repetição while e a condição que controlará a repetição, no caso enquanto o valor digitado for diferente do valor da constante inteira SAIR que é 0.
Como ainda não foi digitado nenhum valor, não se sabe qual o valor da variável num. Outra coisa a observar, é que se o usuário digitar 0, que é o valor da constante SAIR, a soma da linha 12 será executada, quando não deveria ser. Como escolhemos o valor 0 para ser o FLAG, esta soma não afetará o resultado final; mas se tivéssemos escolhido o valor -99, por exemplo, o resultado final estaria totalmente comprometido.
Sendo assim, temos que avaliar o valor digitado antes de efetuar a repetição.
Vejamos como ficaria este código, com esta avaliação antes da repetição, que é a forma correta.


//EXEMPLOS DE COMANDO DE REPETIÇÃO (FLAG)
#include <stdio.h>
#include <stdlib.h>
 
const int SAIR=0;
int main(){
 int num, total=0;
 
 printf("Digite um numero inteiro (0 (zero) para sair): ");
 scanf("%d",num);
 while (num != SAIR){
    total += num;
    printf("Digite um numero inteiro (0 (zero) para sair): ");
    scanf("%d",num);
 }
 printf("A soma dos valores informados eh igual a %d\n", total);
 system("pause");
}


Agora sim.
O valor digitado será armazenado na variável num (linha 10) antes de ser avaliado pelo comando de repetição while.
Se o usuário tiver digitado 0 que é o valor do FLAG, os comandos do bloco não serão repetidos.
Pode compilar e executar este código. Faça os seus testes, altere o valor do FLAG e verifique o que acontece.
É mais fácil do que parece.

E se quisermos repetir um bloco de comandos por um determinado número de vezes?
Veremos isto no próximo post.

quarta-feira, 4 de novembro de 2009

'Abreviações' (Economizando os dedos rsrs !!!)

No post anterior, terminamos a nossa série sobre os comandos de decisão, e vimos um operador que é uma forma abreviada dos comandos if/else. Hoje, como prometido, veremos outras 'abreviações' usadas pelo C.

Abreviar... Para facilitar ou complicar???
Até agora vimos códigos pequenos, com no máximo 50 linhas, ou nem isto. Imagine, se tivéssemos que fazer um código de umas 1000 linhas, repleto de comandos.
Um bom programador, geralmente, é um bom digitador. Mas isto, na maioria das vezes não é verdade. A verdade é que é muito cansativo digitar várias vezes as mesmas palavras.
Hoje com o uso de Messenger, Google Talk, e afins, é cada vez mais normal o uso de abreviações.
Existem alguns comandos no C que são muito comuns e que, para evitar a repetida digitação deles (e economizar os dedos do programador), foram abreviados.
O nome técnico para essas 'abreviações' já é conhecido. São os operadores (lembra do operador de decisão?). Já vimos os lógicos, os relacionais, o de módulo e o de atribuição. Hoje veremos os matemáticos.
Vejamos um código fonte onde eles aparecem, depois vamos conhecê-los um a um.


//EXEMPLOS DE ABREVIAÇÕES DO C
#include <stdio.h>
#include <stdlib.h>
 
int main(){
   int num1=0, num2, num3, total=0;
 
   num1++;
   num3 = num1--;
   num2 = ++num3;
   num2 *= 10;
   total += (++num1 + --num2);
   printf("O valor final da variaveis eh num1: %d num2: %d num3: %d total: %d\n",num1, num2, num3, total);
   system("pause");
}


A 1º operador que nos chama a atenção está na linha 8. Este é um dos mais comuns, senão o mais comum, do C. É o operador de incremento.

 num1++;

Incrementar é aumentar.
O comando da linha 8 incrementa o valor da variável num1; que passa de 0 (zero) para 1 (um). E tem o mesmo efeito do comando abaixo:

 num1 = num1 + 1;

Outro detalhe importante sobre este operador é que ele pode fazer um pré-incremento ou um pós-incremento (hein???).
Observe a linha 10. Este operador aparece novamente. Só que dessa vez ele aparece antes do nome da variável num3. Além disto, existe um comando de atribuição na linha 10. Parece complicado, mas é bem simples. Vamos entender.
O valor da variável num3 é incrementado antes de ser atribuido à variável num2; ou seja, o valor de num3 que era 1, é incrementado, e passa a ser 2 e, este novo valor é atribuido à variável num2. Repare que o valor de num3 é incrementado antes de ser atribuído. Isto é um pré-incremento.
Se o comando da linha 10 fosse:

 num2 = num3++;

O valor da variável num3 seria atribuido à variável num2, e depois este valor de num3 seria incrementado. No caso, num2 receberia o valor de num3 que era 1, e depois o valor de num3 passaria a ser 2. Isto é um pós-incremento.
Se o operador só alterar a variável, como na linha 8, tanto faz ser um pré-incremento ou um pós-incremento, porque o valor final da variável será o anterior incrementado. Mas se a variável alterada pelo operador de incremento estiver em uma expressão , ou atribuição (como na linha 10), esta posição altera totalmente o valor final da expressão ou atribuição, como já vimos.

Na linha 9 vemos o oposto do operador de incremento, o operador de decremento.

 num3 = num1--;

Decrementar, ao contrário de incrementar, é diminuir.
Este operador, como o de incremento, também pode realizar um pré-decremento ou um pós-decremento. Neste caso, é realizado um pós-decremento. O valor de num1 (1) é atribuído à variável num3, depois é decrementado, passando a ser 0.

Na linha 11 vemos um operador de totalização.

 num2 *= 10;

Ele é chamado assim porque atribui à variável a qual está associado o resultado (total) da operação indicada neste operador entre o valor da variável e o outro valor informado (que pode ser inclusive o valor de outra variável).
Neste caso, a variável num2 recebe o valor de num2 multiplicado por 10. Sendo assim, o valor de num2 (2) é multiplicado por 10 e, é atribuido a num2, que passa agora a ter o valor 20.
Observe que foi realizada uma multiplicação (*=), mas poderia ter sido uma soma (+=), subtração (-=), divisão (/=) ou módulo (%=).
Na linha 12, é realizada uma soma.
Não irei explicar o que acontece na linha 12, afinal, não existe nada de novo nela.

Agora que já conhecemos 'as abreviações' (operadores), podemos ver onde eles são usados com muita frequencia: os comandos de repetição.