Mostrando postagens com marcador operadores relacionais. Mostrar todas as postagens
Mostrando postagens com marcador operadores relacionais. Mostrar todas as postagens

domingo, 3 de janeiro de 2010

Funções x Vetores. Parte Final (código)

Agora que já vimos os conceitos e como funciona a alocação dinâmica, estamos prontos para ver um código exemplo. Então vamos a ele.


#include <stdio.h>
#include <stdlib.h>
 
int ler_int(){
  int digitado;
 
 printf("Digite um valor inteiro: ");
 scanf("%d",&digitado);
 return digitado;
}
 
void mostra_int(int num){
 printf("%d ",num);
}
 
void exibe_vetor(int* vet, int tamanho){
 int i;
 
 printf("\n");
 for(i = 0; i < tamanho; i++)
    mostra_int(vet[i]);
 printf("\n\n");
}
 
int* preenche_vet_int(int tamanho){
 int *vet=0, i;
 
 vet = (int *) malloc (tamanho * sizeof(int));
 if (vet){
    printf("\nPREENCHENDO O VETOR:\n");
    for(i = 0; i < tamanho; i++)
       vet[i] = ler_int();
 }
 return vet;
}
 
int aumenta_vet_int(int* vet, int* tamanho, int incremento){
 int novo_tam, i;
 
 novo_tam = *tamanho + incremento;
 vet = (int *) realloc (vet, novo_tam * sizeof(int));
 if (vet){
    printf("\nPREENCHENDO OS NOVOS ITENS DO VETOR:\n");
    for(i = *tamanho; i < novo_tam; i++)
       vet[i] = ler_int();
    *tamanho = novo_tam;
    return 1;
 }
 else{
    printf("NAO FOI POSSIVEL AUMENTAR O VETOR!\n");
    return 0;
 }
}
 
int diminui_vet_int(int* vet, int* tamanho, int decremento){
 int novo_tam, i;
 
 novo_tam = *tamanho - decremento;
 if (novo_tam <= 0){
    printf("DECREMENTO INFORMADO INVALIDO!!! NAO FOI POSSIVEL DIMINUIR O VETOR!\n");
    return 0;
 }
 vet = (int *) realloc (vet, novo_tam * sizeof(int));
 if (vet){
    *tamanho = novo_tam;
    return 1;
 }
 else{
    printf("NAO FOI POSSIVEL DIMINUIR O VETOR!\n");
    return 0;
 }
}
 
int main(){
 int *vetor, tamanho, incremento, decremento;
 
 printf("Digite o tamanho do vetor:\n");
 tamanho = ler_int();
 vetor = preenche_vet_int(tamanho);
 if (vetor){
    exibe_vetor(vetor, tamanho);
    printf("Digite o quanto deseja aumentar o vetor:\n");
    incremento = ler_int();
    if (aumenta_vet_int(vetor, &tamanho, incremento))
       exibe_vetor(vetor, tamanho);
    printf("Digite o quanto deseja diminuir o vetor:\n");
    decremento = ler_int();
    if (diminui_vet_int(vetor, &tamanho, decremento))
       exibe_vetor(vetor, tamanho);
    free(vetor);
 }
 else
    printf("NAO FOI POSSIVEL ALOCAR O VETOR!\n");
 system("pause");
}


