sexta-feira, 30 de outubro de 2009

Deixe que o computador decida... Final ('curiosidades')

Vamos falar hoje sobre algumas 'curiosidades' dos comandos de decisão. Na verdade, não são bem 'curiosidades', são facilidades.

Como 'usar' o operador lógico || (or) com o switch?
Observe o código abaixo:


#include <stdio.h>
#include <stdlib.h>
 
int main(){
 char c;
 printf("Digite um caracter:\n->");
 scanf("%c",&c);
 if (c == 'a' ||c == 'e' ||c == 'i' || c == 'o' || c == 'u')
    printf(" Eh vogal!\n");
 else
    printf("Nao eh vogal!\n");
 system("pause");
}


O código acima recebe um caracter digitado pelo usuário e informa se é uma vogal ou não. Observe o uso do operador lógico || (or) para avaliar todas as 5 vogais (a, e, i, o, u). No entanto, se você compilar e executar este código, e entrar com uma vogal maiúscula (A, E, I, O, U), o programa dirá que não é uma vogal, já que ele só avalia as minúsculas. Poderíamos aumentar os || para avaliar também as maiúsculas.
Iria funcionar, com certeza; mas a linha de avaliação do if ficaria enorme.
Não poderíamos usar um comando switch para resolver isto?
Um código que nos vem a cabeça usando um comando switch seria algo assim:


#include <stdio.h>
#include <stdlib.h>
 
int main(){
 char c;
 printf("Digite um caracter:\n->");
 scanf("%c",&c);
 switch (c){
    case 'a':
       printf("Eh vogal!\n");
       break;
    case 'A':
       printf("Eh vogal!\n");
       break;
    case 'e':
       printf("Eh vogal!\n");
       break;
    case 'E':
       printf("Eh vogal!\n");
       break;
    case 'i':
       printf("Eh vogal!\n");
       break;
    case 'I':
       printf("Eh vogal!\n");
       break;
    case 'o':
       printf("Eh vogal!\n");
       break;
    case 'O':
       printf("Eh vogal!\n");
       break;
    case 'u':
       printf("Eh vogal!\n");
       break;
    case 'U':
       printf("Eh vogal!\n");
       break;
    default:
       printf("Nao eh vogal!\n");
 }
 system("pause");
}


O comando switch não era para reduzir o código??? (rsrs)
Era não, é! Mas o código ficou muito maior! O que deu errado?
Vamos analisar.
Podemos ver que existe uma repetição de comandos. Dentro dos cases que avaliam as vogais existem os mesmos comandos printfs e breaks.
O que fazer então para acabar com estas repetições desnecessárias?
Podemos usar os operadores lógicos || (or) para avaliar uma vogal minúscula e outra maiúscula?
A resposta é NÃO.
Não é possível fazer isto:

 case 'a' || 'A':

Dentro de cada case só pode haver um único valor.
Então não dá para usar o operador lógico || (or) junto com o comando switch?
Outra vez a resposta é NÃO.
Não podemos usar o operador lógico || (or), mas podemos conseguir o mesmo efeito dele.
Como? Veja o código abaixo:


#include <stdio.h>
#include <stdlib.h>
 
int main(){
 char c;
 printf("Digite um caracter:\n->");
 scanf("%c",&c);
 switch (c){
    case 'a':
    case 'A':
    case 'e':
    case 'E':
    case 'i':
    case 'I':
    case 'o':
    case 'O':
    case 'u':
    case 'U':
       printf("Eh vogal!\n");
       break;
    default:
       printf("Nao eh vogal!\n");
 }
 system("pause");
}


Este código ficou muito menor, e funciona perfeitamente para o propósito que foi criado. Pode compilar, executar e testar.
Não tem o mesmo efeito de usar o operador lógico || (or)?
Esta é uma 'curiosidade' do comando switch.
Quando encontra um case que corresponde ao valor avaliado, o comando switch executa os comandos que estão naquele case, até encontrar um comando break; se encontrar um outro case, ele ignora e 'segue em frente', e só para ao encontrar um comando break ou o final do bloco do comando switch.
Neste nosso código, a linha 19 será executada caso o caracter digitado for a, ou A, ou e, ou E, ou i, ou I, ou o, ou O, ou u, ou U.
Não é exatamente o efeito de usar um comando if com uma série de operadores lógicos || (or)?

Outra 'curiosidade' sobre o comando switch, é a possibilidade de utilizarmos, assim como no comando if, comandos switchs aninhados.
Observe este fragmento de código fonte abaixo:


 int x, y;
 .
 .
 .
 switch (x){
    case 1:
       switch (y){
          case 1:
 .
 .
 .
       }
 }
 .
 .
 .


Existem 2 cases com o mesmo valor 1:. Isto é perfeitamente possível, já que um se refere a variável x, e o outro a variável y.

A última 'curiosidade' que veremos hoje sobre os comandos de decisão, é a existência de um operador de decisão.

Operador de decisão ?
A linguagem C é muitas vezes considerada complicada pelo fato de usar algumas abreviações para comandos que são usados comumente.
Veremos estas abreviações mais a frente.
O comando de decisão if é um destes comandos usados com muita frequencia em códigos fonte, já que temos que tomar decisões que dependem dos dados quase que durante todo o tempo. Por isto, foi criado um operador de decisão que substitui um conjunto de comandos if-else simples.
Vejamos um exemplo.

 x = y > 10 ? 5 : 15;

O comando acima, atribui um valor a variável x que depende do valor da variável y. Se y for maior que 10, x receberá o valor 5, se não for, x receberá o valor 15.
Esta única linha substitui os comandos abaixo:


 if (y > 10)
    x = 5;
 else
    x = 15;


Em outras palavras, se a expressão avaliada (neste caso, y > 10) antes do operador de decisão (?), for verdadeira, o valor atribuido a variável (neste caso, x) será o valor imediatamente após o operador de decisão (?)(neste caso, 5); se não for verdadeira, ou melhor dizendo, for falsa, o valor atribuido a variável será o valor que está após o :.

Assim encerramos esta série sobre os comandos de decisão.
No próximo post veremos outras abreviações usadas no C. Até lá.

quinta-feira, 29 de outubro de 2009

Deixe que o computador decida... Parte IV (switch)

Hoje vamos seguir conhecendo os comandos de decisão do C.

Já vimos como tomar decisões que produzem saídas simples, do tipo faça ou não faça.
E quando as possibilidades de saídas aumentam?
Imagine um programa para imprimir o nome de um mês de acordo com o número deste mês.
Usando as regras de indentação, o código fonte vai ficando cada vez maior à medida que acrescentamos novas avaliações.



//PROGRAMA PARA IMPRIMIR O MÊS DE ACORDO COM O NÚMERO
//USANDO IFs ANINHADOS
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int mes;
 
 printf("Digite os digitos do mes:\n->");
 scanf("%d",&mes);
 if (mes == 1)
    printf("Janeiro\n");
 else
    if (mes == 2)
        printf("Fevereiro\n");
    else
        if (mes == 3)
            printf("Marco\n");
        else
            if (mes == 4)
                printf("Abril\n");
    .
    .
    .
    .
 else
    printf("O valor nao corresponde a um mes!\n");
 system("pause");
}


Para evitar esta progressão geométrica de aumento de espaços e tabulações (tanto que não pude colocar todo o código aqui, devido as limitações de espaço de exibição), O C nos dá a opção de usar o comando switch.

Uma lista de opções
Você já deve ter visto várias listas de opções: uma opção embaixo da outra, facilitando a visualização de todas elas.
O comando switch se parece com uma lista destas.
Olhe como ficaria o código acima usando o switch:


