Baixe o app para aproveitar ainda mais
Prévia do material em texto
Centro de Ciências Exatas, Ambientais e de Tecnologias Faculdade de Análise de Sistemas Curso de Sistemas de Informação Algoritmos e Programação para Computadores I 1 o Semestre de 2014 Prof. André Luís dos R.G. de Carvalho Índice ÍNDICE .................................................................................................................................................................. 2 COMUNICAÇÃO E LINGUAGEM ................................................................................................................... 4 ALGORITMOS E RESOLUÇÃO DE PROBLEMAS ...................................................................................... 7 ALGORITIMOS E COMPUTADORES .......................................................................................................... 13 INCLUSÃO DE BIBLIOTECAS ....................................................................................................................... 14 UM PROGRAMA ............................................................................................................................................... 14 COMANDOS ....................................................................................................................................................... 14 SAÍDA BÁSICA ................................................................................................................................................... 14 COMENTÁRIOS ................................................................................................................................................ 15 VARIÁVEIS ........................................................................................................................................................ 16 IDENTIFICADORES ......................................................................................................................................... 17 TIPOS BÁSICOS ................................................................................................................................................ 17 DECLARAÇÃO DE VARIÁVEIS .................................................................................................................... 17 ENTRADA BÁSICA ........................................................................................................................................... 18 EXPRESSÕES ..................................................................................................................................................... 19 OPERADORES ARITMÉTICOS CONVENCIONAIS ................................................................................................... 20 OPERADORES RELACIONAIS .............................................................................................................................. 21 OPERADORES LÓGICOS ..................................................................................................................................... 21 CONVERSÕES DE TIPO ....................................................................................................................................... 21 O COMANDO DE ATRIBUIÇÃO .................................................................................................................... 22 BLOCOS DE COMANDO ................................................................................................................................. 23 O COMANDO IF ............................................................................................................................................... 23 O COMANDO SWITCH ...................................................................................................................................... 25 ACUMULAÇÃO DE VALORES ...................................................................................................................... 28 O COMANDO WHILE ........................................................................................................................................ 31 FUNÇÕES ........................................................................................................................................................... 32 O COMANDO DO-WHILE ................................................................................................................................. 34 O COMANDO FOR ............................................................................................................................................. 36 MAIS SOBRE EXPRESSÕES ........................................................................................................................... 39 OPERADORES DE INCREMENTO E DECREMENTO ............................................................................................... 39 OPERADORES DE BIT ......................................................................................................................................... 40 OPERADOR DE ATRIBUIÇÃO COM OPERAÇÃO EMBUTIDA .................................................................................. 40 EXPRESSÕES CONDICIONAIS .............................................................................................................................. 41 MAIS SOBRE FUNÇÕES .................................................................................................................................. 42 PARÂMETROS POR REFERÊNCIA ........................................................................................................................ 42 RECURSÃO ........................................................................................................................................................ 43 TIPOS PRIMITIVOS ......................................................................................................................................... 45 CONSTANTES .................................................................................................................................................... 47 CONSTANTES LITERAIS...................................................................................................................................... 48 Constantes Literais do Tipo Inteiro ............................................................................................................. 48 Constantes Literais do Tipo Real ................................................................................................................ 48 Constantes Literais do Tipo Caractere ........................................................................................................ 49 Constantes Literais do Tipo String .............................................................................................................. 50 CONSTANTES SIMBÓLICAS ................................................................................................................................ 50 SAÍDA DE DADOS ............................................................................................................................................. 50 ENTRADA DE DADOS...................................................................................................................................... 54 O COMANDO CONTINUE ................................................................................................................................. 55 O COMANDO BREAK ........................................................................................................................................ 55 O COMANDO GOTO .......................................................................................................................................... 56 EXERCÍCIOS PROPOSTOS ............................................................................................................................57 EXERCÍCIOS DE SEQÜENCIA ...................................................................................................................... 57 EXERCÍCIOS DE IF .......................................................................................................................................... 58 EXERCÍCIOS DE SWITCH ................................................................................................................................ 59 EXERCÍCIOS DE REPETIÇÃO ...................................................................................................................... 59 EXERCÍCIOS DE SUBPROGRAMA .............................................................................................................. 61 EXERCÍCIOS DE MACRO .............................................................................................................................. 61 EXERCÍCIOS DE RECURSÃO ........................................................................................................................ 61 Algoritmos Página 4 Comunicação e Linguagem Quando duas pessoas tentam se comunicar, elas precisam usar uma linguagem comum às duas, ou seja, uma forma de comunicação que as duas entendam. Para realizar a comunicação entre uma pessoa e um computador, o processo é semelhante. O computador é uma máquina construída de tal forma que pode processar informações. Tais informações são representadas dentro dele por meio de impulsos elétricos altos e baixos, formando assim configurações de valores 1 (impulso alto) e de valores 0 (impulso baixo). Essas configurações são códigos que representam as informações para o computador, da mesma maneira que as letras do alfabeto, quando agrupadas, podem representar informações na nossa linguagem. Essa linguagem de impulsos elétricos é a linguagem que um computador entende. Abaixo temos uma ilustração desse conceito, indicando como a maioria dos computadores representa letras e dígitos. As linhas horizontais e verticais indicam a altura dos impulsos elétricos: 1 0 0 0 0 0 0 1 Letra ‘A’ (65 em decimal) 0 0 1 1 0 1 1 1 Dígito (algarismo) ‘7’ (55 em decimal) É óbvio que um ser humano não sabe usar esta linguagem de impulsos elétricos. Assim, deve- se procurar meios de traduzir a linguagem humana para a linguagem de máquina usada por um computador. Isto é feito por meio de Linguagens de Programação. Com uma Linguagem de Programação, uma pessoa pode escrever programas, que nada mais são de que ordens, colocadas numa sequência lógica, para o computador executar. Executar um programa significa que a série de ordens descritas pelo programa serão efetuadas pelo computador. Algoritmos Página 5 Assim, é possível estabelecer contato com uma máquina capaz de receber as ordens, efetuá-las e apresentar respostas ao operador. Um programa é, portanto, um conjunto de instruções que são fornecidas a um computador para que ele as entenda e execute. A seguir, temos dois pequenos exemplos de Programa, escrito nas linguagens Pascal e C: Program Exemplo; Uses CRT; { Declaração de Variáveis } Var A, B, Soma: Integer; Begin { Programa Principal } Write('Digite o valor A:'); Read(A); Writeln; { Muda de Linha } Write('Digite o valor B:'); Read(B); Writeln; Soma := A + B; Write('Soma = ',Soma); End. int main() { /*Declaração de Variáveis*/ int a, b, soma; printf("Digite o valor A:"); scanf("%i",&a); printf("\n"); /* Muda de Linha */ printf("Digite o valor B:"); scanf("%i",&b); printf("\n"); soma = a + b; printf("Soma = %i",soma); } Na verdade, o computador não entende o que significam essas palavras, já que sua linguagem é composta apenas pelos impulsos elétricos altos e baixos que citamos. Para que o computador “entenda” o programa, deve haver uma tradução. A fase de tradução é feita por meio de um outro programa que já existe no sistema do computador, chamado COMPILADOR. Ele traduz as instruções da pessoa que escreveu o programa (programador) para a linguagem de máquina. Geralmente, um programa pode ser escrito em qualquer linguagem de programação. Uma linguagem de programação é uma linguagem artificial, criada com certas regras rígidas em termos de sintaxe (como escrever) e semântica (significado do texto escrito). Tais regras devem ser seguidas para que o compilador possa fazer corretamente a tradução para a linguagem de máquina. No exemplo acima, os dois programas efetuam a leitura de dois valores e calculam a soma dos mesmos, escrevendo a seguir o resultado dessa soma. Algoritmos Página 6 Não importa neste momento como isso é feito. O importante é notar que cada linguagem tem seu vocabulário próprio. Por exemplo, para escrever uma mensagem em Pascal, usa-se o procedimento Write, e em C usa-se a função printf. No entanto, a “lógica”, ou a resolução do problema, é mesma para os dois programas: obter os valores a somar, efetuar a soma e escrever esse resultado. Um programa deve especificar instruções que possam ser executadas pelo computador, e que “resolvam” o problema passo a passo, como se resolve o problema proposto, seja este uma equação do 2o. grau, uma folha de pagamento, cálculos avançados, ou ainda uma simples soma de 2 valores inteiros, como vimos no exemplo. Esse é um outro aspecto interessante sobre as linguagens de programação. São linguagens artificiais, e são criadas por pessoas. Essas pessoas podem (e devem) especificar as características que atinjam os propósitos que as levaram a criar a linguagem. Quando Niklaus Wirth, em 1971, criou a linguagem Pascal estava interessado numa linguagem apropriada ao ensino de técnicas de programação. Já a linguagem COBOL, por exemplo, criada em 1959, foi orientada totalmente para o processamento de arquivos de dados administrativos. Com o desenvolvimento das teorias de Banco de Dados, surgiram linguagens voltadas ao processamento de bancos de dados, como SQL e Clipper. Hoje em dia, novas teorias de computação estão sendo aplicadas na criação de novas linguagenas e melhoramentos das atuais, como por exemplo a Orientação a Objetos e Orientação a Eventos. Existe também uma genealogia de linguagens. Por exemplo, a linguagem ALGOL foi baseada em PL/I, uma das primeiras linguagens estruturadas. Em seguida, ALGOL foi a base de Pascal e ADA. Outras linguagens não são procedurais como Pascal, ALGOL, C e FORTRAN, tendo outras características, como LISP e PROLOG, voltadas à Inteligência Artificial. Resumindo, uma linguagem de programação é o meio pelo qual um programador escreve um programa. Um programa é um conjunto de instruções para o computador executar, normalmente processando informações e escrevendo respostas sobre esse processamento. Algoritmos Página 7 Algoritmos e Resolução de Problemas Como vimos, é necessária uma linguagem de programação para que o computador entenda e resolva o problema proposto por uma pessoa. A linguagem permite que se realize uma forma de comunicação com o computador, por meio de conjuntos de instruções chamadas programas. Um programa, portanto, é uma sequência de instruções dadas ao computador para que ele as execute e obtenha um resultado. Este resultado depende diretamente das intruções fornecidas. Portanto, é muito importante que o programa esteja correto, para que o computador desenvolva corretamente as operações necessárias para a solução do problema desejado. Todo problema que tenha solução tem pelo menos um processoque deve ser seguido para se chegar a esta solução. Este processo é geralmente composto por uma sequência de operações (ou ações), ou regras. Ao processo de resolução de um problema dá-se o nome de ALGORÍTMO. Ou seja, algorítmo é um conjunto de ações que são usadas para resolver um problema, ou ainda, para se chegar a um objetivo. Como exemplo de problemas que têm algorítmos, pode-se destacar: 1. Somar dois valores 2. Abrir uma porta 3. Trocar pneu de um carro 4. Fazer um bolo 5. Trocar de roupa 6. Usar um telefone público As ações que são feitas para resolver cada um desses problemas constituem o algorítmo da resolução de cada problema. Como se vê, mesmo as coisas mais triviais que fazemos diariamente têm algorítmos, pois tudo o que fazemos tem um modo de ser feito (é óbvio), e este modo de fazer pode ser descrito com certas regras. O algorítmo do problema 1, somar dois valores, seria: 1. Início 2. Obter o 1o. valor e chamá-lo de A; 3. Obter o 2o. valor e chamá-lo de B; Algoritmos Página 8 4. Calcular o valor A + B e chamá-lo de SOMA; 5. Exibir SOMA; 6. Fim (Alg. 1) O algorítmo acima tem seis passos, ou ações. Todo algorítmo tem um Início e um Fim (passos 1 e 6, respectivamente), como tudo que se executa na vida. Os passos 2 e 3 são semelhantes; a única diferença entre eles é o destino dos valores obtidos em cada um. O primeiro valor é chamado de A para diferenciá-lo do segundo, identificado pela letra B. Assim, as letras A e B foram usadas para identificar valores. São, portanto, chamadas de IDENTIFICADORES. SOMA também é um identificador, e receberá o resultado da EXPRESSÃO A + B. O passo 5 mostra o resultado da soma; esta exibição, em termos de algorítmos para computador, pode ser em papel, em tela, ou em disco. Exibir é, portanto, uma intrução de saída, pois faz com que resultados sejam conhecidos fora do computador. Por outro lado, obter é uma instrução de entrada, pois faz com que valores externos sejam “lidos”, colocados dentro do computador. Isto será visto com mais detalhes adiante. Outra característica de um algorítmo é que certas ações precisam ser feitas antes de outras. Por exemplo, não se pode calcular o valor da soma antes de se obter os valores iniciais; da mesma forma, não se pode obter o segundo valor antes de se obter o primeiro. Portanto pode-se dizer que um algorítmo é um conjunto de ações executadas de forma ordenada e lógica, para se obter o resultado do problema apresentado. A sequência de execução de cada passo do algorítmo é chamada de FLUXO DE EXECUÇÃO: esse fluxo começa desde o primeiro passo do algorítmo, e segue sequencialmente até o último passo, executando cada instrução conforme passa por ela. Assim, no exemplo acima, execuntando cada passo é a instrução Início, o segundo passo é a instrução Obter para o primeiro valor, o terceiro passo é outra instrução Obter, o quarto passo é o cálculo da soma, o quinto passo é a Exibição do resultado, e o sexto passo é a instrução Fim, que termina a execução do algorítmo. Algoritmos Página 9 Esses seis passos, nessa ordem, correspondem ao fluxo de execução desse algorítmo. O algorítmo do problema 2, como se faz para abrir uma porta, seria: 1. Início 2. Gire a maçaneta; 3. Empurre a porta; 4. Fim (Alg. 2) O algorítmo acima resolve o problema de abrir uma porta? Sim, desde que a mesma não esteja trancada à chaves. Se isto ocorrer, pode-se ficar girando a maçaneta e empurrando a porta eternamente, que ela não se abrirá, a menos que seja arrombada. Deixando de lado soluções tão drásticas, vemos que em determinadas situações um algorítmo pode funcionar e em outras, não. Para que ele funcione em todas as situações e condições, estas condições têm de ser previstas, de forma que ações alternativas possam ser executadas, quando da ocorrência da condição, para lidar com esta situação. Cada uma dessas situações constitui um novo problema que deve ser “atacado” separadamente, para se chegar à solução do problema todo. Assim, Para se solucionar cada um, deve-se aplicar o algorítmo específico de cada um. No caso do exemplo 2, sobre como abrir uma porta, no caso da mesma estar trancada, deve-se fazer o seguinte: 1. Início 2. Colocar a chave na fechadura; 3. Enquanto for possível 3.1. Gire a chave para a esquerda; 4. Fim (Alg. 3) Ao final do passo 3, a porta estará destrancada e então pode-se aplicar o algorítmo (2), de abrir a porta. Percebe-se facilmente que o passo 3 é REPETITIVO: o ato de girar a chave é feito ENQUANTO é possível. Quando não mais o é, significa que a porta está destrancada e a repetição do ato de girar a chave terminou. Algoritmos Página 10 A situação do algorítmo (3) é um caso especial do problema de se abrir uma porta, que só ocorre SE a porta está trancada. Consequentemente, o problema de se abrir uma porta pode ter seu algorítmo expandido para: 1. Início 2. Se a porta está trancada 2.1. Início 2.2. Enfiar a chave na Fechadura; 2.3. Enquanto for possível 2.3.1. Gire a chave para a esquerda; 2.4. Fim 3. Gire a maçaneta; 4. Empurre a porta; 5. Fim (Alg. 4) O passo 2 acima configura a situação especial de a porta estar trancada. A palavra SE determina um DESVIO DE FLUXO no algorítmo: se a condição “a porta está fechada” for verdadeira, o FLUXO DE EXECUÇÃO será desviado para o passo 2.1, e seguirá até o 2.4, quando então retornará ao passo 3. Se, ao contrário, a condição for falsa (ou seja, a porta está destrancada), a execução de cada passo continua normalmente, do passo 2 para o 3, e daí até o final. Nesse caso, os passos de 2.1 a 2.4 são ignorados. A palavra SE especifica um desvio de fluxo condicional: sob uma determinada condição, o fluxo é ou não desviado. Se a condição apresentada à palavra SE for verdadeira, o fluxo é desviado para o comando que segue a palavra ENTÃO. Se a condição for falsa, o fluxo não é desviado, e vai para o comando seguinte ao SE. A palavra ENQUANTO especifica uma repetição de passos, também sob uma determinada condição. Enquanto esta condição for verdadeira (no exemplo, enquanto não se deu todas as voltas na chave colocada na fechadura) os passos subordinados ao ENQUANTO serão repetidos. O grupo de passos de 2.1 a 2.4 é chamado um bloco de instruções ou bloco de comandos. São como um sub-algorítmo, ou seja, um algorítmo colocado dentro de outro. Algoritmos Página 11 Em outras palavras, se a porta estiver trancada, resolve-se o algorítmo do bloco 2.1 a 2.4, e segue-se ao passo 3 (segue-se o fluxo de execução). Caso contrário, vai-se direto ao passo 3 (não se faz o desvio), pulando-se o bloco. Este bloco, na verdade, faz parte do passo 2. Como há duas ações no bloco, é necessário, de acordo com as regras da nossa linguagem de algorítmos, que se use as palavras Início e Fim para delimitar o bloco. Se fosse apenas uma ação, não seria necessário delimitar um bloco. Por exemplo, suponha que a chave já estivesse na fechadura, e que isso fosse conhecido, de modo que não fosse preciso colocá-la. O passo 2 seria então reduzido a: 2. Se a porta está trancada 2.1. Enquanto for possível 2.1.1. Gire a chave para a esquerda; O comando Enquanto passou a fazer parte do passo 2, dentro do comando Se. Caso houvesse mais de uma ação a repetir no comando Enquanto, deveríamos colocar Início e Fim, para delimitar um bloco de comandos subordinados ao Enquanto, ou seja, um conjunto de comandos que seria repetido enquanto a condição de parada não fosse satisfeita. Assim, percebe-se que cada comandode um algorítmo tem uma FORMA GERAL e algumas REGRAS DE ESCRITA. Para a instrução Se, a forma geral é a seguinte: Se (<condição>) <comando>; <comando> pode ser uma única instrução ou então um grupo delas. Não se pode esquecer que um grupo de instruções é um bloco de comandos, que começa com a palavra Início e termina com Fim. <comando> será executado se <condição> for verdadeira (ocorre o desvio do fluxo de execução para <comando>). Caso <condição> seja falsa, <comando> não é executado e o fluxo segue para a instrução seguinte as Se. Para a instrução Enquanto, a forma geral é: Enquanto (<condição>) Algoritmos Página 12 <comando>; Na construção acima, <comando> será repetido até que <condição> seja falsa, ou em outras palavras, enquanto <condição> ocorrer (ser verdadeira), <comando> será repetido. Se <condição> nunca deixar de ocorrer, então <comando> será repetido indefinidamente. A isto chama-se LOOP. Abaixo, segue uma proposta de solução para o algorítmo do problema 3, sobre como trocar o pneu de um carro: 1. Início 2. Frear o carro 3. Engrenar a primeira marcha 4. Abrir a tampa do porta-malas 5. Retirar o estepe 6. Retirar o macaco 7. Retirar a chave de boca 8. Enquanto não afrouxar todos os parafusos 8.1 Início 8.2 Colocar a chave de boca no parafuso 8.3 Enquanto não afrouxar o parafuso 8.3.1 girar a chave 8.4 Escolher novo parafuso 8.5 Fim 9 Colocar o macaco no local apropriado 10 Levantar o carro com o macaco 11 Enquanto não retirar todos os parafusos 11.1 Início 11.2 Escolher um parafuso 11.3 Colocar a chave de boca no parafuso 11.4 Enquanto não retirar o parafuso 11.4.1 girar a chave 11.5 Retirar o parafuso 11.6 Fim 12 Retirar o pneu furado 13 Guardar o pneu furado no porta-malas 14 Colocar o estepe 15 Enquanto não prender todos os parafusos 15.1 Início 15.2 Escolher um parafuso 15.3 Colocar o parafuso no bocal 15.4 Colocar a chave de boca no parafuso 15.5 Rosquear um pouco o parafuso Algoritmos Página 13 15.6 Fim 16 Descer o macaco até o pneu tocar o chão 17 Enquanto não apertar todos os parafusos 17.1 Início 17.2 Escolher um parafuso 17.3 Colocar a chave de boca no parafuso 17.4 Apertar totalmente o parafuso 17.5 Fim 18 Guarde o macaco e a chave de boca 19 Feche o porta-malas 20 Entre no carro 21 Ligue o carro 22 Siga até um borracheiro 23 Fim Note que o texto acima é um algorítmo para uma ação do dia-a-dia, e não um algorítmo matemático ou comercial. Assim, ele permite uma liberdade bem maior de escrita. Normalmente numa linguagem de programação, não existirão comandos para “abrir”, “guardar”, “apertar”, etc. O programador terá de ensinar o computar como fazer isso. Um computador “sabe” apenas algumas operações básicas, como soma, subtração, multiplicação e divisão. Sabe também obter valores digitados no teclado, e exibir mensagens na tela. Operações mais complexas devem ser ensinadas passo a passo, usando as operações básicas e os comandos da linguagem. Esse será o objetivo da próxima seção. Algoritimos e Computadores Um computador é uma máquina de processar dados. Em sua memória, são armazenadas informações que serão manipuladas pelo programa executado no momento. O programa deve especificar ao computador quais são, como são, e onde serão armazenados estes dados, identificando cada um. A partir daí, o programa passa a “dizer” ao computador como processar os dados em sua memória, ou seja, deve fornecer ao computador o algorítmo que manipula os dados para se chegar ao resultado final. Algoritmos Página 14 Inclusão de Bibliotecas Um programa pode fazer uso de recusos pré programados e disponibilizados pela linguagem de programação. A necessidade do uso de alguma biblioteca é indicada pelo uso, logo no início do programa, de um ou mais comandos da forma: #include <NomBib.h> onde NomBib é o nome da biblioteca que contém os recursos desejados. Um Programa Todo programa, a princípio, deve começar com main () { e terminar com } Mais adiante veremos com maiores detalhes o significado profundo destas linhas. Por hora, vamos encará-las como uma forma padrão de iniciar e terminar programas. Comandos Comandos são a unidade básica de processamento de uma linguagem de programação imperativa. Saída Básica A seguir, veremos uma função básica para a saída de dados. Para empregá-la, faz-se necessário indicar no início do programa o uso da biblioteca na qual elas se encontram, no caso, a biblioteca stdio. Isto é feito pela instrução #include <stdio.h>. Sua forma geral é: printf (Fmt, Exp1, Exp2,..., Expn); Esta função escreve na saída padrão o string Fmt após substituir nele as expressões Expi. A cada Expi a ser substituída, deve haver um sinal introduzido pelo caractere % em Fmt. Após Algoritmos Página 15 o caractere % deve haver um ou mais caracteres indicadores do tipo da Expi a ser substituída, bem como da formatação que desejamos para aquela expressão. Veja a seguir uma lista destes indicadores e seus significados: %u, indica a escrita de um número natural; %d ou %i, indica a escrita de um número inteiro; %lf, indica a escrita de um número real; %c, indica a escrita de um caractere. Vale observar que a presença de um \n em Fmt faz com que ocorra o salto de uma linha, iisto é, que a próxima escrita ocorra no início da próxima linha, e não na seqüência, na mesma linha, como seria habitual. Para concluir, é importante que se ressalte que, por vezes, informações escritas através deste comando não aparecem imediatamente na tela, tornando-se visíveis tão somente decorrido algum tempo. Quando isso se torna um incômodo, pode-se forçar a escrita imediata de tais informações com o comando fflush (stdout); Comentários Comentários não são levados em conta durante o processo de execução de um programa; tem um efeito meramente documentacional. Os caracteres /* iniciam um comentário que terminará com os caracteres */. [Exemplo 01 – bemvindo.c] /* Este programa lhes da as boas vindas ao estudo da linguagem C */ #include <stdio.h> int main () { printf ("\nBem vindos ao estudo da linguagem C!\n\n"); fflush (stdout); Algoritmos Página 16 return 0; } Variáveis As informações que um programa manipula são armazenados em posições de memória. Cada uma dessas posições é chamada de VARIÁVEL. Como exemplo, temos os identificadores A, B e SOMA, vistos no algorítmo (1), que soma dois valores e escreve o resultado desta soma. Portanto, variável é uma posição da memória do computador onde fica guardado um valor. Este valor não é fixo, pode ser mudado quando necessário. Por exemplo, A pode valer 3 e B, -1, de forma que SOMA valerá 2. Em outro momento, A pode valer 2 e B valer 8, então SOMA valerá 10. Daí vem o nome VARIÁVEL. Note que o mesmo algorítmo não precisa ser reescrito quando os dados são diferentes; simplesmente muda-se o valor das variáveis e executa-se o algorítmo novamente. O valor das variáveis são estabelecidos por meio do comando de leitura (entrada de dados). UCP Memória A: 3 B: -1 Soma: 2 .......... Programa Executável Assim, um mesmo algorítmo (ou problema) serve para resolver um mesmo tipo (uma mesma classe) de problemas, mesmo que os valores sejam alterados para cada problema específico. Toda VARIÁVEL deve ter um tipo. Tiposexpressam a natureza dos valores que podem ser guardados em uma VARIÁVEL, bem como as operações em que a mesma pode estar envolvida (afinal, naturalmente, as operações que se aplicam a VARIÁVEIS que guardam valores inteiros não podem ser as mesmas que se aplicam a VARIÁVEIS que guardam letras). Algoritmos Página 17 Identificadores Identificadores introduzem nomes em um programa. Em C não importa se os identificadores nomeiam uma variável ou outro elemento qualquer de um programa; eles sempre podem ser uma seqüência arbitrariamente longa de letras e dígitos. Embora algumas implementações imponham restrições ao tamanho máximo de um identificador, C não determina nenhuma restrição a respeito. O primeiro caractere de um identificador deve necessariamente ser uma letra ou então o caractere sublinhado (_). É importante ressaltar que, diferentemente de outras linguagens de programação, a linguagem C diferencia letras maiúsculas de letras minúsculas. Em C, identificadores que são lidos da mesma forma, mas que foram escritos de forma diferente no que tange ao emprego de letras maiúsculas e minúsculas, são considerados identificadores diferentes. Identificadores que se iniciam por sublinhado (_) devem ser evitados, tendo em vista que as implementações de C os reservam para seu próprio uso. Tipos Básicos Para fins de um primeiro contato, podemos, simplificadamente, compreender os tipos como segue: unsigned int: representam os números naturais (0, 1, 2, …); int: representam os números inteiros (..., -2, -1, 0, 1, 2, ...); double: representam os números reais (7.5, 1.2, -3.4, -0.3, etc); char: representam um caracteres (uma letra, um dígito, um sinal de pontuação, etc). Declaração de Variáveis Variáveis são definidas quando mencionamos o nome de um tipo, e em seguida uma série de identificadores separados por vírgulas (,) e tendo no final um ponto-e-vírgula (;). Cada um dos identificadores será uma variável do tipo que encabeçou a definição. Algoritmos Página 18 Sendo Tipo um tipo e Vari nomes de identificadores, temos que a forma geral de uma declaração de variáveis é como segue: Tipo Var1, Var2,…, Varn; Variáveis podem ser iniciadas no ato de sua definição, i.e., podem ser definidas e receber um valor inicial. Isto pode ser feito acrescentando um sinal de igual (=) e o valor inicial desejado imediatamente após o identificador da variável que desejamos iniciar. Sendo Tipo um tipo, Vari nomes de identificadores e Expri expressões que resultam em valores do tipo Tipo, temos que a forma geral de uma declaração de variáveis iniciadas é como segue: Tipo Var1 = Expr1, Var2 = Expr2,…, Varn = Exprn; Entrada Básica A seguir, veremos uma função básica para a entrada de dados. Para empregá-la, faz-se necessário indicar no início do programa o uso da biblioteca na qual elas se encontram, no caso, a biblioteca stdio. Isto é feito pela instrução #include <stdio.h>. Sua forma geral é: scanf (Fmt, &Var1, &Var2,..., &Varn); Esta função lê da entrada padrão as variáveis cujos nomes são indicados pelos Vari. Para cada variável a ser lida, deve haver na string Fmt uma especificação de tipo/formato. Como na função printf, esses especificadores são constituídos pelo caractere % seguido por um ou mais caracteres que indicam o tipo e o formato do dado a ser lido. Não mencionaremos aqui os especificadores de tipo/formato da função scanf em virtude desses serem os mesmos da função printf apresentados e discutidos anteriormente. Para concluir, é importante que se ressalte que, por vezes, quando se faz uso de sucessivos comandos de leitura, pode ocorrer de algumas dessas leitaras serem puladas, como se de fato não tivessem sido programadas em seu programa. Isso ocorre em virtude de informações que eventualmente restado no buffer do teclado quando da última leitura. Algoritmos Página 19 Quando isso se torna um incômodo, pode-se forçar o esvaziamento do buffer do teclado após uma leitura o comando fflush (stdin); [Exemplo 02 – bemvindo.c] /* Este programa lhes da as boas vintas ao estudo da linguagem C, alem de lhes desejar sucesso */ #include <stdio.h> int main () { double nota; printf ("\nBem vindo(a) ao estudo de C!\n\n"); printf ("Com que nota voce pretende passar? "); fflush (stdout); scanf ("%lf", ¬a); fflush (stdin); printf ("\nDesejo sucesso a voce;\n"); printf ("que voce passe com %lf ou mais!\n\n", nota); fflush (stdout); return 0; } Expressões Uma expressão é uma seqüência de operadores e operandos que especifica um computação. Uma expressão pode resultar em um valor e pode causar efeitos colaterais. A ordem de avaliação de subexpressões é determinada pela precedência e pelo agrupamento dos operadores. As regras matemáticas usuais para associatividade e comutatividade de operadores podem ser aplicadas somente nos casos em que os operadores sejam realmente associativos e comutativos. A ordem de avaliação dos operandos de operadores individuais é indefinida. Em particular, se um valor é modificado duas vezes numa expressão, o resultado da expressão é indefinido, exceto onde uma ordem seja garantida pelos operadores envolvidos. Algoritmos Página 20 O tratamento do estouro e a verificação da divisão na avaliação de expressões é dependente da implementação. A maior parte das implementações de C existentes ignora o estouro de inteiros. O tratamento da divisão por zero e de todas as exceções em ponto flutuante varia entre as diversas máquinas e é usualmente ajustável por uma função de biblioteca. Operadores Aritméticos Convencionais Os operadores aritméticos da linguagem C são, em sua maioria, aqueles que usualmente encontramos nas linguagens de programação imperativas. Todos eles operam sobre números e resultam números. São eles: 1. + (soma); 2. - (subtração); 3. * (multiplicação); 4. / (divisão); 5. % (resto da divisão inteira); e 6. - (menos unário). Não existe em C um operador que realize a divisão inteira, ou, em outras palavras, em C uma divisão sempre resulta um número real. Para resolver o problema, podemos empregar um conversão de tipo para forçar o resultado da divisão a ser um inteiro. Neste caso, o real resultante terá truncada a sua parte fracionária, se transformando em um inteiro. O operador % (resto da divisão inteira) opera sobre dois valores integrais. Seu resultado também será um valor integral. Ele resulta o resto da divisão inteira de seu primeiro operando por seu segundo operando. O operador - (menos unário) opera sobre um único operando, e resulta o número que se obtém trocando o sinal de seu operando. Algoritmos Página 21 Operadores Relacionais Os operadores relacionais da linguagem C são, em sua maioria, aqueles que usualmente encontramos nas linguagens de programação imperativas. Todos eles operam sobre números e resultam valores lógicos. São eles: 1. == (igualdade); 2. != (desigualdade); 3. < (inferioridade); 4. <= (inferioridade ou igualdade); 5. > (superioridade); e 6. >= (superioridade ou igualdade). Operadores Lógicos Os operadores lógicos da linguagem C são, em sua maioria, aqueles que usualmente encontramos nas linguagens de programação imperativas. Todos eles operam sobre valores lógicos e resultam valores lógicos. São eles: 1. && (conjunção ou and); 2. || (disjunção ou or); e 3. ! (negação ou not). Conversões de Tipo Expressões podem ser forçadas a resultar um certo tipose precedidas pelo tipo desejado entre parênteses. Sendo Tipo um tipo e Expr uma expressão que resulta um valor que não é do tipo Tipo, temos que: (Tipo) Expr resulta a expressão Expressão convertida para o tipo Tipo. Algoritmos Página 22 Observe, abaixo, uma ilustração do uso deste operador: ... double d = 3.14; unsigned int u = (unsigned int)d; printf ("%u\n", u); // 3 ... O Comando de Atribuição O comando de atribuição tem a seguinte forma básica: em primeiro lugar vem o identificador da variável receptora da atribuição, em seguida vem o operador de atribuição (=), em seguida vem a expressão a ser atribuída, em seguida vem um ponto-e-vírgula (;). Sendo Var o identificador de uma variável e Expr uma expressão, temos abaixo a forma geral do comando de atribuição: Var = Expr; [Exemplo 03 – media.c] /* Este programa solicita a digitacao de dois numeros, calculando e exibindo a media aritmetica dos mesmos */ #include <stdio.h> int main () { double nro1, nro2, media; printf ("\nDigite um numero: "); fflush (stdout); scanf ("%lf", &nro1); fflush (stdin); printf ("Digite outro numero: "); fflush (stdout); scanf ("%lf", &nro2); fflush (stdin); media = (nro1 + nro2) / 2.0; printf ("\nA media de %lf e de %lf da %lf!\n\n", nro1, nro2, media); fflush (stdout); return 0; Algoritmos Página 23 } Blocos de Comando Já conhecemos o conceito de bloco de comandos, que nada mais é do que uma série de comandos delimitada por um par de chaves ({}). Blocos de comando não são terminados por ponto-e-vírgula (;). Blocos de comando são muito úteis para proporcionar a execução de uma série de subcomandos de comandos que aceitam apenas um subcomando. O Comando if O comando if tem a seguinte forma básica: em primeiro lugar vem a palavra-chave if, em seguida vem, entre parênteses, a condição a ser avaliada, em seguida vem o comando a ser executado no caso da referida condição se provar verdadeira. Sendo Cond uma condição booleana e Cmd um comando, temos abaixo a forma geral do comando if (sem else): if (Cond) Cmd; O comando if pode também executar um comando, no caso de sua condição se provar falsa. Para tanto, tudo o que temos que fazer é continuar o comando if que já conhecemos, lhe acrescentando a palavra chave else, e em seguida o comando a ser executado, no caso da referida condição se provar falsa. Sendo Cond uma condição booleana e Cmdi dois comandos, temos abaixo forma geral do comando if com else: if (Cond) Cmd1; else Cmd2; Algoritmos Página 24 Observe que, tanto no caso da condição de um comando if se provar verdadeira, quanto no caso dela se provar falsa, o comando if somente pode executar um comando. Isso nem sempre, ou melhor, quase nunca é satisfatório; é comum desejarmos a execução de mais de um comando. Por isso, nos lugares onde se espera a especificação de um comando, podemos especificar um bloco de comandos. [Exemplo 04 – eqprimgr.c] /* Este programa solicita a digitacao dos coeficientes de uma equacao de primeiro grau, calculando e exibindo sua raiz */ #include <stdio.h> int main () { double a, b, raiz; printf ("\nDigite o coeficiente A "); printf ("de uma equacao primeiro grau: "); fflush (stdout); scanf ("%lf", &a); fflush (stdin); if (a == 0.0) { printf ("\nNao se trata de uma equacao de primeiro grau"); fflush (stdout); } else { printf ("\nDigite o coeficiente B "); printf ("de uma equacao primeiro grau: "); fflush (stdout); scanf ("%lf", &b); fflush (stdin); raiz = -b/a; printf ("\nA raiz da equacao digitada vale %lf!\n\n", raiz); fflush (stdout); } return 0; } Algoritmos Página 25 O Comando switch O comando switch tem a seguinte forma: em primeiro lugar vem a palavra-chave switch, em seguida vem, entre parênteses, uma expressão integral a ser avaliada, em seguida vem, entre chaves ({}), uma série de casos. Um caso tem a seguinte forma básica: em primeiro lugar vem a palavra-chave case, em seguida vem uma constante integral especificando o caso, em seguida vem o caractere dois pontos (:), em seguida vem uma série de comandos a serem executados no caso. Sendo Expr uma expressão, ConstI constantes literais do mesmo tipo que Expr e CmdIJ comandos, temos abaixo uma das formas gerais do comando switch: switch (Expr) { case Const1: Cmd1a; Cmd1b; ... case Const2: Cmd2a; Cmd2b; ... case Const3: Cmd3a; Cmd3b; ... ... } Se, em alguma circunstância, desejarmos executar uma mesma série de comandos em mais de um caso, tudo o que temos a fazer é especificar em seqüência os casos em questão, deixando para indicar somente no último deles a referida seqüência de comandos. Sendo Expr uma expressão, ConstI,J constantes literais do mesmo tipo que Expr e CmdIJ comandos, temos abaixo uma das formas gerais do comando switch: switch (Expr) { case Const1,1: case Const1,2: ... Cmd1a; Cmd1b; ... case Const2,1: Algoritmos Página 26 case Const2,2: ... Cmd2a; Cmd2b; ... case Const3,1: case Const3,2: ... Cmd3a; Cmd3b; ... ... } Se, em alguma circunstância, desejarmos executar uma série de comandos qualquer que seja o caso, tudo o que temos a fazer é especificar um caso da forma: em primeiro lugar vem a palavra-chave default, em seguida vem o caractere dois pontos (:), em seguida vem uma série de comandos a serem executados qualquer que seja o caso. Sendo Expr uma expressão, ConstI,J constantes literais do mesmo tipo que Expr e CmdIJ comandos, temos abaixo uma das formas gerais do comando switch: switch (Expr) { case Const1,1: case Const1,2: ... Cmd1a; Cmd1b; ... case Const2,1: case Const2,2: ... Cmd2a; Cmd2b; ... ... default: CmdDa; CmdDb; ... } Algoritmos Página 27 É importante ficar claro que o comando switch não se encerra após a execução da seqüência de comandos associada a um caso; em vez disso, todas as seqüências de comandos, associadas aos casos subseqüentes, serão também executadas. Se isso não for o desejado, basta terminar cada seqüência (exceto a última), com um comando break. Sendo Expr uma expressão, ConstI,J constantes literais do mesmo tipo que Expr e CmdIJ comandos, temos abaixo uma das formas gerais do comando switch com breaks: switch (Expr) { case Const1,1: case Const1,2: ... Cmd1a; Cmd1b; ... break; case Const2,1: case Const2,2: ... Cmd2a; Cmd2b; ... break; ... default: CmdDa; CmdDb; ... } [Exemplo 05 – exparitm.c] /* Este programa solicita a digitacao de uma expressao aritmetica simples (somente envolvendo as operacoes +, -, * e /), calculando e exibindo seu valor */ #include <stdio.h> int main () { double nro1, nro2, resultado; char Operacao; Algoritmos Página 28 printf ("\nDigite um expressao aritmetica simples: "); fflush (stdout); scanf ("n%lf%c%lf", &nro1, &Operacao, &nro2); fflush (stdin);switch (Operacao) { case '+': resultado = nro1 + nro2; printf ("\nResultado = %lf\n\n", resultado); break; case '-': resultado = nro1 - nro2; printf ("\nResultado = %lf\n\n", resultado); break; case '*': resultado = nro1 * nro2; printf ("\nResultado = %lf\n\n", resultado); break; case '/': resultado = nro1 / nro2; printf ("\nResultado = %lf\n\n", resultado); break; default: printf ("\nOperadores validos sao +, -, * e /\n\n"); } fflush (stdout); return 0; } Acumulação de Valores Muitas vezes, é necessário que se acumule valores, somando-os uns aos outros. Como exemplo disso, existe a situação de se exibir o total de salários pagos numa empresa, para efeito de Imposto de Renda que a empresa paga ao governo. Assim, suponha que dos 500 funcionários da empresa existam os seguintes dados, que serão lidos por um algorítmo: (1) Matrícula; (2) Nome; e (3) Salário. Para se somar os salários de todos eles, deve-se usar variáveis que chamaremos de TOTALIZADORES. Totalizador é uma variável que será usada para acumular valores lidos ou calculados, de forma que ao final do processo, ela contenha a soma de todos os valores. Esta soma é chamada de Somatória. Algoritmos Página 29 O valor inicial de um totalizador deve ser ZERO, pois nada ainda foi somado quando o processo se inicia. Após ser zerado, pode-se então começar o processo de somas sucessivas. O esquema abaixo demonstra como fazê-lo. Suponha que Total_De_Salarios é a variável totalizadora, e os dados são os seguintes: 7508 Joao 5000.00 2503 Maria 10050.00 1078 Ana 3450.00 8881 Marcio 2500.01 ... ... ... 1. Zerar o Totalizador Total_de_Salarios: 2. Ler o primeiro registro. Os dados ficarão na memória, nas variáveis abaixo Matr Nome Salario 3. Somar o Salário lido com a variável Total_De_Salarios. O valor resultante deve ser armazenado na própria variável Total_De_Salarios, que assim passa a acumular seu conteúdo anterior (0.00) com o Salário lido (5000.00), como indicado na figura abaixo: Total_De_Salarios: 4. Ler o próximo registro. Os dados ficarão na memória, nas variáveis abaixo: Matr Nome Salario 5. Somar o Salário lido com a variável Total_De_Salarios. O valor resultante deve ser armazenado na própria variável Total_De_Salarios, que assim passa a acumular seu conteúdo anterior (5000.00) com o Salário lido (10050.00), como indicado na figura abaixo: Total_De_Salarios: 6. Ler o próximo registro. Os dados ficarão na memória, nas variáveis abaixo: Matr Nome Salario 0.00 7508 Joao 5000.00 5000.00 15050.00 2503 Maria 10050.00 1078 Ana 3450.00 Algoritmos Página 30 7. Somar o Salário lido com a variável Total_De_Salarios. O valor resultante deve ser armazenado na própria variável Total_De_Salarios, que assim passa a acumular seu conteúdo anterior (15050.00) com o Salário lido (3450.00), como indicado na figura abaixo: Total_De_Salarios: 8. O próximo passo é repetir os dois passos acima para o próximo registro, e assim por diante, até que terminem os dados. Os passos 2 e 3, 4 e 5, 6 e 7 e o 8 são o mesmo conjunto de instruções, repetido para cada registro lido. O acúmulo na variável Total_De_Salarios nada mais é do que a seguinte instrução de algorítmo: Total_De_Salarios Total_De_Salarios + Salario que faz com que o valor anterior de Total_De_Salarios seja somando ao valor de Salario que acabou de ser lido, e o resultado armazenado na própria variável Total_De_Salarios. Da mesma forma que a soma, por vezes é necessário que se acumule produtos entre valores. Assim, introduziremos o conceito de Produtório. Produtório é um acúmulo de produtos entre valores sucessivamente lidos ou calculados no decorrer de uma repetição de ações de um algorítmo. Para ser feito, é necessária uma variável totalizadora, como a que vimos acima. Essa variável, a cada repetição dos comandos que calculam ou lêem os valores que serão acumulados, deverá armazenar o resultado da multiplicação do seu conteúdo atual pelo novo valor que entrará na totalização. O comando que faz isto é o seguinte: Total_De_Produtos Total_De_Produtos * Valor_Novo onde Total_De_Produtos representa a variável usada para produtório e valor_novo representa o valor que foi lido ou calculado nesta repetição do algorítmo. 18500.00 Algoritmos Página 31 Uma questão interessante é: qual deve ser o valor inicial de uma variável totalizadora de um produtório, antes de se iniciar as repetições? A resposta é simples. Da mesma maneira que fizemos na somatória, usa-se o elemento neutro da operação. Para Produtos, o elemento neutro é 1. Se inicializar o totalizador com 0, ao invés de 1, todos os resultados serão nulos. Inicializando com 1, a primeira multiplicação do produtório pelo valor novo fará com que este seja armazenado no totalizador e, na segunda multiplicação, será feito o produto do primeiro valor novo com o segundo, e esse resultado será armazenado no totalizador. Isso continuará até que os dados terminem. O Comando while O comando while tem a seguinte forma básica: em primeiro lugar vem a palavra-chave while, em seguida vem, entre parênteses, a condição de iteração, em seguida vem o comando a ser iterado. A iteração se processa enquanto a condição de iteração se provar verdadeira. Sendo Cond uma condição booleana e Cmd um comando, temos abaixo a forma geral do comando while: while (Cond) Cmd; Observe que, conforme especificado acima, o comando while itera somente um comando. Isso nem sempre, ou melhor, quase nunca é satisfatório; é comum desejarmos a iteração de um conjunto não unitário de comandos. Por isso, em lugar de especificar o comando a ser iterado, podemos especificar um bloco de comandos. Assim conseguiremos o efeito desejado. [Exemplo 06 – fatorial.c] /* Este programa solicita a digitacao de um numero natural, calculando e exibindo o seu fatorial Algoritmos Página 32 */ #include <stdio.h> int main () { double numeroDigitado; unsigned int numero; printf ("\nEntre com um numero natural: "); fflush (stdout); scanf ("%lf", &numeroDigitado); fflush (stdin); if (numeroDigitado < 0) { printf ("\nNao se calcula fatorial de "); printf ("numeros negativos!\n\n"); } else { numero = (unsigned int)numeroDigitado; if (numero != numeroDigitado) { printf ("\nNao se calcula fatorial de "); printf ("numeros fracionarios!\n\n"); } else { unsigned int fatorial = 1; while (numero>1) { fatorial = fatorial*numero; numero = numero-1; } printf ("\nO fatorial deu %u\n\n", fatorial); } } fflush (stdout); return 0; } Funções Todo processamento em C acontece dentro de funções. Funções são definidas mencionando o tipo do retorno da função, seguido pelo identificador da função, seguido por um par de parênteses (()) contendo, opcionalmente, a lista dos parâmetros formais da função, seguido por um bloco de comandos representando o corpo da função.Algoritmos Página 33 Uma lista de parâmetros formais nada mais é do que uma série de definições de parâmetros formais separadas por vírgulas (,). A definição de um parâmetro formal é feita mencionando o nome do tipo do parâmetro e em seguida o identificador do parâmetro formal. O tipo do retorno de uma função pode ser omitido, caso em que assumir-se-á que a mesma retorna um valor do tipo int. Não existe em C o conceito de procedimento, muito embora possamos definir funções que não retornam valor nenhum, o que dá no mesmo. Isto pode ser feito dizendo que o tipo do retorno da função é void. O comando return é empregado para fazer o retorno do resultado da função a seu chamante. [Exemplo 07 – fatorial.c] /* Este programa solicita a digitacao de um numero natural, calculando e exibindo o seu fatorial */ #include <stdio.h> unsigned int fatorial (unsigned int n) { int calculo = 1; while (n>1) { calculo = calculo*n; n=n-1; } return calculo; } int main () { double numeroDigitado; unsigned int numero; printf ("\nEntre com um numero natural: "); fflush (stdout); scanf ("%lf", &numeroDigitado); fflush (stdin); if (numeroDigitado < 0) { printf ("\nNao se calcula fatorial de "); Algoritmos Página 34 printf ("numeros negativos!\n\n"); } else { numero = (unsigned int)numeroDigitado; if (numero != numeroDigitado) { printf ("\nNao se calcula fatorial de "); printf ("numeros fracionarios!\n\n"); } else { unsigned int resultado; resultado = fatorial (numero); printf ("\nO fatorial deu %u\n\n", resultado); } } fflush (stdout); return 0; } O Comando do-while O comando do-while tem a seguinte forma básica: em primeiro lugar vem a palavra-chave do, em seguida vem o comando a ser iterado, em seguida vem a palavra-chave while, em seguida vem, entre parênteses, a condição de iteração. A iteração se processa enquanto a condição de iteração se provar verdadeira. A diferença que este comando tem com relação ao comando while é que este comando sempre executa o comando a ser iterado pelo menos uma vez, já que somente testa a condição de iteração após tê-lo executado. Já o comando while testa a condição de iteração antes de executar o comando a ser iterado, e por isso pode parar antes de executá-lo pela primeira vez. Sendo Cond uma condição booleana e Cmd um comando, temos abaixo a forma geral do comando do-while: do Cmd; while (Cond); Algoritmos Página 35 Observe que, conforme especificado acima, o comando do-while itera somente um comando. Isso nem sempre, ou melhor, quase nunca é satisfatório; é comum desejarmos a iteração de um conjunto não unitário de comandos. Por isso, em lugar de especificar o comando a ser iterado, podemos especificar um bloco de comandos. Assim, conseguiremos o efeito desejado. [Exemplo 08 – fatorial.c] /* Este programa solicita a digitacao de um numero natural, calculando e exibindo o seu fatorial */ #include <stdio.h> unsigned int fatorial (unsigned int n) { int calculo = 1; do { calculo = calculo*n; n=n-1; } while (n>1); return calculo; } int main () { double numeroDigitado; unsigned int numero; printf ("\nEntre com um numero natural: "); fflush (stdout); scanf ("%lf", &numeroDigitado); fflush (stdin); if (numeroDigitado < 0) { printf ("\nNao se calcula fatorial de "); printf ("numeros negativos!\n\n"); } else { numero = (unsigned int)numeroDigitado; if (numero != numeroDigitado) { printf ("\nNao se calcula fatorial de "); printf ("numeros fracionarios!\n\n"); Algoritmos Página 36 } else { unsigned int resultado; resultado = fatorial (numero); printf ("\nO fatorial deu %u\n\n", resultado); } } fflush (stdout); return 0; } O Comando for O comando for tem a seguinte forma básica: em primeiro lugar vem a palavra-chave for, em seguida vem, entre parênteses e separadas por pontos-e-vírgulas (;), a sessão de iniciação, a condição de iteração, e a sessão de reiniciação. Em seguida vem o comando a ser iterado. A iteração se processa enquanto a condição de iteração se provar verdadeira. No caso de haver mais de um comando na sessão de iniciação ou na sessão de reiniciação, estes devem ser separados por virgulas (,). Sendo CmdI,i, CmdR,i e Cmd comandos, e Cond uma condição booleana, temos abaixo a forma geral do comando for (os números indicam a ordem de execução das partes do comando for): for (CmdI,1, CmdI,2,... ; Cond; CmdR,1, CmdR,2,...) Cmd; 1 2 3 5 4 6 8 7 9 11 10 12 ... n n-1 Observe que, conforme especificado acima, o comando for itera somente um comando. Isso nem sempre, ou melhor, quase nunca é satisfatório; é comum desejarmos a iteração de um conjunto não unitário de comandos. Algoritmos Página 37 Por isso, no lugar onde se espera a especificação de um comando, podemos especificar um bloco de comandos. Assim, conseguiremos o efeito desejado. Observe, abaixo, uma ilustração do uso deste comando, que escreve na tela 10 vezes a frase “C e demais!”: ... int i; ... for (i=1; i<=10; i++) printf ("C e demais!\n"); ... equivale a ... int i=1; for (; i<=10; i++) printf ("C e demais!\n"); ... equivale a ... int i=1; for (; i<=10;) { printf ("C e demais!\n"); i++; } ... equivale a ... int i=1; for (;;) { printf ("C e demais!\n"); i++; if (i>10) break; } ... [Exemplo 09 – fatorial.c] /* Este programa solicita a digitacao de um numero natural, calculando e exibindo o seu fatorial */ Algoritmos Página 38 #include <stdio.h> unsigned int fatorial (unsigned int n) { int calculo; for (calculo=1; n>1; n=n-1) calculo = calculo*n; return calculo; } int main () { double numeroDigitado; unsigned int numero; printf ("\nEntre com um numero natural: "); fflush (stdout); scanf ("%lf", &numeroDigitado); fflush (stdin); if (numeroDigitado < 0) { printf ("\nNao se calcula fatorial de "); printf ("numeros negativos!\n\n"); } else { numero = (unsigned int)numeroDigitado; if (numero != numeroDigitado) { printf ("\nNao se calcula fatorial de "); printf ("numeros fracionarios!\n\n"); } else { unsigned int resultado; resultado = fatorial (numero); printf ("\nOfatorial deu %u\n\n", resultado); } } fflush (stdout); return 0; } Algoritmos Página 39 Mais sobre Expressões Operadores de Incremento e Decremento Os operadores de incremento e decremento da linguagem C não são usualmente encontrados em outras linguagens de programação. Todos eles são operadores unários e operam sobre variáveis inteiras e resultam números inteiros. São eles: 1. ++ (prefixo); 2. -- (prefixo); 3. ++ (posfixo); 4. -- (posfixo). O operador ++ (prefixo) incrementa seu operando e produz como resultado seu valor (já incrementado). O operador -- (prefixo) decrementa seu operando e produz como resultado seu valor (já decrementado). O operador ++ (posfixo) incrementa seu operando e produz como resultado seu valor original (antes do incremento). O operador -- (posfixo) decrementa seu operando e produz como resultado seu valor original (antes do decremento). Observe, abaixo, uma ilustração do uso destes operadores: ... int a=7, b=13, c; printf ("%d %d\n", a, b); // 7 13 fflush (stdout); a--; b++; printf ("%d %d\n", a, b); // 6 14 fflush (stdout); --a; ++b; printf ("%d %d\n", a, b); // 5 15 fflush (stdout); c = a++ + ++b; printf ("%d %d %d\n", a, b, c); // 6 16 21 fflush (stdout); ... Algoritmos Página 40 Operadores de Bit Os operadores de bit da linguagem C são, em sua maioria, aqueles que usualmente encontramos nas linguagens de programação imperativas. Todos eles operam sobre valores integrais e resultam valores integrais. São eles: 1. & (and bit a bit); 2. | (or bit a bit); 3. ^ (xor bit a bit); 4. ~ (not bit a bit); 5. << (shift left bit a bit); e 6. >> (shift right bit a bit). Observe, abaixo, uma ilustração do uso destes operadores: ... short int a, b=0x7C3A, // 0111 1100 0011 1010 c=ox1B3F; // 0001 1011 0011 1111 a = b & c; // 0001 1000 0011 1010 a = b | c; // 0111 1111 0011 1111 a = b ^ c; // 0110 0111 0000 0101 a = ~b; // 1000 0011 1100 0101 a = b << 3; // 1110 0001 1101 0000 a = c >> 5; // 0000 0000 1101 1001 ... Operador de Atribuição com Operação Embutida Os operadores aritméticos e de bit podem ser combinados com o operador de atribuição para formar um operador de atribuição com operação embutida. Sendo Var uma variável, Opr um operador aritmético ou de bit e Expr uma expressão, temos que: Var Opr= Expr; é equivalente a Var = Var Opr (Expr); Algoritmos Página 41 Observe, abaixo, uma ilustração do uso destes operadores: ... float a, b, c, d, e; a = a + (3 * b); // a += 3*b; b = b / (a - sin (a)); // b /= a-sin(a); c = c << d; // c <<= d; d = d & (a + b); // d &= a+b; e = e >> (d + 3); // e >>= d+3; ... Expressões Condicionais Expressões condicionais representam uma forma compacta de escrever comandos a escolha de um dentre uma série possivelmente grande de valores. Sendo Cond uma condição booleana e Expri expressões, temos que: Condição? Expr1: Expr2 resulta Expr1 no caso de Cond ser satisfeita, e Expr2, caso contrário. Observe, abaixo, uma ilustração do uso deste operador: ... int a, b; ... printf ("%d\n", a>b?a:b); fflush (stdout); ... equivale a ... int a, b; ... int maior; if (a>b) maior = a; else maior = b; printf ("%d\n", maior); fflush (stdout); ... Algoritmos Página 42 Mais sobre Funções Parâmetros por Referência Para passarmos um parâmetro por referência em C, é preciso explicitamente usar ponteiros. Um parâmetro por referência, na realidade, é um ponteiro para a variável que desejamos passar. Desta forma, quando desejamos tomar ou alterar o valor da referida variável, o fazemos sempre através do ponteiro. A declaração de uma variável que é um ponteiro para um dado tipo é idêntica à declaração de uma variável do tipo dado, exceto pelo fato de que antepomos ao identificador da variável o caractere asterisco (*). Como veremos com mais detalhes quando estivermos considerando o tipo ponteiro, existe um operador prefixo unário simbolizado pelo caractere * que opera sobre ponteiros. Trata-se do operador de derreferenciação. Este operador, quando aplicado a um ponteiro P, resulta no conteúdo da memória apontada por P. Existe um operador prefixo unário simbolizado pelo caractere &. Este operador, quando aplicado a uma variável, resulta no endereço de memória que lhe próprio. Este operador é muito útil na passagem de parâmetros por referência. Isto porque, quando desejamos passar uma variável como um parâmetro efetivo por referência, o que passamos não é de fato a variável, e sim o seu endereço, já que a função receptora espera receber um ponteiro. Considerando que A e B são duas variáveis do tipo int, veja no exemplo abaixo como as passaríamos para a função Troca definida no exemplo acima: Troca (&A, &B); [Exemplo 10 – troca.c] /* Este programa exibe o valor de duas variaveis, troca-lhes o conteudo, exibindo, em seguida, seus valores novamente */ Algoritmos Página 43 #include <stdio.h> void troca (int* x, int* y) { int terceiroCopo; terceiroCopo = *x; *x = *y; *y = terceiroCopo; } int main () { int a = 7, b = 13; printf ("\nA = %2d - b = %2d\n", a, b); fflush (stdout); troca (&a, &b); printf ("a = %2d - b = %2d\n", a, b); fflush (stdout); return 0; } Recursão A recursão é o processo pelo qual passa um algoritmo quando um dos passos do algoritmo envolve a repetição completa deste mesmo algoritmo. Um algoritmo que se utiliza da recursão é dito recursivo. Para entendermos a recursão, devemos primeiro compreender a diferença entre um algoritmo e a execução de um algoritmo. Um algoritmo é um conjunto de passos que devem ser tomados baseados em um conjunto de regras. A execução de um algoritmo envolve seguir de fato as regras e executar os passos. Um algoritmo é dito recursivo quando um de seus passos consiste na chamada de uma nova execução do algoritmo. Um algoritmo recursivo deve completar cada um de seus passos. Mesmo se uma nova chamada é feita, cada execução deve passar por cada um dos passos restantes. Algoritmos recursivos resolvem problemas fazendouso da técnica Dividir para Conquistar ou, em outras palavras, dividem o problema a ser resolvido em subproblemas do mesmo tipo, Algoritmos Página 44 resolvem os subproblemas e, com suas soluções, compõem a solução do problema que originalmente se pretendia resolver. [Exemplo 11 – fatorial.c] /* Este programa solicita a digitacao de um numero natural, calculando e exibindo o seu fatorial */ #include <stdio.h> unsigned int fatorial (unsigned int n) { if (n <= 1) return 1; else return n * fatorial (n-1); } int main () { double numeroDigitado; unsigned int numero; printf ("\nEntre com um numero natural: "); scanf ("%lf", &numeroDigitado); if (numeroDigitado < 0) { printf ("\nNao se calcula fatorial de "); printf ("numeros negativos!\n\n"); } else { numero = (unsigned int)numeroDigitado;if (numero != numeroDigitado) { printf ("\nNao se calcula fatorial de "); printf ("numeros fracionarios!\n\n"); } else { unsigned int resultado; resultado = fatorial (numero); printf ("\nO fatorial deu %u\n\n", resultado); } } fflush (stdout); return 0; } Algoritmos Página 45 Tipos Primitivos Não são muitos os tipos de que dispomos na linguagem C; na verdade são apenas quatro tipos básicos, a saber: char (caractere), int (inteiro), float (real) e void (vazio). No entanto, através de qualificadores, podemos criar interessantes variações desses tipos, ampliando assim o conjunto dos tipos básicos. Observe abaixo os possíveis tipos numéricos existentes em Turbo C++ 3.0, uma particular implementação de C++, que, como de praxe, suporta o desenvolvimento de programas em linguagem C: 1. Inteiros: Os tipos inteiros permitem a declaração de variáveis capazes de armazenar números inteiros. Os inteiros simples têm o tamanho natural sugerido pela arquitetura da máquina; os demais tamanhos são fornecidos para atender a necessidades especiais e podem ser tornados equivalentes entre si ou a um inteiro simples. char: 8 bits com sinal (de -128 a 127); signed char: como char; unsigned char: 8 bits sem sinal (de 0 a 255); int: 16 bits com sinal (de -32768 a 32767); signed int: como int; unsigned int: 16 bits sem sinal (de 0 a 65535); short int: como int; signed short int: como short int; unsigned short int: como unsigned int; Algoritmos Página 46 long int: 32 bits com sinal (de -2147483648 a 2147483647); signed long int: como long int; unsigned long int: 32 bits sem sinal (de 0 a 4294967295). 2. Reais: Os tipos reais permitem a declaração de variáveis capazes de armazenar números reais. As implementações de C podem decidir livremente as características a conferir a estes tipos. float: 32 bits (de 3,4 x 10-38 a 3,4 x 10+38); double: 64 bits (de 1,7 x 10-308 a 1,7 x 10+308); long double: 80 bits (de 3,4 x 10-4932 a 1.1 x 10+4932). Observe abaixo os possíveis tipos numéricos existentes em Visual C++ 6.0, uma particular implementação de C++, que, como de praxe, suporta o desenvolvimento de programas em linguagem C: 1. Inteiros: Os tipos inteiros permitem a declaração de variáveis capazes de armazenar números inteiros. Existem em diversos tamanhos, a saber: char: 8 bits com sinal (de -128 a 127); signed char: como char; unsigned char: 8 bits sem sinal (de 0 a 255); short int: 16 bits com sinal (de -32.768 a 32.767); signed short int: como short int; unsigned short int: 16 bits sem sinal (de 0 a 65.535); int: 32 bits com sinal (de – 2.147.483.648 a 2.147.483.647); signed int: como int; unsigned int: 32 bits sem sinal (de 0 a 4.294.967.295); Algoritmos Página 47 long int: como int; signed long int: como long int; unsigned long int: como unsigned int. 2. Reais: Os tipos reais permitem a declaração de variáveis capazes de armazenar números reais. Existem em três tamanhos, a saber: float: 32 bits (de 3,4 x 10-38 a 3,4 x 10+38); double: 64 bits (de 1,7 x 10-308 a 1,7 x 10+308); long double: como double. Observe abaixo outros tipos típicos da linguagem C, independentemente de implementação: 3. Vazio: O tipo void especifica um conjunto vazio de valores. Ele é usado como tipo de retorno para funções que não retornam nenhum valor. Não faz sentido declarar variáveis do tipo void. 4. Booleanos: Vale ressaltar que na linguagem C não existe um tipo específico para armazenar valores lógicos. Para tanto, qualquer tipo integral pode ser empregado. Faz-se a seguinte convenção: o valor zero simboliza a falsidade, e qualquer valor diferente de zero, simboliza a verdade. Constantes Constantes são instâncias de tipos das linguagens. Temos duas variedades de constantes, a saber, constantes literais e constantes simbólicas. Algoritmos Página 48 Constantes Literais Constantes literais são aquelas que especificam literalmente uma instância de um tipo da linguagem. A seguir apresentaremos as constantes literais existentes na linguagem C++ (e também na linguagem C). Constantes Literais do Tipo Inteiro Uma constantes inteira constituída de uma seqüência de dígitos é considerada decimal, a menos que inicie por um dígito 0, caso em que será considerada uma constante octal. É importante notar que os caracteres 8 e 9 não são dígitos octais válidos, e por isso não podem ser empregados em tais constantes. Uma seqüência de dígitos precedida por 0x ou 0X é considerada uma constante hexadecimal. Além dos dígitos, também as letras de a (ou A) até f (ou F) são consideradas válidas para compor tais constantes. O tipo de uma constante inteira depende de sua forma, valor e sufixo. Se ela for decimal e não tiver nenhum sufixo, ela será do primeiro desses tipos no qual seu valor puder ser representado: int, long int, unsigned long int. Se ela for octal ou hexadecimal e não tiver nenhum sufixo, ela será do primeiro desses tipos no qual seu valor puder ser representado: int, unsigned int, long int, unsigned long int. Independentemente da base, se ela for seguida pelo caractere u ou U, ela será do primeiro desses tipos no qual seu valor puder ser representado: unsigned int, unsigned long int. Também independentemente da base, se ela for seguida pelo caractere l ou L, ela será do primeiro desses tipos no qual seu valor puder ser representado: long int, unsigned long int. Por fim, ainda independentemente da base, se ela for seguida por ul, lu, uL, Lu, Ul, lU, UL ou LU, ela será unsigned long int. Constantes Literais do Tipo Real Uma constante real consiste numa parte inteira com sinal opcional, um ponto decimal e uma parte fracionária, um e (ou E), um expoente inteiro com sinal opcional, e um sufixo de tipo. Algoritmos Página 49 Tanto a parte inteira como a parte fracionária podem ser omitidas (mas não ambas). Tanto o ponto decimal seguida da parte fracionária como o e (ou E) e o expoente podem ser omitidos (mas não ambos). O sufixo de tipo também pode ser omitido. O tipo de uma constante real é double float, a menos que explicitamente seja especificado um outro tipo. Os sufixos f (ou F) e l (ou L) especificam, respectivamente float e long double. Constantes Literais do Tipo Caractere Uma constantes caractere é constituída por um único caracteres delimitado por apostrofes (‘c’). Constantes caractere são do tipo char, que é um tipo integral. O valor de uma constante caractere é o valor numérico do caractere no conjunto de caracteres da máquina. Certos caracteres não visíveis, o apóstrofe (‘), as aspas (“), o ponto de interrogação (?) e a barra invertida (\) podem ser representados de acordo com a seguinte tabela de seqüências de caracteres: ‘\b’ retrocesso (backspace) ‘\t’ tabulação (tab) ‘\v’ tabulação vertical (vtab) ‘\n’ nova linha (new line) ‘\f’ avanço de formulário (form feed) ‘\r’ retorno do carro (carriage return) ‘\a’ alerta (bell) ‘\0’ nulo (null) ‘\’’ apóstrofe (single quote) ‘\”’ aspas (double quote) ‘\\’ barra invertida (backslash) ‘\OOO’ caractére ASCII (OOO em octal) ‘\xHH’ caractére ASCII (HH em hexadecimal) Uma seqüência como estas, apesar de constituídas por mais de um caractere, representam um único caractere. Vale ressaltar que o emprego de uma barra invertida (\) seguida
Compartilhar