Depois do que já vimos nos post anteriores, este código ficou muito simples.
Algumas funções já são conhecidas nossas. E dentre as novas funções existe pouca coisa que ainda não foi dita.
A primeira função nova está na linha 25, e é a razão desta sequência de posts. É uma função que retorna um vetor. Um detalhe interessante dela é que damos ao usuário a liberdade de definir o tamanho deste vetor. Seu funcionamento é simples.
Declaramos um ponteiro para inteiros vet e o inicializamos com o valor 0. Este ponteiro irá armazenar o endereço do vetor que será alocado dinamicamente.
Fazemos uma chamada a função malloc com o tamanho definido pelo usuário, e atribuimos o seu retorno ao ponteiro vet.
Se a chamada teve sucesso e o vetor foi alocado, imediatamente vamos preenchê-lo.
Observe o uso do if sem nenhum operador relacional. Na verdade ele verifica o valor de vet. Por isso o inicializamos com 0. Se a função malloc falhou, o valor de vet ainda será 0 (se funcionar perfeitamente, malloc nunca retorna um endereço 0). Este if verifica se o valor de vet é diferente de 0 (cuidado com isto: por diferente entenda qualquer outro valor, inclusive negativo). Este uso do if é muito comum, e passaremos a usá-lo, sempre que possível, daqui pra frente, como pode ser visto nas linhas 84 e 88, onde ele avalia o valor retornado pelas funções que aumentam e diminuem o tamanho do vetor, respectivamente.
A segunda nova função, na linha 37, aumenta o tamanho do vetor com um valor também definido pelo usuário, usando a função realloc. Observe que usando um ponteiro para a variável tamanho, podemos alterar o seu valor dentro da própria função.
A última função nova, na linha 55, diminui o tamanho do vetor de forma semelhante à função que o aumenta, usando a função realloc com um valor definido pelo usuário. A diferença entre elas é a verificação da validade do valor informado pelo usuário, evitando um erro ao tentar alterar o tamanho do vetor para 0 ou um valor negativo.
Observe que na linha 90, já na função main, desalocamos o bloco de memória usado pelo vetor. Isto é muito importante, se não este espaço ficará 'ocupado' mesmo após o término do programa.

Com isto encerramos a nossa série sobre funções que retornam vetores e como isto é possível utilizando a alocação dinâmica.
Alguma dúvida?

segunda-feira, 26 de outubro de 2009

Deixe que o computador decida... Parte I (if)

Continuando a nossa jornada pelo C, hoje vamos falar sobre como o computador toma decisões.

O computador não pensa, mas pode tomar decisões!
Parece estranho isto que falei; afinal, todas as vezes que precisamos tomar decisões temos que pensar (embora algumas pessoas não o façam ;).
Pois bem, se ele não pensa, como faz isto? Simples! Alguém tem que pensar por ele! Quem seria este alguém??? Você, programador.
Criar programas é pensar pelo computador e, é o que já fazemos. Definimos as variáveis, os tipos, como os dados serão processados, o que será impresso, etc.
Para nos ajudar nesta tarefa de 'ensinar' o computador a tomar decisões, o C nos fornece os comandos de decisão e os operadores relacionais.
Hoje falaremos sobre o comando de decisão if e os operadores relacionais.

E se...?
Já reparou que temos que tomar decisões em função dos acontecimentos? Quando você vai sair de casa, logo olha para as condições climáticas. Seria algo, mais ou menos, assim:
Está calor agora, mas o céu está com nuvens. Levo guarda-chuva ou não? Mas, e se chover? Então, é melhor levar o guarda-chuva. Se chover, e somente se chover, eu faço uso do guarda-chuva, senão ele fica fechado.
O comando de decisão if faz exatamente isto. Vamos ver na prática, como ele funciona?

"O prevenido vale por dois!"
Se você se lembra do programa que usei como exemplo para explicar o uso do scanf (aqui), verá que no comando da linha 11, que explica ao usuário o que digitar para que o programa funcione, existe uma sugestão para que ele não digite o valor 0 (zero). Imagina, o por quê disto?
O resultado de uma divisão por zero é indeterminado. Como não se consegue determinar, evita-se fazer esta divisão.
Agora, me responda esta pergunta. E se o usuário, mesmo sendo avisado antes, digitar zero?
Na gíria dos programadores, o programa vai 'capotar'.
Os micros mais antigos, com sistemas operacionais também antigos, travavam de uma forma que, para voltar a funcionar, só desligando e ligando novamente (reboot); e com isto se perdia tudo o que não tinha sido salvo ainda.
Eu mesmo já perdi várias horas de digitação, porque um programa fez uma divisão por zero (runtime error division by zero). Como 'xinguei' o computador! Hoje sei, que 'xinguei' a 'pessoa' errada rsrs!
Evite ser xingado e use o comando if!
No caso do nosso exemplo seria só fazer assim:
- Antes de fazer a operação da linha 13, a divisão de num1 por num2, temos que avaliar o valor de num2.
Fácil, não é? E como se faz isto?
Resposta: Usando os operadores relacionais! Vamos a eles.