//PROGRAMA PARA IMPRIMIR O MÊS DE ACORDO COM O NÚMERO
//USANDO SWITCH
#include <stdio.h>
#include <stdlib.h>
 
int main(){
 int mes;
 
 printf("Digite os digitos do mes:\n->");
 scanf("%d",&mes);
 switch (mes){
    case 1:
       printf("Janeiro\n");
       break;
    case 2:
       printf("Fevereiro\n");
       break;
    case 3:
       printf("Marco\n");
       break;
    case 4:
       printf("Abril\n");
       break;
    case 5:
       printf("Maio\n");
       break;
    case 6:
       printf("Junho\n");
       break;
    case 7:
       printf("Julho\n");
       break;
    case 8:
       printf("Agosto\n");
       break;
    case 9:
       printf("Setembro\n");
       break;
    case 10:
       printf("Outubro\n");
       break;
    case 11:
       printf("Novembro\n");
       break;
    case 12:
       printf("Dezembro\n");
       break;
    default:
       printf("O valor nao corresponde a um mes!\n");
 }
 system("pause");
}


Algumas coisas chamam a atenção neste código.
A 1ª delas é a forma de uso do switch da linha 11. Entre os () fica a variável que será avaliada. O switch só trabalha com variáveis dos tipos char e int. Além disto, observe o uso de {} para indicar as opções que serão avaliadas.
A 2ª coisa que devemos reparar é na palavra case, que aparece pela 1ª vez na linha 12, seguida pelo número 1 e um :. Aqui aparece o valor que a variável avaliada pode assumir, neste caso 1.
Se a variável tiver um valor igual ao que segue a palavra case, os comandos abaixo deste case serão executados até o comando break.
O comando break encerra o switch, ou seja, o programa 'salta' para o comando seguinte ao bloco do switch. Ele é chamado de comando de desvio; e, além do switch, também pode trabalhar em conjunto com outros comandos, como veremos mais a frente em nossos estudos.
A 3ª coisa que devemos reparar é na palavra default, que aparece na linha 48, também seguida por :. O uso do default é opcional. Mas se usado, ele deve ser colocado abaixo de todas as opções possíveis, antes do fim do bloco do switch.
Se a variável não tiver um valor igual a nenhum dos anteriores, os comandos abaixo dele serão executados. Observe que após o default não é necessário o uso do comando break, já que não existem opções depois dele, e o switch será mesmo finalizado.

O switch é simples, mas muito útil. Veremos mais sobre algumas características dele no próximo post, onde encerraremos nossa série sobre os comandos de decisão, vendo algumas curiosidades sobre os comandos de decisão.

Até lá.

PS: O que você está achando do blog? Tem alguma coisa que não ficou clara? Ou que você tem uma forma melhor de explicar? COMENTE! Ajude a tornar este blog melhor!

quarta-feira, 28 de outubro de 2009

Deixe que o computador decida... Parte III (operadores lógicos)

Vamos continuar aprendendo como o computador 'toma' descisões.
Hoje vamos ver os operadores lógicos e como eles facilitam a nossa vida quando precisamos tomar decisões baseadas em várias condições.

Duas descisões (ou mais!) de uma tacada só!
Dando uma olhada no nosso código exemplo do post anterior, podemos observar que para resolver a questão proposta tivemos que avaliar duas condições, se o divisor era zero e se o divisor era par. Estas avaliações são feitas nas linhas 15 e 18, respectivamente. Você sabia que poderíamos fazer estas duas avaliações de uma só vez!
Vamos pensar na questão proposta:
A divisão só será feita se o divisor não for igual a zero e se o divisor for um número par.
Sendo assim, a divisão só será realizada se as duas condições forem verdadeiras. Se apenas uma delas não for, a divisão não será realizada.
Poderíamos, analisar uma delas e, se não fosse verdadeira, provocar a saída abrupta do programa; se ela fosse verdadeira, passaríamos a análise da outra e, se ela não fosse verdadeira, provocar a saída abrupta do programa; se esta segunda avaliação desse um resultado verdadeiro, aí sim, a divisão seria realzada.


//Exemplo de avaliação de várias condições

#include <stdio.h>
#include <stdlib.h>

int main( )
{
 float num1, resultado;
 int num2;
 
 printf("Digite o numero que sera dividido(dividendo)\n");
 scanf("%f",&num1);
 printf("Digite o numero par que dividira o anterior (divisor), nao pode ser zero\n");
 scanf("%d",&num2);
 if (num2 == 0){
    printf("O DIVISOR NAO PODE SER ZERO! O programa sera encerrado.\n");
    system("pause");
    exit(1);
 }
 if (num2 % 2 != 0){
    printf("O DIVISOR NAO EH UM NUMERO PAR! O programa sera encerrado.\n");
    system("pause");
    exit(1);
 }
 resultado = num1 / num2;
 printf("O resultado da divisao de %.2f por %d eh igual a %.2f.\n",num1, num2, resultado);
 system ("pause");
}


Esta solução funciona, mas não é 'estéticamente' correta. Vejamos o porquê?
Quando fazemos alguma coisa, queremos que ela chegue até o seu final, e não seja interrompida antes disto. Com um programa não é diferente!
No começo deste mesmo post anterior, alteramos o nosso código para respeitar esse comportamento: ir até o final, mesmo que, por alguma entrada inválida do usuário, sua operação principal não fosse executada.
Usando os ifs aninhados do post anterior, conseguimos este efeito.
Mas existe uma forma mais 'bonita' (rsrs) de fazer isto: usando os operadores lógicos!

A lógica dos operadores
Os operadores lógicos são baseados nos conceitos de portas lógicas e lógica de Boole. O objetivo deles é 'unir' duas entradas e produzir uma única saída.
Podemos, com isto, 'unir' as duas condições avaliadas do nosso problema e, produzir uma única saída em função delas.
Existem 3 operadores lógicos em C: o && (and), o || (or) e o !(not).
O operador relacional not (!) tem por função produzir uma sáida que é o inverso da entrada. Tudo o que for verdadeiro se torna falso, e o que for falso se torna verdadeiro. O ! já é nosso conhecido, apesar de ainda não termos falado dele (rsrs). Lembra do operador relacional de igualdade (==), ele tem um oposto, que é o operador relacional diferente de (!=). Percebeu a presença do operador lógico not (!) neste operador relacional?
Ele está aí justamente para dar a idéia do inverso do igual a, ou seja, diferente de.

 !Verdadeiro => Falso

O operador relacional or (||) realiza uma 'soma' das entradas. De forma simples, se uma das entradas (ou as duas) for verdadeira, a saída será verdadeira. A saída só será falsa se as duas entradas forem falsas.

 Falso || Falso => Falso
 Falso || Verdadeiro => Verdadeiro
 Verdadeiro || Falso => Verdadeiro
 Verdadeiro || Verdadeiro => Verdadeiro

O operador relacional and (&&) realiza um 'produto' das entradas. De uma forma simples, se uma das entradas for falsa, a saída será falsa. A saída só será verdadeira se as duas entradas forem verdadeiras.

 Falso && Falso => Falso
 Falso && Verdadeiro => Falso
 Verdadeiro && Falso => Falso
 Verdadeiro && Verdadeiro => Verdadeiro

Entendeu a lógica dos operadores? Então responda:
Qual o operador lógico que devemos usar para resolver o nosso problema?

Acertou quem disse and (&&). Vamos ver porque?
Usando as seguintes avaliações:
num2 != 0; será verdadeiro se num2 for diferente de 0 (zero).
num2 % 2 == 0; será verdadeiro se o valor armazenado em num2 for par.

Se num2 for igual a zero, e o valor armazenado em num2 for impar teremos:
 Falso && Falso => Falso saída falsa

