A linguagem c não possui um tipo de dado booleano, então de que forma ele trada o que é verdadeiro e falso?
Sabe-se que para a linguagem C tudo o que tiver valor 0 é falso e tudo o que for diferente de 0 é verdadeiro.
Para fins de demonstração recorrerei a dois exemplos.
O primeiro exemplo apresenta o valor numérico de duas expressões lógicas, uma verdadeira e outra falsa.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char sexo = 'F';
007:
008: printf("sexo igual a F: %d\n", sexo == 'F');
009: printf("sexo igual a M: %d\n", sexo == 'M');
010: system("PAUSE");
011: return 0;
012: }
A saída produzida pelo programa deve ser
sexo igual a F: 1
sexo igual a M: 0
Como o sexo vale F, quando é feita a relação entre sexo e M, o resultado é falso(0). Quando a relação é estabelecida entre sexo e F, o resultado é verdadeiro (diferente de 0, nesse caso 1).
O segundo exemplo é para provar que valores diferentes de zero são considerados verdadeiros.
A estrutura de decisão if (se) avalia uma variável ou expressão e decide se executará seu bloco verdade ou seu bloco falsidade.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: int valor;
008:
009: printf("Digite um valor inteiro: ");
010: fflush(stdin);scanf("%d", &valor);
011: if(valor)
012: {
013: printf("Valor diferente de zero: %d\n", valor);
014: }
015: else
016: {
017: printf("Valor igual a zero: %d\n", valor);
018: }
019: system("PAUSE");
020: return 0;
021: }
Na execução do programa, se você digitar 0, a saída do programa é
Valor igual a zero: 0
ou seja a instrução if (valor), pode ser traduzida para if(0), ou ainda, em português estruturado se falso então. Isso sempre executara o bloco else do if.
Quando você digita um valor diferente de zero, suponha 5, a saída esperada é
Valor diferente de zero: 5
então a instrução if (valor), é equivalente a if (5), que equivale a se verdade então.
Espero que as demonstrações sejam suficientes para você guardar que 0 é falso e diferente de zero é verdadeiro. :-D
quarta-feira, 27 de fevereiro de 2008
Verdadeiro e falso
Operadores relacionais
Os operadores relacionais estabelecem uma relação (Não poderia ser mais óbvio!) entre seus operandos.
Essa relação pode ser de:
- (==) igualdade
- (!=) diferença
- (>) maior que
- (<) menor que
- (>=) maior ou igual a
- (<=) menor ou igual a
É interessante saber que o resultado de uma expressão relacional é sempre lógico, ou seja, retorna verdadeiro ou falso.
Analisando a equação relacional
X == 7;
concluímos que o resultado será verdadeiro para X igual a 7 e falso para X diferente de 7.
Algumas vezes a análise não é tão simples assim. Por exemplo:
X > 7;
O resultado será verdadeiro para qualquer valor real maior ou igual a 7.
Quando o resultado será falso? Alguns respondem, de primeira, quando X for menor que 7 e esquecem que quando X é igual a 7 o resultado da expressão também é falso.
A resposta correta é quando X for menor ou igual a 7.
Sempre que deparar com uma relação, tente identificar os conjuntos de valores que a tornam verdadeira e falsa, assim você terá domínio maior sobre o problema.
segunda-feira, 25 de fevereiro de 2008
O scanf engana
Quando falei sobre a função scanf, chamei a atenção para a limpeza do buffer do teclado.
Naquele momento enfatizei que limpar o buffer do teclado evitaria algumas dores de cabeça.
Execute o código abaixo e verifique o seu funcionamento.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char chr1, chr2;
007:
008: printf("Digite o primeiro caractere: ");
009: scanf("%c", &chr1
010: printf("Digite o segundo caractere: ");
011: scanf("%c", &chr2);
012: printf("Primeiro caractere %c\nSegundo caractere: %c\n", chr1, chr2);
013: system("PAUSE");
014: return 0;
015: }
Não fique nervoso tentando digitar o segundo caractere. Esse problema é bastante comum nos códigos de programadores pouco experientes. Tente limpar o buffer do teclado, utilizando a instrução fflush(stdin) antes de cada scanf. Você verá que agora o segundo caractere é lido.
Por que isso ocorre? Imagine o buffer do teclado como um arquivo seqüencial, onde o scanf retira os dados.
Para o exemplo anterior, na linha 9, o scanf espera que você digite um byte (estamos lendo variáveis do tipo char). O que você faz? Digita o caractere e em seguida o enter. Supondo que você digitou o caractere V, o buffer do teclado fica:
V\n
O \n representa o enter.
Após a execução da linha 9, o caractere V é armazenado na variável chr1, deixando o \n no buffer do teclado. Adivinhe que receberá o \n? Correto, a variável chr2. Por esse motivo ela não é lida!
Quando você usa a instrução fflush(stdin), e limpa o buffer do teclado, o \n sai do buffer, deixando ele limpo para a próxima leitura.
Operadores aritméticos
A linguagem C disponibiliza cinco operadores aritméticos binários.
- (+) soma
- (-) subtração
- (*) multiplicação
- (/) divisão
- (%) resto de uma divisão entre inteiros
Os operadores binários recebem esse nome porque necessitam de dois operandos para que a operação exista.
x = a + b;
Nem todas as operações são binárias. A linguagem C disponibiliza a operação menos unário, a qual necessita somente de um operando para existir.
x = -a;
O menos unário é equivalente a multiplicação por -1. Estere aí! Na multiplicação por -1 não estamos empregando o menos unário no operando 1. Olhe o código abaixo e conclua!
x = -1 * a;
Todas as operações são aplicadas a números inteiros e de ponto flutuante, com exeção do resto.
O conceito de resto de uma divisão só existe quando falamos em números inteiros, portanto o operador % exige que seus operandos sejam do tipo int ou char.
De todas as operações, a mais ingrata é a divisão.
Você é capaz de responder o que será impresso pelo seguinte código?
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: int a = 5, b = 2;
007: float c;
008: c = a/b;
009: printf("O resultado da divisao e: %f", c);
010: system("PAUSE");
011: return 0;
012: }
Se você pensou em 2.5, você pensou errado! O resultado é 2.0. Na linguagem C, a divisão entre dois inteiros, resulta em resultado inteiro, portando o resultado da divisão entre cinco e dois, é dois.
Se a sua intensão é apresentar o resultado real da divisão então, ao menos um dos operados deverá ser de ponto flutuante. Para isso recorro a utilização do cast que faz a conversão momentânea do dado.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: int a = 5, b = 2;
007: float c;
008: c = (float)a/b;
009: printf("O resultado da divisao e: %f", c);
010: system("PAUSE");
011: return 0;
012: }
Você pode ver a utilização do cast (float) na linha 8. Isso transforma o dado da variável a em float então este dado é dividido por 2. O resultado dessa operação é o 2.5.
Em resumo, os operadores aritméticos são tranqüilos de usar. O cuidado maior está sempre na divisão.
sexta-feira, 22 de fevereiro de 2008
lendo dados - a função scanf
Agora que você sabe como funciona o operador de endereço &, posso apresentar a você a função scanf (leia-se scanEFE).
Essa função, como a printf, está localizada na biblioteca stdio.h e serve como entrada de dados em seu programa. Tudo aquilo que você digita no teclado será lido por essa função.
É claro que para o scanf você deverá informar duas coisas:
- Em qual formato o dado será lido?
- Onde ele será armazenado?
Para informar o formato do dado para o scanf é necessário recorrer a tabela abaixo:
| Código | Formatação |
| %c | Lê um caractere |
| %d | Lê um inteiro positivo ou negativo (base decimal) |
| %i | Lê um inteiro positivo ou negativo (base decimal) |
| %e | Lê um número de ponto flutuante em notação científica |
| %f | Lê um número de ponto flutuante |
| %g | Lê um número de ponto flutuante podendo ser expressa em notação científica |
| %o | Lê um número em octal |
| %s | Lê uma cadeia de caracteres (string) |
| %u | Lê um inteiro sem sinal |
| %x | Lê um número hexadecimal |
| %n | Recebe um valor inteiro correspondente ao número de caracteres lidos até então |
| %[] | Busca por um conjunto de caracteres |
A resposta genérica para a segunda pergunta é a memória. Devemos especificar para o scanf qual o endereço de memória ele deve guardar o dado inserido. Para essa operação utiliza-se o operador de endereço &.
A forma geral do scanf é:
scanf("código de formatação", lista de endereços);
Para ler duas variáveis, sexo e anoNascimento podemos fazer como no programa abaixo.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char sexo;
007: int anoNascimento;
008: printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\n");
009: scanf("%c",&sexo);
010: printf("Digite o ano de nascimento: ");
011: scanf("%d",&anoNascimento);
012: system("PAUSE");
013: return 0;
014: }
Note que nas linhas 9 e 11 o código de formatação indica somente o tipo de dado a ser lido.
O scanf permite ler mais de uma variável na mesma instrução. Adaptando o programa acima para ler em apenas uma instrução fica da seguinte forma:
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char sexo;
007: int anoNascimento;
008: printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\nEm seguida digite o ano de nascimento.");
009: scanf("%c%d",&sexo, &anoNascimento);
010: system("PAUSE");
011: return 0;
012: }
Particularmente não gosto dessa segunda opção porque não permite a limpeza do buffer do teclado entre uma leitura e outra. A limpeza é importante pois garante que nenhuma sujeira presente no buffer contaminará suas variáveis.
Para fazer a limpeza do buffer basta inserir a instrução
fflush(stdin);
antes de cada scanf.
Veja o primeiro programa escrito de uma forma mais segura.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char sexo;
007: int anoNascimento;
008: printf("Digite o sexo\n[F] - Feminino\n[M] - Masculino\n");
009: fflush(stdin);
010: scanf("%c",&sexo);
011: printf("Digite o ano de nascimento: ");
012: fflush(stdin);
013: scanf("%d",&anoNascimento);
014: system("PAUSE");
015: return 0;
016: }
Agora sim, ler dados ficou ainda mais fácil!
quinta-feira, 21 de fevereiro de 2008
Operador de endereço
Quando falei sobre criação e inicialização de variáveis, falei também que cada variável recebe uma casa, chamada de memória.
Como toda casa possui um endereço (Rua, número, bairro, cidade, estado, país, CEP), a memória possui um endereçamento, muito mais simplificado, composto por números.
Esses números indexam a memória byte-a-byte.
Vamos recorrer ao exemplo abaixo para compreender melhor:
| Endereço | 2048 | 2049 | 2050 |
| Identificador | sexo | anoNascimento | |
| Valor | 'F' | 1982 | |
O exemplo representa um fragmento de memória, na qual estão presentes duas variáveis identificadas por sexo e anoNascimento. Pelo número de bytes alocados para cada variável e, com o auxílio da tabela de limites mínimos de variáveis, pode-se concluir que sexo é do tipo char e anoNascimento é inteiro.
Quando pergunto qual o endereço de sexo, a resposta deve ser 2048. Quando pergunto qual o endereço de anoNascimento, a dúvida impera!
Alguns respondem 2049, outros 2050, um grupo isolado arrisca 2049 e 2050. A resposta correta é 2049. O endereço de uma variável que ocupa mais de um byte é o menor endereço do bloco de memória ocupado pela variável. O bloco ocupado por anoNascimento é 2049-2050, portanto o menor endereço desse bloco é 2049.
Na linguagem C a forma utilizada para descobrir o endereço de uma variável é por meio do operador &.
O programa abaixo ilustra como se utiliza o operador & para imprimir na tela o endereço de uma variável.
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: char sexo = 'F';
007: int anoNascimento = 1982;
008:
009: printf("O endereco de sexo e %p\n", &sexo);
010: printf("O endereco de anoNascimento e %p\n", &anoNascimento);
011: system("PAUSE");
012: return 0;
013: }
Com base no fragmento de memória apresentado anteriormente, a saída esperada para esse programa é:
O endereço de sexo e 2048
O endereço de anoNascimento e 2049
Você deve estar se perguntando... Quando usarei esse operador?
Primeiramente na função scanf, utilizada na leitura de dados do teclado, e mais a frente em passagem de parâmetros por referência (o que é feito na função scanf) e no uso de ponteiros.
A propósito, a passagem de parâmetro por referência é feita utilizando ponteiros. :D
segunda-feira, 18 de fevereiro de 2008
A função printf()
No post Meu primeiro programa em C, apresentei o uso da função printf em sua forma mais ordinária. Aquela em que a utilizamos para apresentar mensagens fixas, como a apresentada abaixo.
printf("Uma mensagem para voce!");
Nessa forma não existem códigos de formatação.
Os códigos mais básicos servem para controlar tabulações, quebras de linhas, impressão de aspas, etc..., e são iniciados pela barra invertida seguida de um caractere.
A tabela abaixo apresenta esses códigos.
| Código | Significado |
| \n | Quebra de linha (Pula para a próxima linha) |
| \r | Retrocede o cursor para o início da linha |
| \t | Insere uma tabulação no texto |
| \b | Retrocede o cursor uma posição |
| \" | Imprime a aspas |
| \\ | Imprime uma barra invertida |
Existem códigos de formatação para a impressão de variáveis. Não seria ótimo apresentar um número no meio de uma mensagem, por exemplo:
O numero 2 e par.
O programa que gera essa saída pode ser dado por:
001: #include <stdio.h>
002: #include <stdlib.h>
003:
004: int main(int argc, char *argv[])
005: {
006: int num = 2;
007:
008: printf("O numero %d e par\n", num);
009: system("PAUSE");
010: return 0;
011: }
Esse raciocínio é válido para todos os tipos de dados. A tabela abaixo apresenta o código de formatação e o formato impresso:
| Código | Formatação |
| %c | Caractere |
| %d | inteiros com sinais (base decimal) |
| %i | inteiros com sinais (base decimal) |
| %e | Notação científica (e minúsculo) |
| %E | notação científica (E maiúsculo) |
| %f | ponto flutuante |
| %g | usa %f ou %e, o que for mais curto graficamente |
| %G | usa %f ou %E, o que for mais curto graficamente |
| %o | imprime um número em base octal |
| %s | cadeia de caracteres (string) |
| %u | inteiros sem sinal |
| %x | imprime um número na base hexadecimal. As letras serão minúsculas. |
| %X | imprime um número na base hexadecimal. As letras serão maiúsculas. |
| %p | Apresenta endereço de memória. |
Se você é um pouco perspicaz estará se perguntando como fazer para imprimir o sinal de %. Isso é fácil, basta duplicar o sinal de percentual (%%) no printf.
Se você acha que acabou, aguarde o post sobre a formatação de precisão e campos utilizando o printf.
Identificadores
O nome que damos a uma função ou variável é chamado de identificador.
Os identificadores são fundamentais na compreensão do programa. Para isso devemos escolher identificadores significativos, que indiquem exatamente o papel que a função ou variável desempenha no sistema.
Uma variável que armazena, por exemplo, o peso de um paciente pode ser identificada por pesoPaciente. Lendo somente o identificador podemos deduzir o que essa variável faz.
Procure resistir à tentação de criar identificadores engraçados ou sem significado. Eles prejudicam a leitura do programa e, conseqüentemente, aumentam o tempo de manutenção.
Para funções, é interessante demonstrar que ela executa uma ação. Uma função que calcula o imposto de renda sobre um rendimento qualquer poderá ser identificada como calcularImpostoDeRenda. Note que a primeira palavra é um verbo que se apresenta no infinitivo. Essa característica reforça a execução de uma ação pela função (calcular). As demais palavras indicam qual o objetivo da ação (imposto de renda). Os objetos da ação serão tratados como parâmetros da função. Se você não sabe o que é uma função, acalme-se, em breve eu a apresentarei a você.
A linguagem C exige uma regra para a criação de identificadores. Ela é muito simples, mas ainda é uma regra....
O primeiro caractere deve ser letra ou sinal de sublinha ( _ ). Os demais caracteres podem ser letras, números ou sinal de sublinha, portanto, identificadores como 1peso ou @email estão errados.
Algumas coisas que você deve lembrar:
Os identificadores não devem coincidir com palavras reservadas da linguagem, portanto se você gosta da palavra switch, lamento decepcioná-lo, mas ela é uma palavra reservada.
A linguagem C distingue letras maiúsculas de minúsculas, ou seja ela é sensível ao caso. Essa característica implica em uma variável pesoPaciente diferente de PesoPaciente.
Agora a criação de identificadores é uma tarefa mais fácil.
sexta-feira, 15 de fevereiro de 2008
Criação e inicialização de variáveis
Na linguagem C a criação de variáveis é bastante simples. O comando de criação é formado pelo tipo de dados seguido de uma ou mais variáveis que assumirão aquele tipo e termina-se o comando com o famoso ponto-e-vírgula.
Ex.: Para criar uma variável do tipo char podemos fazer:
char opcao;
Por esse comando sabemos que existe no programa uma variável chamada opção que manipula dados do tipo char.
Para declarar uma lista de variáveis utilizamos o tipo de dado seguido dos identificadores das variáveis separados por vírgula e, finalmente, o término do comando dado pelo ponto-e-vírgula.
Ex.: Para criar uma lista de variáveis do tipo float podemos fazer:
float proventos, despesas, saldo;
Com base na linha anterior, podemos constatar que no programa existirão três variáveis de ponto flutuante que armazenarão valores relativos a proventos (dinheiro que entra em seu fluxo de caixa, tal como salário), despesas (aquilo que você gasta) e saldo (diferença entre proventos e despesas).
Agora que você sabe como criar variáveis vamos a inicialização delas. Vou contar uma estória triste. Quando uma variável nasce, ela recebe uma casa (chamada de memória) suja. A sujeira na casa da variável é representada por um valor aleatório e que, se não for limpa, poderá ser a causa de grandes problemas para o seu programa. Casa limpa é sinônimo da saúde.
A inicialização pode ocorrer no momento da criação da variável, por exemplo:
float proventos=0, despesas=0, saldo=0;
Isso indica que as três variáveis declaradas anteriormente são iniciadas com o valor 0. Agora sei que nelas existe um valor conhecido e não sujeira de memória.
Duas perguntas são freqüentes nesse tema:
- Sou obrigado a inicializar uma variável?
A inicialização é obrigatória quando a variável é utilizada para auto-alteração (auto-incremento, auto-decremento, auto-multiplicação, auto-etc...).
- O valor a ser utilizado na inicialização é sempre zero?
multiplicadora = multiplicadora * fatorCorrecao;
multiplicadora = multiplicadora * juros;
Se multiplicadora for inicializado com 0, o resultado final dessa operação será sempre 0. Então multiplicadora deverá ser inicializada com um número neutro no contexto da multiplicação. O valor que procuramos é o 1. Eu sempre digo que o valor inicial de uma variável depende do seu uso futuro.
Espero que tenha compreendido que declarar uma variável é mais do que escrever uma simples linha de código.
Tipos básicos de dados na linguagem C.
Os tipos de dados são utilizados para assinalar qual será a forma de tratamento dispensada ao dado em memória ou outro sistema de armazenamento de dados.
A linguagem C possui cinco tipos básicos de dados:
- char
- int
- float
- double
- void
Com exceção do void, os tipos em linguagem C são todos numéricos e podem ser aplicadas às operações aritméticas disponíveis no C, com ressalvas ao operador de módulo.
O tipo void é utilizado como retorno de funções e tipo de ponteiros.
Os tipos char e int são utilizados para armazenar números inteiros negativos e positivos. O tipo int utiliza mais bytes para armazenamento que o char, o que lhe proporciona maior faixa de valores.
Os tipos float e doube armazenam números de ponto flutuante (números reais). O double utiliza maior número de bytes que o float, o que proporciona maior faixa de valores e ainda, maior precisão numérica.
A American National Standard Institute (ANSI) padroniza os valores mínimos para os tipos de dados do C. O compilador que você utiliza deve seguir esse padrão!
Abaixo está a tabela de tipos com seus respectivos tamanhos e faixa de valores padronizada pela ANSI.
| Tipo | Tamanho (*) | Faixa mínima | |
| char | 1 | -127 a 127 | |
| int | 2 | -32.767 a 32.767 | |
| float | 4 | Seis dígitos de precisão | |
| double | 8 | Dez dígitos de precisão | |
| void | 1 | - | |
| * Valor aproximado em bytes. | |||
quinta-feira, 14 de fevereiro de 2008
Anatomia do programa em C.
No tópico "C - Meu primeiro programa!" apresentei um programa simples que dizia "Estou vivo....!" para quem mexia com ele!
Vamos entender o seu funcionamento.
001: #include <stdio.h>
002:
003: int main(int argc, char *argv[])
004: {
005: printf("Estou vivo....!");
006: return 0;
007: }
Quando você executa um programa no sistema operacional, dentre aquele amontoado de código de máquina, existe um especial, que indica onde o sistema operacional deverá iniciar a execução do programa.
A linguagem C marca esse ponto com a função main, a qual pode ser vista na linha 3. A palavra reservada int que precede o main é o tipo de retorno da função. Isso indica que o main deverá retornar um valor inteiro. Veja na linha 6 o que está acontecendo... O main retorna para o sistema operacional o valor 0 por meio da palavra reservada return.
Voltando a linha 3, após o main, estão presentes os argumentos da função. Esses argumentos aparecem entre parênteses e são separados por vírgulas. Existirá um momento oportuno onde mostrarei como esses argumentos podem ser explorados.
Na linha 4, é aberta uma chave que marca o início da função main. Na linha 7 a chave que fecha, marca o fim da função.
Na realidade as chaves marcam um bloco de comandos, nesse caso um bloco de comandos
da função main, e elas existirão aos montes em seus programas. Acostume-se a elas e lembre-se que para cada chave aberta deverá existir uma fechada.
A única linha que faz algo realmente sensível é a 5, a qual contém a chamada a função printf. Veja que o argumento da função printf "Estou vivo....!" é o que vemos quando executamos o programa. Altere o argumento para "Estou corrompendo o seu sistema de arquivos...", compile e execute o programa novamente. Pode executar... Será muito, muito divertido!
O que aconteceu? Seu sistema foi corrompido? Não! Claro que não! Você está produzindo somente mensagens que o programa fornece ao usuário.
A função printf faz parde da biblioteca stdio.h. stdio vem de standard input/output e é nessa biblioteca que estão declaradas as funções de entrada e saída padrões do C. Para ter acesso a a elas, utilizamos a diretiva #include apresentada na linha 1.
Acho que estendemos demais nesse tópico. Para finalizá-lo você é capaz de responder as seguintes perguntas?
1. Qual o comando que exibe mensagens aos usuários?
2. Em qual biblioteca estão localizadas as funções de entrada de dados?
3. O que pode significar função main (main function)?
4. Quando você usará os argumentos da função main?
5. A função main retorna sempre zero?
6. A mensagem que um programa fornece reflete fielmente o que está sendo executado por ele?
quarta-feira, 13 de fevereiro de 2008
C - Meu primeiro programa!
O primeiro programa em C é como o seu primeiro sutien. Você nunca esquece!
Nunca tive um sutien, mas, bem.... O meu primeiro programa em C não esqueci e portanto,você não deverá esquecer o seu!
Vamos a ele!
001: #include <stdio.h>
002:
003: int main(int argc, char *argv[])
004: {
005: printf("Estou vivo....!");
006: return 0;
007: }
O resultado da execução desse programa é apresentado abaixo:
Estou vivo....!
Viu como é simples!
Sei que parte desse código pode parecer grego. Para entendê-lo melhor é necessário dissecá-lo.Em breve veremos a anatomia de um programa em C.