Operadores relacionais (Qual a relação entre laranjas e bananas?)
Antes de mostrar os operadores relacionais, vamos pensar no nosso exemplo.
Não queremos que o divisor da nossa divisão seja zero. Ele pode ser maior que zero, ou menor que zero. Só não pode ser zero! Tem que ser diferente.
Pensando assim, achamos a relação entre o nosso divisor (num2) e zero.
Se num2 for igual a zero, não poderemos efetuar a divisão. O programa será finalizado.
É exatamente isto que devemos 'dizer' ao computador que faça.
A forma de 'dizer' isto em C, é:

if (num2 == 0)
    exit(1);


Vamos por partes ;).
O if é o se da nossa frase em português, e significa exatamente isto em inglês (língua 'mãe' do C).
Dentro dos ( ) está a relação que estamos avaliando: num2 igual a zero.
Não estamos atribuindo o valor 0 (zero) a num2! Estamos avaliando/testando se a variável do lado esquerdo do == é igual a variável/valor do lado direito.
O == é um dos operadores operacionais, e avalia a igualdade entre variáveis e valores.
(O operador de atribuição é o =, e o operador relacional de igualdade é o ==. A confusão entre os 2 é muito comum, e gera erros de lógica que fazem muitos programadores queimarem neurônios por horas (rsrs). Preste muita atenção ao usar este operador relacional!)
A tabela abaixo mostra todos os operadores relacionais, e o que cada um significa.



Depois retornaremos a eles, com mais calma. Vamos continuar a análise, do nosso comando.
Na linha de baixo, temos o comando que encerra o nosso programa antes que ele execute a divisão.
E finalmente o ; que encerra o comando. Como assim, encerra?
Apesar de estar um duas linhas, este é um único comando. Poderia estar em uma única linha, mas está em duas por questões de clareza. Esta é uma caracteristica (não somente) do if: unir-se a outro comando formando um único.
Se quiser, altere o código, fazendo esta modificação, compile e execute; digite 0 (zero) para o valor do dividendo e veja o que acontece.
Esta alteração evita um 'capotamento' (rsrs), mas não deixa claro ao usuário o por quê do programa ser finalizado.
Não ficaria mais 'bonito' se fosse informado ao usuário a causa deste encerramento?
Então vamos alterar nosso código de novo para que isto seja feito.

if (num2 == 0)
    printf("O DIVIDENDO NÃO PODE SER ZERO! O programa será encerrado.\n");
    system("pause");
    exit(1);


Faça essas alterações no código, compile e execute.
O que aconteceu?
Conforme você deve ter notado, o programa encerra independente do valor do dividendo ser zero ou outro qualquer. Por que?
O comando if se encerra no ; . Portanto, para o computador os comandos seguintes NÃO fazem parte do if, e serão executados independente do if ser executado. Como corrigir isto?
Usando blocos! Que nada mais são que os sinais {, antes da sequência de comandos que queremos agrupar; e }, após estes comandos agrupados. Já falamos sobre isto aqui.
Assim nosso código ficará assim:


//Exemplo de if
//Exemplo de if

#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);
 if (num2 == 0){
    printf("O DIVISOR NAO PODE SER ZERO! O programa sera encerrado.\n");
    system("pause");
    exit(1);
 }
 resultado = num1 / num2;
 printf("O resultado da divisao de %.2f por %.2f eh igual a %.2f.\n",num1, num2, resultado);
 system ("pause");
}


Ficou muito melhor, não é?
E se desejarmos que para o valor do dividendo só sejam aceitos números pares?
Veremos isto no próximo post.

Continua...