Se num2 for igual a zero, e o valor armazenado em num2 for par teremos:
 Falso && Verdadeiro => Falso saída falsa

Se num2 for diferente de zero, e o valor armazenado em num2 for impar teremos:
 Verdadeiro && Falso => Falso saída falsa

Se num2 for diferente de zero, e o valor armazenado em num2 for par teremos:
 Verdadeiro && Verdadeiro => Verdadeiro SAIDA VERDADEIRA

Usando os operadores relacionais, o nosso código ficará assim:

//Exemplo do uso de operadores lógicos

#include <stdio.h>
#include <stdlib.h>

int main( )
{
 float num1, resultado;
 int num2;
 
 printf("Digite o numero que sera dividido(dividendo)\n");
 scanf("%f",&num1);
 printf("Digite o numero par que dividira o anterior (divisor), nao pode ser zero\n");
 scanf("%d",&num2);
 if ((num2 != 0)&& (num2 % 2 == 0)){
    resultado = num1 / num2;
    printf("O resultado da divisao de %.2f por %d eh igual a %.2f.\n",num1, num2, resultado);
 }
 else
    printf("O DIVISOR NAO PODE SER NEM ZERO NEM IMPAR! O programa sera encerrado.\n");
 system ("pause");
}


Você não acha que o código ficou mais 'bonito' agora?

Hoje vimos como avaliar várias condições de entrada de uma forma melhor que com os ifs aninhados.
No próximo post veremos como agir quando uma mesma condição pode ter várias saídas.
Até lá.

terça-feira, 27 de outubro de 2009

Deixe que o computador decida... Parte II (else)

No post anterior, deixei uma pergunta. Vamos respondê-la hoje.
Antes disto vamos, melhorar ainda mais o nosso código.
Se você reparar bem, nós fazemos uma saída forçada do programa se o usuário digitar o valor zero para o divisor (linha 17).
Esta sáida forçada pode ser evitada! Podemos fazer com que o programa se encerre normalmente no } que encerra a função main.
Como?
É isto que veremos hoje.

O comando else
Vamos analisar o que desejamos que o programa faça.

Primeiro avaliamos qual é o valor do divisor, se for zero, informamos isto ao usuário e vamos para o final do programa sem fazer a divisão. Se não for, fazemos a divisão, mostramos o resultado desta divisão ao usuário e vamos para o final do programa.
Reparou no se não? Assim como o se, ele existe em C! É o else (se não em inglês, da mesma forma que o if é o se).
Um else sempre está ligado a um if. Ele é o caminho alternativo da condição avaliada no if, algo como um 'plano b'.
Se a condição avaliada for verdadeira, faça isto; se não for, faça aquilo.
O else não precisa avaliar nenhuma condição. A condição já foi avaliada pelo if.
E somente quando ela for falsa, o comando else entrará em cena.
Lembra do exemplo do guarda-chuva. Seria algo assim:

Se está chuvendo
 abro o guarda chuva;
Se não
 ele vai continuar fechado;

No caso do nosso código, ele ficará assim:


//Exemplo de else
 
#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");
 else {
    resultado = num1 / num2;
    printf("O resultado da divisao de %.2f por %.2f eh igual a %.2f.\n",num1, num2, resultado);
}
 system ("pause");
}


Compile e execute este código. Para efeitos de teste, digite 0 (zero) para o divisor.
Viu como o programa foi até o final, mesmo quando o valor digitado pelo usuário foi inválido!
Mas, se a outra forma estava funcionando, qual o motivo desta alteração?
Porque esta alteração nos ajudará a resolver a questão que foi proposta.
Vamos prosseguir que logo você vai entender.
Nós alteramos nosso código para que avaliasse o divisor antes de fazer a divisão, afim de evitar uma divisão por zero. Agora desejamos avaliar se o valor do dividendo é um número par. Sendo assim, devemos fazer esta avaliação também.

Como saber se um número é par?
Dentre outras, um número é par se sua divisão por 2 for exata, ou seja, não sobrar resto. Em outras palavras, o resto tem que ser zero.
Fácil não é? Nem tanto.
Você lembra que tivemos que mudar o tipo da variável num2 de int para float, para que o resultado da divisão aparecesse corretamente? Não lembra? Veja aqui.
A divisão de um tipo float por 2 sempre será exata, já que o resultado será um número fracionário (com casas decimais). O resto sempre será zero, mesmo que o número seja ímpar.
Solução? Vamos mudar novamente o tipo da variável num2, agora de float para int.
O fato da variável num1 ser do tipo float garante que o resultado da divisão também será do tipo float.
Agora sim. Se o valor armazenado na variável do tipo int num2 for um número ímpar, ao ser dividido por 2, o resto da divisão será diferente de zero.
Então, agora teremos que fazer duas divisões? A resposta é NÃO.
Não? Mas, se para saber se um número é par ou ímpar, eu preciso saber qual é o resto da divisão deste número por 2, como não precisa dividir?
Simples! O C (sempre ele ;) nos fornece um recurso para isto: o operador de módulo (%).
O operador de módulo nos dá o resto da divisão entre 2 números inteiros.
Para saber o resto da divisão do valor armazenado na variável do tipo int num2 por 2 (que é o que desejamos para resolver este problema!), é só usar o seguinte comando:

 num2 % 2

Para saber se este resto é diferente de zero , é só usar o operador relacional diferente de (!=).
O comando completo ficaria assim:

 num2 % 2 != 0

Agora que já sabemos avaliar se um número inteiro é par ou ímpar, vamos continuar com a resolução da questão proposta.

Primeiro avaliamos qual é o valor do divisor, se for zero, informamos isto ao usuário e vamos para o final do programa sem fazer a divisão. Depois, se não for, analisamos se este valor é um número par. Se for fazemos a nossa divisão, mostramos o resultado desta divisão ao usuário e vamos para o final do programa. Se não for, informamos ao usuário e vamos para o final do programa.
Se você notou, temos um se e um se não dentro de um se não. Este é um recurso poderoso do C.

Blocos dentro de blocos (A Boneca Russa)
Já ouviu falar em Matrioshka. A Matrioshka é uma brinquedo tradicional de origem russa, que consiste em várias bonecas de tamanhos diferentes, encaixadas umas dento das outras.



O C tem sua própria versão de Matrioshka (rsrs).
É possível inserir um comando dentro de outro comando!
Imagine o comando if. É possível inserir um if dentro de outro if, ou dentro de um else. Isto é chamado de 'aninhar'. Você vai ouvir muito falar em ifs aninhados.
Vamos ver isto na prática.
Nosso código agora ficará assim:


//Exemplo de ifs/elses aninhados
 
#include
#include "stdlib.h"
 
int main( )
{
 float num1, resultado;
 int num2;
 
 printf("Digite o numero que sera dividido(dividendo)\n");
 scanf("%f",&num1);
 printf("Digite um numero par que dividira o anterior (divisor), nao pode ser zero\n");
 scanf("%d",&num2);
 if (num2 == 0)
    printf("O DIVISOR NAO PODE SER ZERO! O programa sera encerrado.\n");
 else
    if (num2 % 2 == 0){
       resultado = num1 / num2;
       printf("O resultado da divisao de %.2f por %d eh igual a %.2f.\n",num1, num2, resultado);
    }
    else
       printf("O DIVISOR NAO EH UM NUMERO PAR! O programa sera encerrado.\n");
 system ("pause");
}



Observou a indentação? Indentação são os espaços colocados no código fonte para que fiquem bem claros a quais blocos eles pertencem. Ela já apareceu em alguns exemplos de códigos anteriores. Para códigos fonte pequenos, ela não é tão necessária. Mas, para códigos um pouco maiores, como o do exemplo de hoje, ela se faz praticamente essencial.

Por hoje é só pessoal! Até o próximo post.

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...

domingo, 25 de outubro de 2009

Lendo valores digitados (scanf)

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


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



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

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

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

Vamos ao assunto de hoje.


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

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




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


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


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


Compile e execute.



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

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

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

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

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

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

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

Quem conseguir pode postar nos comentários.

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

sábado, 24 de outubro de 2009

Imprimindo na tela (printf)

No último post da série sobre código fonte nós analisamos (pelo menos, tentamos analisar ;) linha a linha um típico código fonte em C. Eu deixei um desafio para que você descobrisse o que fazia o comando da linha 11 do código analisado, no caso, system ("pause"). Descobriu?
Antes que os mais puristas venham me criticar sobre o uso deste comando, já que existem outros que atingem o mesmo objetivo; e de forma melhor, já que não deixam o código fonte dependente do sistema (leia-se Rwindow$); deixem que eu me defenda. Também não gosto deste comando, mas utilizo-o por 2 motivos:
1 - É o comando ensinado pela maioria dos professores de C (não é verdade?);
2 - Como uso o Dev C++, estou seguindo a recomendação da página oficial desta IDE (duvida? veja aqui, em inglês).

Isto posto, vamos ao assunto de hoje.

O comando printf
Por falar no código fonte do post anterior, você deve lembrar que falamos que o comando printf (linha 10) era muito importante e iríamos fazer um post só para ele, não é? Pois bem, este é o post.

Imprimindo...
O comando printf foi criado para imprimir. Isso você já deve ter percebido, mas imprimir o que e onde?
É aí que entra você, programador (gostou de ser chamado de programador???)!
Quem diz o que e onde o printf vai imprimir é você. Como você vai fazer isto? É o que veremos agora. Vamos começar com o onde.

A saída padrão
O comando printf pode imprimir em qualquer lugar. Por qualquer lugar, entenda a tela, uma impressora, um arquivo (existe uma função especializada, construída a partir do printf, para imprimir em arquivos (fprintf)), etc.
O alvo da impressão feita pelo printf é a saída padrão (stdout) que, geralmente, é a tela (existem formas de alterar isto).

Impressão formatada
Certamente você já ouviu falar em formatar (dar formato, forma, organizar segundo um padrão). A impressão feita pelo printf é formatada, ou seja, tem uma forma definda.
A forma que esta impressão terá é definida pelos parametros que são passados à função printf. Estes parametros ficam entre os ( ), como já vimos antes.

Os parametros da printf
Seguindo a teoria de que é fazendo que se aprende, vamos ao Dev C++.
Abra o Dev C++, crie um novo Arquivo fonte e copie o código abaixo.

//Exemplo 01 de printf

#include <stdio.h>

#include "stdlib.h"


int main( )

{

printf("Ola mundo!");

system ("pause");

}



Este código simples, é a minha versão do "Hello world", o programa mais simples feito em C (o mais simples que exibe algo na tela).
Pode compilar e executar.
Reparou na saída?

Olá mundo!Pressione qualquer tecla para continuar. . .

Não era isto que queríamos escrever! Era para aparecer só o Ola mundo!.
A frase Pressione qualquer tecla para continuar. . . é impressa pelo system("pause"). Só que ela está 'colada' no texto que escrevemos. Não ficaria mais 'bonito' se esta frase ficasse numa linha separada do nosso texto? Para isto é só imprimir um "enter". E como se faz isso?
O printf consegue imprimir qualquer caracter imprimível (verdade?). E os não imprimíveis, como é o caso do "enter" que nós precisamos?

Imprimindo o que não pode ser impresso
Para resolver esta questão complicada, o C dispõe de um recurso simples. Qual recurso é este?
Os códigos de escape, também conhecidos como códigos de barra invertida.
O símbolo '\' é conhecido no C como símbolo de escape. Ele é usado para tornar possível a impressão de alguns caracteres de controle e alguns símbolos especiais do C.
Os mais usados estão nesta tabela:




Conforme podemos ver, o 'enter' que precisamos é o '\n'.
Quanto aos símbolos especiais, um exemplo é o caracter ". Este caracter delimita o que vai ser impresso pelo printf. Agora, imagine que você queira imprimir um texto que tenha um outro texto delimitado por ". Exemplo: ("alguma "coisa""). A forma correta seria ("alguma \"coisa\"").
Substitua o comando da linha nn por este:

printf("Alo mundo!\n");

Agora, recompile e execute.
Ficou 'bem melhor'.

Imprimindo valores desconhecidos
Salve o seu Arquivo fonte do exemplo anterior e crie um novo em branco.
Copie o código abaixo.


//Exemplo 2 de printf

#include <stdio.h>
#include "stdlib.h"

int main( )
{
int num1=5, num2=2, resultado;



resultado=num1 / num2;
printf("O resultado da divisao de num1 por num2 eh igual a resultado.\n");
system ("pause");
}



Compile e execute.

Repare na saída. Você pode dizer, só olhando para a frase impressa, qual o valor armazenado nas variáveis? É bem capaz que você diga quais são os valores, porque viu no código fonte quais são eles. Sendo assim poderíamos substituir o comando da linha 9 por este:

printf("O resultado da divisao de 5 por 2 eh igual a 2.5.\n");

E se não tivesse nenhum valor no código fonte? Se tivéssemos dado ao usuário do programa a possibilidade de digitar os valores para a nossa soma (o que é muito comum)?
Entra em cena aqui mais um parametro de formatação da função printf, os especificadores de formato.
Os principais estão na tabela abaixo:




Agora que conhecemos este recurso do C, vamos corrigir o nosso código fonte para exibir os dados que desejamos mesmo sem saber o valor deles. É só substituir o comando da linha 9 por este:

printf("O resultado da divisao de %d por %d eh igual a %d.\n",num1, num2,resultado);

Note que usamos o especificador %d que imprime um número inteiro com sinal (poderíamos usar %i ou %u, já que nossos números são 'pequenos').
Além disto, o número de parametros do nosso comando printf ficou maior. Vejamos o porque disto.
Os especificadores de formato funcionam como comandos de substituição. Onde aparece o especificador de formato deverá ficar o valor que queremos mostrar; neste caso, o conteúdo das variáveis num1, num2 e resultado, exatamente nesta ordem. É importante observar isto, a ordem de impressão dos valores é a mesma em que eles são passados para a função printf.
Pode recompilar e executar.
Funcionou?
Na verdade não, correto? Nós sabemos que 5 dividido por 2 é igual a 2,5. E por que foi impresso 2?
A resposta é o tipo.
O tipo escolhido para a variável resultado foi int que armazena números inteiros. O resultado da divisão de um número inteiro por outro número inteiro na matemática nem sempre dá um número inteiro, veja o nosso exemplo. Para resolver isto temos que mudar o tipo da variável resultado para float.
Assim as linhas 6 e 7 ficarão assim:

int num1, num2;
float resultado;

Corrija, recompile e execute.
Além de não funcionar, agora ficou pior. Tá aparecendo que o resultado é 0 (zero). Por quê?
Porque não alteramos o printf, que deveria ficar assim:

printf("O resultado da divisao de %d por %d eh igual a %f.\n",num1, num2, resultado);

Novamente, recompile e execute.
Funcionou agora? Nada ainda, não é? Por quê?
Simples: Apesar da variável resultado ser do tipo float, o resultado da divisão continua dando um inteiro para o computador (ele não sabe das regras matemáticas!).
Temos duas soluções para isto (tem outra, mais veremos isso mais tarde):
A 1ª é mudar o tipo da variável num2 para float. A divisão de um número armazenado numa variável do tipo inteiro por outro número armazenado numa variável do tipo float tem como resultado um número com casas decimais (tipo float).
A 2ª é mais drástica. Mudar o tipo de todas as variáveis para float.

Tente a 1ª que já resolve. Não esqueça de mudar o comando printf da linha 9. Sabe como, certo?
Experimente esquecer e veja o que acontece.

Agora funcionou, não é?
Funcionar, funcionou; mas ainda não tá legal. Tá aparecendo um monte de zeros desnecessários.

Os especificadores de largura de campo
Dentre os parametros de formatação do printf, tem um que ainda não vimos que resolve isso. São os especificadores de largura de campo. Pode ficar tranquilo, que esses não precisam de tabela (rsrsrs).
Na verdade, os especificadores de largura de campo trabalham juntos com os especificadores de formato. É um número (e ponto) que fica entre o símbolo % e a letra do formato.
No nosso exemplo, para imprimir 2 e 2.5, usaríamos o seguinte especificador de largura de campo:

printf("O resultado da divisao de %d por %.0f eh igual a %.1f.\n",num1, num2, resultado);

Que significa que desejamos imprimir o valor armazenado na variável num2 com 0 (nenhuma) casas decimais, e o valor armazenado na variável resultado com uma casa decimal.

Corrija, recompile e execute (De novo! De novo!).

Finalmente, funcionou da forma esperada.

Agora você já pode fazer seus próprios teste.
Altere o nosso código fonte de exemplo para que ele faça a soma de 2 inteiros e exiba o resultado usando o comando abaixo:

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

Sabe explicar o que está acontecendo?

Nos 'vemos' no próximo post.

sexta-feira, 23 de outubro de 2009

Código Fonte... Parte III - Final (Estrutura)

Com os conceitos que vimos no post anterior, já estamos próximos (na verdade hoje é o dia) de fazer um código fonte que compile (gere um programa executável). Não necessáriamente, que funcione; afinal um programa pode compilar e mesmo assim não funcionar rsrs. Veremos isto mais a frente.

No primeiro post desta série, falamos sobre a necessidade de estruturar um texto. Separá-lo em parágrafos, pontuar corretamente, etc.
Este é o assunto de hoje: a estrutura de um código fonte em C.

A estrutura de um código fonte
Um típico código fonte em C é igual a este aqui embaixo.



//Programa para apresentar resultado da soma de dois números inteiros
#include <stdio.h>
#include "stdlib.h"
const int NUM2 = 10; //ESTE VALOR É UMA CONSTANTE
int main( )
{
int num1, resultado;
num1 = 5;
resultado = num1 + NUM2;
printf("O resultado da soma %d + %d eh igual a %d.\n",num1,NUM2,resultado);
system ("pause");
}


Vamos analisar este código linha a linha.

Comentários
Os comentários servem para esclarecer alguns pontos obscuros (obscuros? que não estão claros). Viu para que serve um comentário?
Como você viu acima, eu uso (e muito) os parênteses para fazer comentários.
No C, a forma de fazer um comentário é usando as barras paralelas //. Na verdade este é um dos padrões do C++, é o mais usado hoje em dia. Existe outro, que não vou comentar aqui. Esteja livre para procurar no Google qual é ele.
Assim sendo, a linha 1 é um comentário, que diz o propósito deste código fonte de forma simplificada. Há programadores que fazem verdadeiros cabeçalhos utilizando os comentários. Embora eles não sejam necessários, ajudam a esclarecer o código fonte. Esclarecer para nós programadores, porque para o C eles não significam nada! O C simplesmente os ignora. Repare que não tem ponto final (;) no fim dele.
Os comentários não precisam ficar separados em uma linha. Eles podem ser colocados no meio do código, após os comandos, como você pode ver na linha 4.
Lembre-se que TUDO o que for colocado após as barras paralelas é ignorado pelo C, mesmo que seja um comando válido.

Que # é esse? E porque não tem ;?
No post em que falei sobre compilação, falei sobre um tal de pré-processador, que é responsável por fazer alguns ajustes no código antes de 'entregá-lo' ao compilador.
É aí que entram as linhas 2 e 3. Nelas estão comandos para o pré-processador, por isto elas não seguem o padrão C, e sim o padrão do pré-processador.
O que elas fazem? Elas incluem (compliquei mais ainda rsrs). Para explicar o que elas incluem temos que ver outro conceito do C: as bibliotecas.

Bibliotecas
O Natal está se aproximando e eu já começo a lembrar do cheirinho das comidas especiais desta época: chester, rabanada, panetone, etc.
E o que isso tem a ver com Bibliotecas? Não era melhor falar em livros?
Vamos falar em livros agora e você vai entender o porquê desta instrodução.
As comidas especiais de Natal são tão especiais que só são feitas no Natal. Por isto, quem as faz não lembra exatamente como fazê-las, e por isto, recorre a livros de receita. (Não falei que ia chegar nos livros?)
Pois bem, algumas receitas são tão complexas que às vezes precisam de duas ou mais receitas que nem sempre estão num livro só. São necessários alguns livros.
O C também trabalha com seus 'livros de receitas'. Cada um destes 'livros' é chamado de biblioteca. Voltando as receitas culinárias; se quisermos passar uma receita para alguém teremos que copiar todas as partes das receitas que usamos para fazer aquela comida, mesmo que ela esteja em vários livros.
Agora vejam que idéia brilhante!
Um código fonte é na verdade uma 'receita', onde dizemos ao computador o que desejamos que ele faça. Se nossa 'receita' for complexa, nós usamos as bibliotecas. Só que, ao invés de copiar cada pedaço das várias 'receitas' dos vários livros, só precisamos dizer em que livro, ou melhor biblioteca, a receita está.
Isto é feito neste código pelas linhas 2 e 3. Elas incluem as bibliotecas que contém as receitas dos comandos printf (linha 10) e system (linha 11). Neste recurso que estou usando para exibir os códigos aqui no blog (Syntax Highlight), esses comandos aparecem em vermelho.
Existem várias bibliotecas (que são chamadas de especializadas), para os mais variados propósitos.
Se você reparou bem existe uma pequena diferença entre as linhas 2 e 3. Na linha 2, o nome da biblioteca está entre <>; já na linha 3, está entre " ". Este é um padrão para o local em que estas bibliotecas estão instaladas no seu computador, e indicam onde o pré-processador vai procurar por elas para poder incluí-las no código.
Os <> dizem para o pré-processador começar a procurar por elas no diretório padrão das bibliotecas ( se você instalou o Dev C++ no diretório sugerido pelo seu programa de instalação, este diretório é o C:\Dev-Cpp\include ). Já as " ", dizem para começar a procura pelo diretório onde o código fonte está salvo. Você pode usar qualquer um dos dois modos, conforme a sua necessidade.

Voltando ao código
O comando da linha 4 já é um conhecido nosso. Ele declara uma constante inteira e a inicializa com o valor 10.

Na linha 5, temos a função main. Esta merece uma atenção toda especial. Então vamos sair do código de novo rsrs.

A função main (Amém rsrs)
Se você fosse fazer alguma coisa dentre um um conjunto de quaisquer outras coisas, qual iria escolher para fazer?
Seguindo algum critério próprio, você decidiria por alguma delas. E o computador? Qual critério ele usa para escolher o que fazer?
Ele não usa critério nenhum (lembra que computador não pensa... ainda), quem diz onde ele deve começar somos nós programadores.
É aí que entra a main. Ela é a função principal de um programa executável. Todo programa executável tem que ter uma main (eu não conheço nenhum que não tenha, quem conhecer pode nos apresentar ;).
Antes da main, existe um identificador de tipo inteiro int. Ele pode, até, ser ignorado (o Dev C++ acrescenta ele, 'por baixo dos panos', quando compila o programa), você já deve ter visto alguns códigos sem ele. O que ele faz?
Ainda é cedo para explicar, voltaremos a este assunto mais a frente. Pode cobrar depois.
Depois da palavra main tem ( ). Dentro deles ficam os parâmetros da função main; que neste caso, não são usados e por isto os ( ) estão vazios. Parametros?
Parametros são dados e 'informações' que as funções usam para fazer o seu trabalho.
Lembra da linha 10? Nela está um comando (printf) que, geralmente, exibe alguma coisa na tela. O que ela tem que exibir e da forma que tem que exibir é 'informando dentro dos ( ).
Por hora é isto o que precisamos saber sobre a main. Vamos voltar ao código novamente (ou não).

Voltando ao código novamente (será?)
Na linha 6 temos um {. Para saber o que ele faz vamos sair do código ( de novo!) e explicar outro conceito fundamental do C: os blocos de comando.

Os blocos de comando
Podemos comparar os blocos de comandos da linguagem C ao parágrafo da linguagem escrita.
O parágrafo é o conjunto de frases que formam uma sequência com sentido, com lógica (tirei isto daqui); ou seja, são frases que tem a ver umas com as outras.
Blocos de comandos são comandos que estão relacionados entre si (simples assim). Todos trabalham juntos para cumprir uma tarefa. Um de cada vez, mas o objetivo final é o mesmo.
Um bloco de comando é iniciado com { e encerrado com }.
O bloco de comandos da main começa na linha 6 e acaba na linha 12.

Vamos (tentar) voltar ao código agora?
A resposta é não rsrsrs. Os outros comandos já são nossos velhos conhecidos :). São feitas algumas atribuições e o resultado é exibido na tela pelo comando da linha 10, do qual já falamos.
Aliás, o comando da linha 10 (o printf) é um comando muito importante, por isto faremos um post só para ele.
Você deve estar dizendo: Tem um comando na linha 11. O que ele faz?
Resposta: Descubra!!! (kkkkk)

Este código do nosso exemplo funciona. Pode criar um Arquivo fonte novo no Dev C++ e digitá-lo (ou copiá-lo). Ele está pronto para ser compilado.
Pode fazer alterações nos valores. E fazer suas próprias descobertas.
Quer uma dica sobre a linha 11? Pense em comentários.

Por hoje é só. Até o próximo post.

quinta-feira, 22 de outubro de 2009

Código Fonte... Parte II

Conforme prometido no post anterior, hoje vamos falar sobre os padrões do C.

Sou adepto da filosofia que diz que é fazendo que se aprende. Então vamos seguir essa filosofia! (Ao menos quando for possível ;)

Para isto inicie o Dev C++ e abra um novo Arquivo Fonte. Se não sabe como fazê-lo, veja aqui.

Para não causar desapontamentos futuros, vou logo avisando que não vamos criar um código fonte completo hoje! Veremos algumas particularidades sobre os padrões do C e como a IDE trata deles. Ok?

Identificando os dados
Lembra dos 'quadrinhos' que vimos aqui? Pois bem, dentro deste quadrinhos podem ficar armazenados informações ou instruções. O computador sabe encontrar cada um deles de acordo com o seu endereço. Mas este endereço não fica visível para nós programadores (existe uma forma de encontrar este endereço, assunto de um post mais adiante).
Se não podemos saber o endereço de um 'quadrinho', como vamos usá-lo? Como vamos 'escrever' ou 'ler' o que tem dentro de um deles?
Para resolver isto, o C nos dá a possibilidade de identificar cada um deles. Isto mesmo! Podemos dar um 'nome' a um 'quadrinho'. Seria como 'colar uma etiqueta' nele com o nome desejado.
Todas as vezes que nos referirmos a este nome estaremos falando daquele 'quadrinho' específico.
Este nome deve seguir algumas regras simples:
-COMEÇAR COM UMA LETRA OU _ (CARACTER DE SUBLINHADO (UNDERLINE)). Os caracteres seguintes podem ser letras, o próprio caracter de sublinhado ou números. Não use caracteres acentuados, espaços, símbolos de pontuação ou símbolos especiais (lembre-se que estes não são padronizados).
-LETRAS MAIÚSCULAS E MINÚSCULAS SÃO DIFERENTES PARA O C. Assim podemos ter no mesmo código fonte 4 'quadrinhos' identificados como valor, Valor, vAlOr e VaLoR. Cada um deles tem um endereço diferente e podem armazenar valores diferentes. USE ESTA REGRA COM CAUTELA! O computador não se confunde quanto a eles, mas nós podemos nos confundir. Não fica nem um pouco claro usar nomes como estes num mesmo programa.
-SÓ 32 CARACTERES SÃO SIGNIFICATIVOS.
-NÃO PODEM SER USADAS 'PALAVRAS RESERVADAS'. Vejamos o que e quais são elas.

Palavras reservadas
Existem algumas palavras que exercem um papel fundamental no C. Um exemplo são os identificadores e modificadores de tipo, que vimos aqui. No total elas são 32. (como diminuo este espaço entre o texto e a tabela?)





  • auto

  • break

  • case

  • char

  • const

  • continue

  • default

  • do


  • double

  • else

  • enum

  • extern

  • float

  • for

  • goto

  • if


  • int

  • long

  • register

  • return

  • short

  • signed

  • sizeof

  • static


  • struct

  • switch

  • typedef

  • union

  • unsigned

  • void

  • volatile

  • while

  • Vamos à pratica
    Digite algumas dessas palavras naquele código fonte em branco que criamos no Dev C++.
    Note que assim que você acaba de digitá-la, ela fica, automaticamente, em negrito. Esta é a forma que o Dev C++ trata as palavras reservadas do C.

    Nomeando os 'quadrinhos'
    Para nomear um 'quadrinho' devemos 1º dizer ao C qual será o tamanho dele, ou seja, o seu tipo.
    Antes mesmo disto, se desejarmos que o seu conteúdo não se altere, devemos informar este desejo. Se não o fizermos, ele será, por padrão, variável.
    Depois disto, informamos o nome desejado para ele.
    Por exemplo, para dar o nome valor a um 'quadrinho' que armazenará um valor inteiro e terá seu conteúdo variável devemos digitar:

    int valor

    Experimente digitar isto no código fonte que está aberto no Dev C++.
    Isto é uma instrução que demos ao C. Ela significa: pegue um 'quadrinho' de tamanho suficiente para armazenar um valor inteiro e cole uma etiqueta nele com o 'nome' valor.
    Esta é uma instrução está quase completa. Falta uma coisa muito simples a ela: O ponto final.

    O ponto final do C (;)
    No post anterior, vimos alguns padrões da língua portuguesa. Um exemplo que usei foi o parágrafo e os sinais de pontuação. O C também tem parágrafos e sinais de pontuação.
    Vejamos os sinais de pontuação; mais precisamente, o ponto final.
    O ponto final define o final da frase (será que é por isso que ele tem este nome?). Sem ponto final não dá pra saber onde termina uma frase e começa a outra.
    O ponto final do C é o ponto e vírgula (;). Se você tentar compilar um código fonte que não tenha o ; no final de cada instrução, isto criará um erro de compilação.
    Parabéns! Você acabou de descobrir o erro de compilação que usei para mostrar como o Dev C++ encontra este tipo de erro.

    Sendo assim a nossa instrução só ficará completa com o seu (;) final.

    int valor;

    E se o nosso 'quadrinho' fosse constante? Como seria declarado? (Vá se acostumando com esta nomenclatura. Daqui pra frente, procurarei usar a linguagem técnica, o famoso jargão.)
    Para declarar uma constante a forma correta é:

    const int valor;

    Esta instrução declara uma constante do tipo inteira com o nome valor. Só que cria um problema! Será que você sabe que problema é este?

    Qual o valor do 'quadrinho'?
    Para responder a esta pergunta, precisamos ter em mente que a MEMÓRIA RAM é um área onde o PROCESSADOR guarda dados rápidos e realiza operações. Lembre do conceito do quadro na sala de aula.
    Só que tem um detalhe! O PROCESSADOR é um professor descansado, que não se preocupa em apagar o quadro depois de usar.
    Portanto, nunca se sabe o que estava escrito no quadro antes. (Algumas vezes, em situações específicas, quando uma variável é declarada, o 'quadrinho' correspondente a ela é automaticamente apagado.)

    Olha o problema aí: Declaramos uma constante inteira chamada valor, mas não sabemos qual o valor que está armazenado nela. E, ainda pior, por ser uma constante não pode ser alterada.
    Como resolver isto?

    Colocando um valor no 'quadrinho'
    Mais uma vez, o C vem nos socorrer rsrs.
    Nos podemos 'colocar' um valor no nosso 'quadrinho'. Quando este 'quadrinho' é variável, esta atribuição pode ser feita a qualquer momento, inclusive, na declaração desta variável. No caso de ser constante, SÓ pode ser feito na declaração desta constante. O símbolo que indica esta atribuição é o = (não confundir com o = de matemática, que significa é igual a).
    Vamos ver alguns exemplos:
    int valor;
    valor = 10;

    Traduzindo: Declaramos uma variável do tipo inteiro com o nome valor e, no comando seguinte, atribuimos o valor inteiro 10 a esta variável. Este valor pode mudar durante a execução do problema.
    Usamos 2 comandos para fazer isto. Poderíamos fazer a mesma coisa com um único comando.

    int valor = 10;

    Esta é uma atribuição na declaração, que é chamada de inicialização. Que é a única forma de criar constantes.
    Agora que sabemos disto, vamos corrigir o nosso problema anterior.

    const int valor = 10;

    Agora sim! Criamos uma constante inteira chamada valor que contém o valor 10.
    Eu, particularmente, goste de nomear constante com letras maiúsculas, pois acho que fica mais fácil de identificá-las no código fonte. Faça como achar melhor.

    Um pouco mais sobre atribuições
    Como você viu até agora, podemos atribuir um valor a uma variável, tanto na sua declaração, como no decorrer do código fonte.
    Existem outras coisas que podemos fazer com as atribuições. Vejamos duas delas.

    Podemos atribuir o valor de uma variável a outra variável.
    Quer um exemplo?

    int valor01 = 10;
    int valor02 = 5;
    valor02 = valor01;

    Os comandos acima declaram e inicializam duas variáveis (valor01 com o valor 10 e valor02 com o valor 5) e, depois, o valor da variável valor01 é atribuido a variável valor02; ou seja, o valor de valor02 agora é 10 (valor armazenado). Não quer dizer que as variáveis são iguais, e sim que o valor armazenado nas duas é o mesmo, no caso, 10. (Procure entender bem este conceito, pois ele causa um tipo de erro muito comum, o famoso erro de lógica.)

    Podemos atribuir o resultado de uma operação a uma variável.
    Exemplo:

    int total;
    total = 10 + 5;

    Olhando os comandos acima, você pode dizer qual é o valor de total após o 2º comando?
    Parabéns se você disse 15.

    Pode fazer os seus testes no Dev C++. Lembrando que ainda não dá pra ver o resultado disto, ou seja, o programa em execução.

    Essa hora está chegando. Aguarde e confie.

    quarta-feira, 21 de outubro de 2009

    Código Fonte... Parte I (A volta da teoria rsrs)

    Hoje vamos começar a analisar o CÓDIGO FONTE.

    No post anterior, falamos sobre a instalação da IDE Dev C++ e de uma funcionalidade de todas as IDEs (não conheço nenhuma que não tenha): a detecção de erros de compilação.

    (Note que eu disse de compilação e não apenas erros. Existem outros erros que não são 'detectáveis' (ainda ;), como é o caso dos erros 'lógicos' (ou seriam, ilógicos?).

    Como uma IDE detecta um erro de compilação?

    Imagino que você tenha se feito esta pergunta (se não fez, deveria rsrs). Agora vem a resposta.
    Leia com atenção o texto abaixo:
    nÁo mãgicaê?simPle5m ais FÂcil. paRece~eq.ue

    Entendeu alguma coisa? Nem eu rsrs.

    Na verdade, o que eu queria escrever era:
    Não é mágica! É mais fácil que parece.

    Por que você conseguiu ler a frase na 2ª vez e não na 1ª ? Simples! Porque ela foi escrita de forma errada na 1ª vez.
    Então, como saber se uma frase está certa ou errada? O que controla isto?

    Sintaxe e análise sintática

    O C é uma linguagem de programação de computadores, assim como o Português (idioma) é uma linguagem de comunicação (é isso mesmo?). O que as duas tem em comum? Por serem linguagens, elas são reguladas para que todos que as usam se entendam entre si? Imagine se cada pessoa falasse ou escrevesse o Português da forma que bem entendesse? (Tem gente que o faz, mas, para efeito de estudo, vamos ignorar isso!) Ninguém iria se entender.
    O que regula uma linguagem é a SINTAXE.
    Existe uma padronização na linguagem. Se alguma coisa está fora dos padrões se diz que está errada (conta uma novidade).
    Para saber se algo está errado, é feita uma análise chamada de ANÁLISE SINTÁTICA. Que nada mais é que uma comparação do que está sendo escrito/dito com o padrão.

    Conhecendo os padrões

    Existem alguns padrões no Português que são conhecidos. Às vezes, são 'atropelados', mas que existem existem. (Eu mesmo devo ter cometido barbaridades neste texto!)
    Exemplo simples:
    Nomes próprios começam sempre com letra maiúscula - Maria e João.
    Existem muitos outros, que eu acredito que você conheça; pelo menos os mais comuns.

    A linguagem C também possui os seus padrões. É fazendo uma comparação com estes padrões que as IDEs conseguem encontrar os erros de compilação.

    Um outro fato que deve ser levado em conta nesta análise, já que o código fonte é um texto, é a estrutura do texto.
    Um texto deve ter uma estrutura definida. Você não conseguirá se fazer entender se não seguir esta estrutura.
    Um exemplo claro disto é o conceito de sinais de pontuação e parágrafo. Nós não pensamos com parágrafos (ou pensamos?)! Mas, tente escrever um texto longo sem parágrafos ou sinais de pontuação.

    No próximo post, veremos os padrões do C.

    terça-feira, 20 de outubro de 2009

    Instalando o Dev C++

    Está chegando a hora de começarmos a ver na prática toda a teoria que vimos até agora. Para isto é necessário instalar uma IDE (se não sabe o que é, veja aqui). A IDE que escolhemos para começar foi a Dev C++ da Bloodshed.
    Neste post veremos a sua instalação, algumas configurações (uma só por enquanto rsrs) e como utilizá-la. Lembrando que são conceitos iniciais. Para uma visão completa, visite a lista de perguntas frequentes na página do fornecedor, aqui, em inglês.

    Instalando o Dev C++ 5.0 beta (4.9.9.2)
    Se você ainda não baixou o Dev C++, pode fazê-lo agora aqui.
    Salve o arquivo no seu HD, e execute. Você verá uma tela como esta aqui abaixo (clique na imagem para ampliar).




    É só clicar no OK, e seremos levados a esta tela, onde podemos escolher a linguagem dos botões do programa de instalação (a linguagem dos menus do programa será configurada depois).


    Escolhida a linguagem, OK novamente. Próxima tela (Licença).

    Esta é a licença do Dev C++. Esta licença é chamada de GPL, detalhes sobre ela aqui. É só aceitar para dar início a instalação. Próxima tela (Tipo de Instalação).

    Usaremos a Full (com todos os componentes instalados, tem menos de 60MB); se você quiser pode escolher quais componentes instalar, mas só o faça se tiver certeza do que está fazendo, pois alguns componentes são essenciais para o correto funcionamento do programa. Depois de escolhido o tipo de instalação, ou os componentes a serem instalados, é só clicar em Seguinte.
    Próxima tela (Diretório de Instalação).

    Aqui você escolhe onde o Dev C++ será instalado. É sugerido um diretório padrão. Eu mantenho o sugerido. Mude se quiser. Agora é só clicar em Instalar. Próxima tela (Progresso da Instalação).
    Os arquivos do Dev C++ serão copiados para o seu HD. Esta tela mostra o progresso deste processo. Próxima tela (Usuários).
    Deseja que os atalhos para o Dev C++ sejam instalados para todos os usuários? (Este programa é muito educado, não faz nada sem perguntar se pode rsrs). Próxima tela (Concluindo).

    Agora parece que acabou (pelo menos, é o que está dizendo ;)! Pode clicar em Terminar. Próxima tela (Configurações Iniciais).

    É aqui que será escolhida a linguagem dos menus do programa. Escolha a que lhe agradar (ju flasin shqip???). Se quiser pode mudar o tema (aparência) do programa. Depois de mudar o que desejar, clique em Next. Próxima tela (Funcão 'Auto-ajuda').

    O Dev C++ possui uma função 'Auto-ajuda', que dá sugestões para completar o código de funções comuns do C/C++ (veremos isto depois); para isto, ele faz uma pesquisa em certos arquivos, o que necessita de um pouco mais de processamento do computador (consumo de CPU e memória). Mantendo a educação de sempre, ele pergunta se você quer ativar esta função. Eu, particularmente, gosto muito desta função. Faça sua escolha e clique em Next. Próxima tela (Indexação).

    Se você escolheu usar a 'Auto-ajuda', é necessário fazer uma indexação (criação de atalhos para encontrar informações mais facilmente; isto é uma 'tradução' minha, se estiver errado, me corrijam). Você pode fazer agora ou depois. Se escolher fazer agora, se prepare para esperar um pouco (comigo nunca passou de 6 minutos, e isto em um 'dinossauro'). Clique em Next. Próxima tela (Indexando).

    Espere e confie rsrs. Próxima tela (Acabou???)

    Agora sim, acabou. Seu Dev C++, está com a configuração padrão, pronto para usar. Clique em OK.

    Esta é a 'cara' do Dev C++.

    Dica do dia. Você sabia... Qual a sua sorte hoje? rsrs.
    Fique a vontade para ler as dicas (algumas não serão tão claras ainda). Depois clique em Fechar.

    Agite antes de usar.

    Agora que o Dev C++, já está instalado, vamos fazer uma pequena mudança na configuração padrão que será muito útil depois (pode acreditar que você vai agradecer).
    Clique em Ferramentas, e a sua tela ficará como a figura abaixo.


    Clique agora em Opções do Editor. Na tela que se abre, clique em Display.

    E marque a opção Número das Linhas. Pode clicar em Ok.
    Com isto o Dev C++ vai numerar as linhas do nosso código fonte. Por quê? Você vai ver daqui a pouco.

    Criando um novo código fonte.

    Para criar um novo código fonte, é só clicar em novo e escolher Arquivo Fonte, ou usar o atalho Ctrl+N. Poderíamos criar um novo projeto; mas, como estamos começando, vamos dar um passo de cada vez: Arquivo fonte já é o suficiente.

    Um exemplo de Arquivo fonte.


    Este é um arquivo fonte em C. Repare que o nome dele é ex1.c.
    Arquivos da linguagem C, geralmente, e preferencialmente, tem extensão .c
    Arquivos da linguagem C++, extensão .cpp


    Compilando um código fonte:
    O Dev C++ é uma IDE, e portanto, possui um compilador 'integrado' (não necessariamente, se você escolheu não instalar o compilador, ignorando a sugestão do Dev C++).
    Para compilar o código fonte, você pode clicar no menu Executar e depois em Compilar, ou usar o atalho Ctrl+F9, ou clicar no 1º ícone da 2ª barra de ferramentas (os 4 quadradinhos coloridos separados).
    Se você ainda não salvou o código fonte, o Dev C++ recomenda que você o faça antes de compilar (conselho: Aceite a sugestão). Um vez feito isto, o programa compilado será salvo no disco no mesmo diretório onde você salvou o código fonte.
    Compilei, mas não aconteceu nada! Onde foi que eu errei???
    Acredito que em nada. Lembra que falei que o computador só faz o que é mandado? Você mandou compilar, e não executar!
    Para compilar e executar, é só clicar em Compilar & Executar, ou usar o atalho F9 (sem o Ctrl), ou clicar no 3º botão da 2ª barra de ferramentas (agora os 4 quadrinhos coloridos estão 'grudados'). Feito isto deve aparecer uma tela como esta abaixo.

    Tela preta e com letras brancas??? Cadê os ícones, janelas e botões do Windows???
    Não fique frustrado! Você ainda fará um programa com a 'cara' do Windows (aguarde e confie, e acima de tudo não se desanime).
    Lembra das nossas analogias? Vou usar outra agora.
    Quantos filmes você já viu? Já reparou que o 'mocinho' sempre está arrumadinho, mesmo depois de saltos, explosões, tiros, etc.? Sabe por quê?
    Porque não é ele que salta, que fica no meio do fogo, dos tiros. Quem faz isto é um dublê!
    No computador; aquelas janelas, botões e ícones são o 'mocinho', e esta 'tela preta' é o dublê.
    Quem assiste o filme no cinema não vê o dublê, mas quem está dirigindo o filme, sabe da existência dele e, inclusive, dá as instruções do que ele tem que fazer.
    Nós estamos criando os programas, 'fazendo o filme'. Por isto vemos o dublê.
    Mais tarde, vamos aprender a esconder este 'dublê' dos olhos do grande público.
    Mas, voltando ao tema deste post, vamos ver o porquê daquela alteração que fizemos na configuração do Dev C++, para que ele numerasse as linhas para nós.

    Poderíamos ter feito o nosso código fonte em qualquer editor de texto não-formatado. O editor do Dev C++ além de ser não-formatado, tem ainda algumas funções adicionais que facilitam a nossa vida de programador, por exemplo a numeração das linhas.
    Outra função essencial é a indicação de erros no código fonte.
    Propositalmente, introduzi um erro no código fonte que estamos usando como exemplo neste post. Se tentarmos compilar esta versão com erro, nossa tela ficará assim:
    Tá notando a linha marcada em vermelho? E o quadro que apareceu na parte inferior da tela?
    Eles são a forma que o Dev C++ usa para 'mostrar' onde está o erro. Note que ele informa o número da linha e o erro que ela apresenta. Neste caso: syntax error before "valor2" (erro de sintaxe antes de "valor2"). Um erro da linha anterior que se refletiu na seguinte.
    Como as linhas estão numeradas fica muito mais fácil de encontrar o erro. Neste código simples, talvez não fosse necessário, mas imagine se este código tivesse 1.000 ou 2.000 linhas? (o que não é nenhum absurdo.)
    Que erro foi este?

    Assunto para o próximo post.