Sie sind auf Seite 1von 142

Faculdade SATC

Tcnicas de Programao II
Linguagem C

Engenharias Eltrica e Mecnica

Prof.: Giovani Martins Cascaes


giovani.cascaes@satc.edu.br http://www.satc.edu.br/gcascaes/

verso 1.07.142 2010/2011

Sumrio
Listas de Figuras............................................................................................................. 5 Lista de Tabelas .............................................................................................................. 6 1 Introduo .................................................................................................................... 7 1.1 Organizao bsica de programas C....................................................................... 7 1.2 Criando, compilando e executando programas em linguagem C ........................... 9 2 Tipos, bases, operadores e expresses...................................................................... 12 2.1 Componentes bsicos de um computador ............................................................ 13 2.1.1 Unidade Lgica e Aritmtica......................................................................... 14 2.1.2 Registradores ................................................................................................. 14 2.1.3 Memria ........................................................................................................ 15 2.1.4 Bases.............................................................................................................. 16 2.1.5 Unidade de Controle...................................................................................... 18 2.2 Declaraes de variveis....................................................................................... 18 2.2.1 Definindo contantes....................................................................................... 19 2.2.2 Definindo variveis globais ........................................................................... 20 2.3 Expresses ............................................................................................................ 20 2.3.1 Expresses Aritmticas ................................................................................. 21 2.3.2 Expresses Condicionais ............................................................................... 23 2.3.3 Prioridade de operadores ............................................................................... 24 2.4 Exerccios propostos............................................................................................. 24 3 O controle do fluxo de execuo............................................................................... 26 3.1 Seqncias ............................................................................................................ 26 3.2 Ifs......................................................................................................................... 27 3.3 Switch ................................................................................................................... 29 3.4 Comando ternrio ................................................................................................. 33 3.5 Repeties............................................................................................................. 34 3.5.1 Comando while ............................................................................................. 34 3.5.2 Comando do while ........................................................................................ 36 3.5.3 Comando for ................................................................................................. 38 3.6 Exerccios propostos............................................................................................. 43 4 Funes ....................................................................................................................... 47 4.1 Prottipos de funes............................................................................................ 48 4.2 Escopo de variveis .............................................................................................. 49 4.2.1 Variveis locais.............................................................................................. 49 4.2.2 Variveis estticas ......................................................................................... 51 4.2.3 Variveis globais ........................................................................................... 51

4.2.4 Parmetros formais ........................................................................................ 51 4.2.5 Passagem de parmetros por valor ................................................................ 52 4.2.6 Passagem de parmetros por referncia......................................................... 52 4.2.7 O comando de returno ................................................................................... 52 4.2.8 Funes sem retorno...................................................................................... 52 4.3 Recurso ............................................................................................................... 54 4.4 A funo printf()................................................................................................... 55 4.5 A funo scanf() ................................................................................................... 57 4.5.1 Operador de endereo (&) ............................................................................. 59 4.6 Funes getche() e getch().................................................................................... 59 4.7 Funes getchar() e putchar() ............................................................................... 61 4.6 Exerccios propostos............................................................................................. 62 5 Arranjos...................................................................................................................... 65 5.1 Vetores.................................................................................................................. 66 5.1.1 Exerccios Propostos ..................................................................................... 68 5.2.1 Vetores de caracteres ..................................................................................... 70 5.2.2 Funes para manipulao de vetores de caracteres...................................... 73 5.2.3 Exerccios Propostos ..................................................................................... 77 5.3 Matrizes ................................................................................................................ 78 5.3.1 Matrizes bidimensionais................................................................................ 78 5.3.2 Matrizes de cadeias de caracteres .................................................................. 80 5.3.3 Inicializaes ................................................................................................. 80 5.3.4 Inicializaes sem a especificao de tamanho ............................................. 81 5.3.5 Passagem de vetores e matrizes..................................................................... 81 5.3.6 Exerccios propostos...................................................................................... 84 5.4 Definio de estruturas ......................................................................................... 84 5.5 Enumeraes......................................................................................................... 86 5.6 Definio de nomes de tipos................................................................................. 88 5.7 Exerccios propostos............................................................................................. 89 6 Ponteiros ..................................................................................................................... 94 6.1 Exerccios propostos............................................................................................. 95 6.2 Aritmtica de Ponteiros ........................................................................................ 95 6.3 Ponteiros e Arranjos ............................................................................................. 96 6.3.1 Exerccios propostos...................................................................................... 99 6.4 Ponteiro genrico .................................................................................................. 99 6.5 Ponteiro como argumento de funes................................................................. 100 6.6 Ponteiros e estruturas.......................................................................................... 102 6.7 Exerccios propostos........................................................................................... 105 7 Estruturas de dados................................................................................................. 111 7.1 Filas .................................................................................................................... 111 7.1.1 Filas com prioridades................................................................................... 114 7.2 Pilhas .................................................................................................................. 115 7.2.1 Exerccios propostos.................................................................................... 124 7.3 Listas lineares ligadas ......................................................................................... 124 7.3.1 Funo sizeof() ..................................................................................... 126

7.3.2 Alocao dinmica de memria .................................................................. 126 7.3.3 Lista ordenada.............................................................................................. 131 7.3.4 Exerccios propostos.................................................................................... 134 Bibliografia.................................................................................................................. 139 Apndice A - Palavras reservadas em C e C++........................................................ 140 Anexo A Tabela de caracteres ASCII .................................................................... 141

Obs.: Este material foi adaptado da apostila do Prof. Ivan L. M. Ricarte lotado no Departamento de Engenharia de Computao e Automao Industrial da Unicamp. Os exerccios presentes nas listas em cada captulo desta, foram retirados ou adaptados de livros e pginas da internet e pertencem a seus respectivos donos.

Listas de Figuras
Figura 1.1 - Estrutura bsica de um algoritmo............................................................ 8 Figura 1.2 - Programa que faz nada. ............................................................................ 8 Figura 1.3 Fluxo no compilador C. ............................................................................ 9 Figura 2.1 - Composio bsica de um computador.[Linhas tracejadas indicam fluxo de controle e Linhas contnuas fluxo de dados] ............................................... 15 Figura 2.2 Complemento de base (2)........................................................................ 18 Figura 3.1 Seqncia em C - Fluxograma. .............................................................. 26 Figura 3.2 Seleo com if ... else em C......................................................... 29 Figura 3.3 Seleo usando switch ... case em C.......................................... 32 Figura 3.4 Seleo usando switch ... case em C, omitindo-se o break.... 33 Figura 3.5 Repetio usando while ... em C................................................... 34 Figura 3.6 Repetio usando do while ... em C. ............................................ 37 Figura 3.7 Repetio usando for ... em C. ...................................................... 39 Figura 5.1 Armazenando caracteres na memria RAM. ....................................... 70 Figura 6.1 - Espao ocupado pelas variveis.............................................................. 95 Figura 7.1 Fila com prioridade descendente. ........................................................ 114 Figura 7.2 Lista ligada simples............................................................................... 125

Lista de Tabelas
Tabela 2.1 Tipos de dados em C............................................................................... 12 Tabela 2.2 Caracteres de controle............................................................................ 13 Tabela 2.3 Operadores aritmticos .......................................................................... 22 Tabela 2.4 Operadores bit a bit................................................................................ 22 Tabela 2.5 Operadores relacionais........................................................................... 23 Tabela 2.6 Operadores lgicos.................................................................................. 23 Tabela 2.7 Tabela verdade dos operadores lgicos &&, || e !. ............................... 24 Tabela 2.8 Prioridade de operadores....................................................................... 24

1 Introduo
A linguagem de programao C foi desenvolvida no incio dos anos 70 nos Laboratrios AT&T Bell, nos Estados Unidos. A motivao para que o autor de C, Dennis Ritchie, criasse uma nova linguagem de programao foi o desenvolvimento do sistema operacional Unix. C uma ferramenta to bsica que praticamente todas as ferramentas suportadas por Unix e o prprio sistema operacional foram desenvolvidas em C. C acompanhou o ritmo da distribuio do sistema operacional Unix, que foi amplamente divulgado e livremente distribudo na dcada de 70. Apesar de haver compiladores para linguagens mais tradicionais na distribuio Unix, aos poucos C foi ganhando simpatizantes e adeptos. Atualmente, no h dvidas de que C uma das linguagens de programao de maior aceitao para uma ampla classe de aplicaes. A simplicidade de C no restringe, no entanto, a potencialidade de suas aplicaes. Blocos desempenhando tarefas muito complexas podem ser criados a partir da combinao de blocos elementares, e este mecanismo de combinao de partes pode se estender por diversos nveis. Esta habilidade de construir aplicaes complexas a partir de elementos simples um dos principais atrativos da linguagem. O sucesso de C foi to grande que diversas implementaes de compiladores surgiram, sendo que nem todos apresentavam o mesmo comportamento em pontos especficos, devido a caractersticas distintas da arquitetura dos computadores ou a extenses que se incorporavam linguagem. Para compatibilizar o desenvolvimento de programas em C, o Instituto Norte-Americano de Padres (ANSI) criou em 1983 um comit com o objetivo de padronizar a linguagem. O resultado deste trabalho foi publicado em 1990, e foi prontamente adotado como padro internacional. 1.1 Organizao bsica de programas C Na linguagem C, todo algoritmo deve ser traduzido para uma funo. Uma funo nada mais do que um conjunto de expresses da linguagem C (possivelmente incluindo invocaes ou chamadas para outras funes) com um nome e argumentos associados. Em geral, a definio de uma funo C tem a forma: tipo nome (lista de argumentos) { declaracoes; comandos; } O tipo indica o valor de retorno de uma funo, podendo assumir qualquer valor 7

vlido da linguagem C (que sero vistos adiante). O tipo da funo pode ser omitido, sendo que neste caso o compilador ir assumir que o tipo int (inteiro) ser retornado. O nome o rtulo dado funo, que em geral deve expressar de alguma forma o que a funo realiza. Nos compiladores mais antigos, o nmero de caracteres em um nome era limitado (em geral, a 6 ou 8 caracteres). Atualmente, no h restries ao comprimento de um nome, de forma que nomes significativos devem ser preferencialmente utilizados. Em C, todo nome que estiver seguido por parnteses ser reconhecido como o nome de uma funo. A lista de argumentos que fica no interior dos parnteses indica que valores a funo precisa para realizar suas tarefas. Quando nenhum valor necessrio para a funo, a lista ser vazia, como em ( ). O que se segue na definio da funo, delimitado entre chaves { e }, o corpo da funo. Declaraes correspondem s variveis internas que sero utilizadas pela funo, e comandos implementam o algoritmo associado funo. Todo algoritmo (e, conseqentemente, todo programa) deve ter um ponto de incio e um ponto de fim de execuo. Na figura abaixo (fig.1.1), a estrutura bsica de um algoritmo ilustrada - onde h uma nuvem faz alguma coisa, deve ser inserido o corpo do algoritmo que descreve a funo a ser realizada.

inicio

faz alguma coisa

fim Figura 1.1 - Estrutura bsica de um algoritmo. Um programa em C basicamente um conjunto de funes. O ponto de incio e trmino de execuo de um programa em C est associado com uma funo de nome especial: a funo main principal. O menor programa em C que pode ser compilado corretamente um programa que nada faz (Figura 1.2). Este programa em C : main(){ } inicio

fim Figura 1.2 - Programa que faz nada.

Neste caso, a funo de nome main() definida sem nenhum comando. Neste ponto, algumas observaes devem ser feitas: Todo programa em C tem que ter pelo menos uma funo. Pelo menos uma funo do programa em C tem o nome main() - esta funo indica o ponto onde se iniciar a execuo do programa e aps executado seu ltimo comando o programa finaliza sua execuo. Ao contrrio do que ocorre em Pascal ou FORTRAN, que diferenciam procedimentos (sub-rotinas) de funes, em C h apenas funes - mesmo que elas no retornem nenhum valor. 1.2 Criando, compilando e executando programas em linguagem C Aps as etapas de entendimento do problema e definio de uma ou mais solues para o mesmo chegado o momento de criar a representao da soluo do problema por meio do cdigo fonte. Este por sua vez nada mais do que a representao de uma soluo utilizando a sintaxe correta de uma linguagem de programao, tal qual o C. Uma ferramenta de edio de texto se faz necessria. Prefira editores de texto que tenha poucos recursos e que sejam capazes de salvar seus arquivos fontes em modo caractere, ou seja, ASCII (American Standard Code for Information Interchange). Evite utilizar editores muito sofisticados tais como Microsoft Word, Open Office Writer, etc. estes armazenam caracteres extras (de controle) que no interessam ao programa ou cdigo fonte. Por conveno o arquivo fonte deve ter a extenso .c, em minsculo. Esta atitude facilita o reconhecimento imediato de um arquivo com cdigo C, assim como extenses .pas para Pascal ou .cpp para C++. headers (.h) cdigo fonte

Pr-processador

Compilador cdigo assembly Montador bibliotecas (.obj) cdigo objeto Editor de Ligao cdigo executvel Figura 1.3 Fluxo no compilador C. 9

Como mostra a figura anterior (fig 1.3) o cdigo fonte somente o incio do trabalho de criao de programas executveis. Ainda na mesma figura (fig. 1.3) pode-se observar outras etapas. O conceito de cada uma destas etapas apresentado a seguir: pr-processador este recebe o arquivo com o cdigo fonte e responsvel por retirar os comentrios e interpretar diretivas especiais denotadas por #. Por exemplo: #include <math.h> - arq da biblioteca math. #include <stdio.h> - arq da biblioteca padro de E/S. #define TAM_MAX_ARRAY 100 compilador o compilador C traduz o cdigo fonte em cdigo assembly. Ele recebe o arquivo fonte do pr-processador. montador cria o cdigo objeto. No UNIX estes arquivos so encontrados com a extenso .o e no MS DOS com .obj. editor de ligao se o arquivo fonte referencia alguma funo de alguma biblioteca ou de algum arquivo externo cabe ao editor de ligao combinar estes arquivos com a funo main() para criar o arquivo executvel. Exemplo 1.1 Digite o programa abaixo e compile-o. O que o programa faz? (No incluir os nmeros e os dois pontos)

1: #include <stdio.h> 2: #include <conio.h> 3: int raio, area; 4: 5: main() 6: { 7: printf("Entre com o raio (ex. 10): "); 8: scanf("%d", &raio); 9: area = (int) (3.14159 * raio * raio); 10: printf("\n\nArea = %d\n", area); 11: getch(); 12: return(0); 13: } Exemplo 1.2 1: 2: 3: 4: 5: 6: 7: Digite e compile o programa a seguir. O que o programa faz?

#include <stdio.h> #include <conio.h> int x,y; main() { for (x = 0; x < 10; x++, printf ("\n")) 10

8: 9: 10: 11: 12: } Exemplo 1.3 -

for (y = 0; y < 10; y++) printf("X"); getch(); return(0); Caador de Erros: O programa seguinte apresenta um problema. Use o editor e o compilador, encontre e corrija o erro. Qual a linha contem o erro?

1: 2: 3: 4: 5: 6: 7: 8: 9:

#include <stdio.h> #include <conio.h> main(); { printf("Fique Olhando!"); printf(" Voce o encontrara!\n"); getch(); return(0); } Caador de Erros: O programa seguinte apresenta um problema. Use o editor e o compilador, encontre e corrija o erro. Qual a linha contem o erro?

Exemplo 1.4 -

1: 2: 3: 4: 5: 6: 7: 8: 9:

#include <stdio.h> #include <conio.h> main() { printf("Este e um programa com um "); do_it ("problema!\n"); getch(); return(0); } Faa a seguinte alterao no programa do exemplo 1.2. Use o editor e o compilador e execute novamente o programa. O que acontece agora?

Exemplo 1.5 -

9: printf( "%c", 1 );

11

2 Tipos, bases, operadores e expresses


A linguagem C suporta os tipos de dados bsicos usualmente suportados pelos computadores. Na linguagem padro, os tipos bsicos suportados so char, int, float e double. A tabela completa dos tipos de dados em C, aparece (tab. 2.1) logo a frente. O tipo char ocupa um nico byte, sendo adequado para armazenar um caractere do conjunto ASCII e pequenos valores inteiros. O tipo int representa um valor inteiro que pode ser positivo ou negativo. O nmero de bytes ocupado por este tipo (e, conseqentemente, a faixa de valores que podem ser representados) reflete o tamanho natural do inteiro na mquina onde o programa ser executado. Os tipos float e double representam valores reais, limitados apenas pela preciso da mquina que executa o programa. O tipo float oferece cerca de seis dgitos de preciso enquanto que double suporta o dobro da preciso de um float. Alguns destes tipos bsicos podem ser modificados por qualificadores. Por exemplo, o tipo char pode ser acompanhado pelo qualificador signed ou unsigned. O tipo signed char seria utilizado para indicar que a varivel do tipo char estaria representando pequenos nmeros inteiros (na faixa de -128 a +127). O tipo unsigned char seria utilizado para indicar que a varivel estaria armazenando valores inteiros exclusivamente positivos (sem sinal) na faixa de 0 a 255. Tabela 2.1 Tipos de dados em C Tipo Tamanho (Byte) char 1 unsigned char 1 int 2 unsigned int 2 long int 4 unsigned long int 4 short int 2 unsigned short int 2 float 4 double 8 long double 10

Valor inicial -128 0 -32.768 0 -2.147.483.648 0 -32.768 0 -3.4E-38 -1.7E-308 -3.4E-4932

Valor final +127 255 +32.767 65535 +2.147.483.647 4.294.264.295 +32.767 65535 +3.4E+38 +1.7E+308 +3.4E+4932

O tipo int tambm pode ser qualificado. Um tipo unsigned int indica que a varivel apenas armazenar valores positivos. Um tipo short int indica que (caso seja possvel) o compilador dever usar um nmero menor de bytes para 12

representar o valor numrico - usualmente, dois bytes so alocados para este tipo. Uma varivel do tipo long int indica que a representao mais longa de um inteiro deve ser utilizada, sendo que usualmente quatro bytes so reservados para variveis deste tipo. Estas dimenses de variveis denotam apenas uma situao usual definida por boa parte dos compiladores, sendo que no h nenhuma garantia quanto a isto. A nica coisa que se pode afirmar com relao dimenso de inteiros em C que uma varivel do tipo short int no ter um nmero maior de bits em sua representao do que uma varivel do tipo long int. Valores com representao em ponto flutuante (reais) so representados em C por meio do uso do ponto decimal, como em 1.5 para representar o valor um e meio. A notao exponencial tambm pode ser usada, como em 1.2345e-6 ou em 0.12E3. Caracteres ASCII so denotados entre aspas simples, tais como A. Cada caractere ASCII corresponde tambm a uma representao binria usada internamente. Por exemplo, o caractere ASCII A equivale a uma seqncia de bits que corresponde ao valor hexadecimal 41H ou decimal 65. Os valores definidos para os caracteres ASCII so apresentados na tabela localizada no anexo A. Alm dos caracteres alfanumricos e de pontuao, que podem ser representados em uma funo diretamente pelo smbolo correspondente entre aspas, C tambm define representaes para caracteres especiais de controle do cdigo ASCII por meio de seqncias de escapes iniciados pelo smbolo \ (contra barra). As principais seqncias so encontradas na tabela a seguir (tab. 2.2). Tabela 2.2 Caracteres de controle Caractere de Controle Finalidade \n Nova linha \t Tabulao \b Retrocesso \r Retorno de carro \f Salto de pgina \a Sinal sonoro \\ Contra barra \ Apstrofo \ Aspas \0 O caractere nulo 2.1 Componentes bsicos de um computador Apesar da existncia de uma grande diversidade em termos de arquiteturas de computadores, pode-se enumerar, em um ponto de vista mais genrico os componentes bsicos desta classe de equipamentos. A figura a seguir (fig 2.1) apresenta um esquema de um computador, destacando os elementos que o compem. Apesar da grande evoluo ocorrida na rea de informtica desde o aparecimento dos primeiros computadores, o esquema apresentado na figura seguinte (fig 2.1) pode ser utilizado tanto para descrever um sistema computacional atual como os computadores da dcada de 40, projetados por engenheiros como 13

John Von Neuman. Os pargrafos que seguem apresentam os componentes principais de um computador genrico. 2.1.1 Unidade Lgica e Aritmtica O primeiro componente essencial num computador (ou sistema computacional) a Unidade Lgica e Aritmtica (ALU), a qual, como o prprio nome indica, assume todas as tarefas relacionadas s operaes lgicas (ou, e, negao, etc...) e aritmticas (adies, subtraes, etc...) a serem realizadas no contexto de uma tarefa realizada por meio dos computadores. Neste contexto, importante observar a evoluo que este elemento sofreu ao longo dos anos e quais so os parmetros a ele associados que influenciam no desempenho global de um sistema computacional. Um parmetro importante o tamanho da palavra processada pela unidade lgica e aritmtica, lembrando que o sistema de numerao adotado nas arquiteturas de computadores o binrio, o qual tem como unidade bsica de informao o bit, que pode assumir os valores 0 ou 1. Quanto maior o tamanho da palavra manipulada pelo microprocessador, maior o seu potencial de clculo e maior a preciso das operaes realizadas. As primeiras CPUs integradas num nico chip, como por exemplo, o 4004 fabricado pela Intel em 1968 manipulava palavras (dados e instrues) expressas por 4 dgitos binrios. Os microprocessadores mais recentes so capazes de manipular palavras entre 32 bits (caso dos 486) e 64 bits (Pentium e Power PC). A velocidade de clculo outro fator de peso para as arquiteturas de computador, uma vez que ela ser determinante para o tempo de resposta de um sistema computacional com respeito execuo de uma dada aplicao. A velocidade de clculo est diretamente relacionada com a freqncia do relgio que pilota o circuito da CPU como um todo. Ainda relacionada com a ALU, possvel destacar a quantidade de operaes que ela suporta. Os primeiros processadores suportavam um conjunto relativamente modesto de operaes lgicas e aritmticas. Em particular, no que diz respeito s operaes aritmticas, os primeiros processadores suportavam apenas operaes de adio e subtrao, sendo que as demais operaes tinham de ser implementadas atravs de seqncias destas operaes bsicas 2.1.2 Registradores So dispositivos de alta velocidade, localizados fisicamente na UCP, para armazenamento temporrio de dados. O nmero de registradores varia em funo da arquitetura de cada processador. Alguns registradores so de uso especfico e tm propsitos especiais, enquanto outros so ditos de uso geral. o contador de instrues (CI) ou program counter (PC) o registrador responsvel pelo armazenamento de endereo da prxima instruo que a UCP dever executar. Toda vez que a UCP executa uma instruo, o PC atualizado com um novo endereo;

14

o apontador da pilha (AP) ou stack pointer (SP) o registrador que contm o endereo de memria do topo da pilha, que a estrutura onde o sistema mantm informaes sobre tarefas que estavam sendo processadas, e tiveram que ser interrompidas por algum motivo. 2.1.3 Memria Todo computador dotado de uma quantidade (que pode variar de mquina para mquina) de memria a qual se constitui de um conjunto de circuitos capazes de armazenar (temporariamente ou por longos perodos de tempo) as unidades de dados e os programas a serem executados pela mquina. Nos computadores de uso geral, possvel encontrar diferentes denominaes para as diferentes categorias de memria que neles so encontradas: a memria principal, ou memria de trabalho, onde normalmente devem estar armazenados os programas e dados a serem manipulados pelo processador; a memria secundria que permitem armazenar uma maior quantidade de dados e instrues por um perodo de tempo mais longo; os discos rgidos so os exemplos mais evidentes de memria secundria de um computador, mas podem ser citados outros dispositivos como CD-ROM, DVD, cartes de memria, etc; a memria cache, que se constitui de uma pequena poro de memria com curto tempo de resposta, normalmente integrada aos processadores e que permite incrementar o desempenho durante a realizao de um programa. UCP UC
R e g i s t r a d o r e s

ULA

Dispositivos de Entrada

Armazenamento

Dispositivos de Sada

Figura 2.1 - Composio bsica de um computador.[Linhas tracejadas indicam fluxo de controle e Linhas contnuas fluxo de dados] Os circuitos de memria so normalmente subdivididos em pequenas unidades de armazenamento denominadas palavras. Cada palavra identificada no circuito por 15

um endereo nico, o qual vai ser referenciado pelo processador no momento de consultar ou alterar o seu contedo. Historicamente, cada palavra de memria permitia armazenar 8 dgitos binrios (ou bits), o que introduziu o conceito de Byte como sendo uma palavra de 8 bits, unidade at hoje utilizada para medir a capacidade de armazenamento das memrias e o tamanho dos programas. As quantidades de memria hoje so definidas em termos de KBytes (QuiloBytes) que correspondem a 1024 Bytes ou (210 Bytes) e MBytes (MegaBytes), que correspondem a 1024 KBytes ou (220 Bytes). 2.1.4 Bases A representao de um nmero depende da base escolhida ou disponvel na mquina em uso. A base Decimal a mais empregada atualmente. Na antiguidade, foram utilizadas outras bases como a base 12, a base 60, etc. J um computador opera na base 2. (Por qu?) O que ocorre na interao entre o usurio (aplicao) e o computador? O usurio passa seus dados no sistema decimal e estes so convertidos em binrio pelo computador. Os resultados numricos obtidos no sistema binrio so convertidos para o sistema decimal e finalmente so transmitidos ao usurio. A seguir os processos de converso do sistema binrio e decimal. Binrio para Decimal (347)10 = 3 x 102 + 4 x 101 + 7 x 100 (10111)2 = 1 x 24 + 0 x 23 + 1 x 22 + 1 x 21 + 1 x 20 de modo geral, dado um nmero N na base b, na forma polinomial : N = an bn + an-1 bn-1 + ... + a2 b2 + a1 b1 + a0 b0 com esta representao pode-se facilmente converter um nmero do sistema binrio para o sistema decimal, por exemplo: (10111)2 = = 1 x 24 + 0 x 23 + 1 x 22 + 1 x 21 + 1 x 20 16 + 0 + 4 +2 +1 = (23)10

16

Decimal para Binrio Mtodo da Diviso Sucessiva por 2. (11)10 = (?)2 11 1 2 5 1 2 2 0 (1011)2 Representao de nmeros Como o computador armazena inteiros positivos? Usando todos os bits disponveis para armazenamento. [0, b n] -1 Como o computador armazena inteiros negativos? Sinal-magnitude 0 = + e 1 = - Ex.: 1111, ..., 1000 = - 7, ..., - 0; Complemento da Base Veja figura (fig. 2.2). N = b n-1 - a Ex.: 1000, ..., 1111 = - 8, ..., - 1; 0000, ..., 0111 = 0, ..., 7; ?no existe? Como o computador armazena os caracteres? 0000, ..., 0111 = 0, ..., 7; 2 1

Exerccios 1.1 Sabe-se que os computadores tm a sua disposio apenas zeros e uns para representarem os mais diversos dados. Abaixo vemos nmeros em notao decimal, normalmente utilizada pelo ser humano no seu cotidiano. Converter esses nmeros, em uma notao que o computador possa trabalhar, ou seja, em nmeros binrios. 57d 27d 79d 75d 010d 101d 33d 73d 44d 94d 67d 62d 89d 19d 204d 106d 03d 13d 99d 39d 224d 020d 17

Exerccios 1.2 Os nmeros binrios abaixo, que bem poderiam estar na memria de um computador, esto representando quais nmeros decimais? 11011010b 11011110b 10011010b 11101010b 10001010b 10101010b 01011101b 01110101b 01010111b 00100011b 00110011b 00110111b 11010001b 11010010b 11010100b

Figura 2.2 Complemento de base (2) 2.1.5 Unidade de Controle Este ltimo componente de um sistema computacional tem, sem dvida alguma, a maior importncia na operao de um computador, uma vez que esta unidade quem assume toda a tarefa de controle das aes a serem realizadas pelo computador, comandando todos os demais componentes de sua arquitetura. este elemento quem deve garantir a correta execuo dos programas e a utilizao dos dados corretos nas operaes que as manipulam. a unidade de controle que gerencia todos os eventos associados s operaes dos computadores, particularmente as chamadas interrupes. Tanto a unidade de controle quanto a unidade lgica e aritmtica so implementadas em um circuito nico conhecido sob a sigla de CPU (Central Processing Unit) ou por Unidade Central de Processamento, Microprocessador ou, simplesmente, Processador. 2.2 Declaraes de variveis Variveis representam uma forma de identificar por um nome simblico uma regio da memria que armazena um valor sendo utilizado por uma funo. Em C, uma varivel deve estar associada a um dos tipos de dados presentes na tabela anterior (tab. 2.1). Toda varivel que for utilizada em uma funo C deve ser previamente declarada. A forma geral de uma declarao de varivel : tipo nome_variavel; ou tipo nome_var1, nome_var2, ... ; 18

onde nome_var1, nome_var2, ... so variveis de um mesmo tipo de dado. Exemplos vlidos de declarao de variveis em C so: int um_inteiro; unsigned int outro_inteiro; char c1, c2; float salario; double x, y; Nomes de variveis podem ser de qualquer tamanho, sendo que usualmente nomes significativos devem ser utilizados, mas somente os 31 primeiros caracteres so considerados. C faz distino entre caracteres maisculos e caracteres minsculos, de forma que Salario diferente de salario. H restries aos nomes de variveis. Palavras associadas a comandos e definies da linguagem (tais como if, for e int) so reservadas, no podendo ser utilizadas para o nome de variveis. A lista de palavras reservadas em C apresentada no Apndice A. O nome de uma varivel pode conter letras, nmeros e o sublinha ( _ ), mas deve comear com uma letra. Como se pode observar no exemplo acima diversas variveis de um mesmo tipo podem ser declaradas em um mesmo comando, sendo que o nome de cada varivel neste caso estaria separado por vrgulas. Alm disto, variveis podem ser tambm inicializadas enquanto declaradas, como em: int a = 0, b = 20; char c = X; long int d = 12345678; 2.2.1 Definindo contantes Uma maneira de se declarar constantes muito semelhante declarao de variveis com inicializao, exceto que o seu valor permanecer inalterado. Uma varivel cujo valor no ser alterado pelo programa pode ser qualificada como const, como em: const int NotaMaxima = 100; Neste caso, a varivel NotaMaxima no poder ter seu valor alterado. Evidentemente, variveis deste tipo devem ser inicializadas no momento de sua declarao. Outra forma de declarar constantes simblicas por meio da clusula #define logo no incio do programa. #define MAX #define PI 1024 3.1415926

19

2.2.2 Definindo variveis globais Variveis globais so definidas acima da funo main() e seguem a forma abaixo: short int soma; char letra; main () { soma = 0; letra = a; ... } Estas tambm podem ser inicializadas como mostra a funo main() no mesmo exemplo. 2.3 Expresses Aps a declarao das variveis, o corpo de uma funo definido atravs dos comandos que sero executados pela funo. Estes comandos devem ser expressos sob a forma de uma seqncia de expresses vlidas da linguagem C. Antes de mas nada, interessante que se apresente a forma de se expressar comentrios em um programa C. Comentrios em C so indicados pelos terminadores /* (incio de comentrio) e */ (fim de comentrio). Quaisquer caracteres entre estes dois pares de smbolos so ignorados pelo compilador. Comentrios em C no podem ser aninhados, mas podem se estender por diversas linhas e podem comear em qualquer coluna. Por exemplo, /* Exemplo de * comentario */ main(){ /* esta funcao que faz coisa alguma */ } As expresses na linguagem C so sempre terminadas pelo smbolo ; (ponto e vrgula). Uma expresso nula constituda simplesmente pelo smbolo terminador. Assim, o exemplo acima equivalente a /* Exemplo de * comentario */ main(){ /* esta funcao nao faz coisa alguma */ ; } 20

2.3.1 Expresses Aritmticas O comando de atribuio em C indicado pelo smbolo =, como em: main(){ int a, b, c; a = 10; b = c = a; }

/* a recebe valor 10 */ /* b e c recebem o valor de a (10) */

Observe neste exemplo que a atribuio pode ser encadeada - na ltima linha da funo acima, c recebe inicialmente o valor da varivel a, e ento o valor de c ser atribudo varivel b. Expresses aritmticas em C podem envolver os operadores binrios (isto , operadores que tomam dois argumentos) de soma (+), subtrao (-), multiplicao (*), diviso (/), lista completa na tabela abaixo (tab 2.3). Valores negativos so indicados pelo operador unrio -. Adicionalmente, para operaes envolvendo valores inteiros so definidos os operadores de resto da diviso inteira ou mdulo (%), incremento (++) e decremento (--). Por exemplo, main(){ int a b = 2 a++; c = b d = b } = 10, b, c, d; * a; / a; % a;

/* /* /* /*

b = 20 */ a = a+1 (11) */ divisao inteira: c = 1 */ resto da divisao: d = 9 */

Cada um dos operadores de incremento e decremento tem duas formas de uso, dependendo se eles ocorrem antes do nome da varivel (pr-incremento ou prdecremento) ou depois do nome da varivel (ps-incremento ou ps-decremento). No caso do exemplo acima, onde o operador de incremento ocorre de forma isolada em uma expresso (sozinho na linha), as duas formas possveis so equivalentes. A diferena entre eles ocorre quando estes operadores so combinados com outras operaes. No exemplo acima, as linhas de atribuio b e incremento de a poderiam ser combinados em uma nica expresso, b = 2*(a++); /* b recebe 2*a e entao a recebe a+1 */

Observe como esta expresso diferente de b = 2*(++a); /* a recebe a+1 e entao b recebe 2*a */

Na prtica, os parnteses nas duas expresses acima poderiam ser omitidos uma vez que a precedncia do operador de incremento maior que da multiplicao, ou seja, o incremento ser avaliado primeiro. A subseo 2.3.3 apresenta a ordem de avaliao para todos os operadores da linguagem C (tab. 2.8).

21

Tabela 2.3 Operadores aritmticos Smbolo Significado + adio * multiplicao subtrao ou inversor do sinal / diviso % resto da diviso de inteiros ++ incremento -decremento = atribuio +=, -=, *=, /= formas compactas para operaes aritmticas A linguagem C tem tambm uma forma compacta de representar expresses na forma: var = var op (expr); onde uma mesma varivel var aparece nos dois lados de um comando de atribuio. A forma compacta : var op= expr; Por exemplo, a += b; c *= 2; /* equivale a a = a+b */ /* equivale a c = c*2 */

O operador % trabalha somente com operadores int. J a / (barra) funciona para int e float. Mas esteja atento, pois r = 5/2 ser igual a 2, mesmo que r tenha sido declarado como float. Esteja certo de especificar r = 5/2.0 ou r = 5.0/2, ou ainda melhor r = 5.0/2.0. Se preferir, r = (float) 5/2;. A linguagem C oferece tambm operadores que trabalham sobre a representao binria de valores inteiros e caracteres. Estes operadores so apresentados na tabela (tab. 2.4) a seguir. Tabela 2.4 Operadores bit a bit Smbolo & | ^ << >> ~

Significado and bit a bit (mascara de 0s) or bit a bit (mascara de 1s) xor bit a bit deslocamento de bits esquerda (* por 2) deslocamento de bits direita (/ por 2) complemento (inverte cada bit)

Estes operadores tomam dois argumentos exceto pelo operador ~, que unrio. Ex.:

22

a = a & 0xDF; x = y >> 3; x = y << 2;

/* Dec 223, converte a para maisculo */ /* divide por 8 */ /* multiplica por 4 */

2.3.2 Expresses Condicionais Um tipo muito importante de expresso em C a expresso condicional, cujo resultado um valor que ser interpretado como falso ou verdadeiro. Como a linguagem C no suporta diretamente o tipo de dado booleano, ela trabalha com representaes inteiras para denotar estes valores. O resultado de uma expresso condicional um valor inteiro que ser interpretado como falso quando o valor resultante da expresso igual a 0, e como verdadeiro quando o valor resultante diferente de 0. Assim, qualquer expresso inteira pode ser interpretada como uma expresso condicional. A situao mais comum, entretanto, ter uma expresso condicional comparando valores atravs dos operadores relacionais. Os operadores relacionais (tab. 2.5) em C so: Tabela 2.5 Operadores relacionais Operador Operao == igual a != diferente de < menor que > maior que <= menor que ou igual a >= maior que ou igual a Observe que o operador de igualdade ==, e no = que o smbolo de atribuio conforme mostra a tabela anterior (tab. 2.3). Esta uma causa comum de erros para programadores que esto acostumados com outras linguagens onde = um operador relacional. Expresses condicionais elementares (comparando duas variveis ou uma varivel e uma constante) podem ser combinadas para formar expresses complexas atravs do uso de operadores booleanos. Estes operadores (tab. 2.6) so: Tabela 2.6 Operadores lgicos Operador Operao && conjuno (and) || disjuno (or) ! negao (not) O operador && (and) resulta verdadeiro (tab. 2.7) quando as duas expresses envolvidas so verdadeiras (ou diferente de 0). O operador || (or) resulta verdadeiro quando pelo menos uma das duas expresses envolvidas verdadeira. Alm destes dois conectores binrios, h tambm o operador unrio de negao, !, que resulta falso quando a expresso envolvida verdadeira (diferente de 0) ou resulta verdadeiro quando a expresso envolvida falsa (igual a 0) .

23

Tabela 2.7 Tabela verdade dos operadores lgicos &&, || e !. Operador A B Operador || Operador ! (A) && 1 1 1 0 1 1 0 1 0 0 0 1 1 1 0 0 0 0 1 0 Expresses lgicas complexas, envolvendo diversos conectores, so avaliadas da esquerda para a direita. Alm disto, && tem precedncia maior que ||, e ambos tm precedncia menor que os operadores lgicos relacionais e de igualdade. Entretanto, recomenda-se sempre a utilizao de parnteses em expresses para tornar claro quais operaes so desejadas. A exceo a esta regra ocorre quando um nmero excessivo de parnteses pode dificultar ainda mais a compreenso da expresso; em tais casos, o uso das regras de precedncia da linguagem pode facilitar o entendimento da expresso. 2.3.3 Prioridade de operadores Durante a execuo de uma expresso que envolve vrios operadores, necessrio existir certas prioridades, caso contrrio pode-se obter valores que no representam o resultado esperado. A linguagem C utiliza as seguintes prioridades de operadores (tab. 2.8): Tabela 2.8 Prioridade de operadores Alta prioridade ( ) [ ] -> . ! - * & sizeof (type) ++ -da direita para esquerda * / % + << >> < <= >= > == != & ^ | && || ?: da direita para esquerda = += -= etc. da direita para esquerda , vrgula Baixa prioridade 2.4 Exerccios propostos Exerccio 2.3 Entre com dois nmeros e d como resultado a soma, a mdia e o 24

Exerccio 2.4 Exerccio 2.5

somatrio dos quadrados dos nmeros. Escreva um programa que mostre o maior e o menor valor de um conjunto de 10 valores inteiros fornecidos. Escreva um programa que leia um nmero fracionrio representado um nmero de grau Celsius e exiba como um nmero fracionrio temperatura equivalente em Fahrenheit. Mostre o resultado como segue: 100.0 graus Celsius convertido para 212.0 graus Fahrenheit.

Exerccio 2.6

Escreva um programa para ler um nmero de unidade de comprimento (um fracionrio) e mostre a rea do crculo deste raio. Assuma com valor do pi 3.14159 (uma apropriada declarao deve ser dado a esta constante). A sada deveria ter a seguinte forma: A rea do crculo de raio ___ unidades e ___ unidades.

Se voc desejar melhorar este cdigo, exiba a mensagem: Erro: valores negativos no so permitidos. Se o valor de estrada for negativo. Exerccio 2.7 Dada uma entrada de um nmero de centmetros em fracionrio, mostre o equivalente em nmero de ps e polegadas (fracionrio, 1 decimal), isto , uma preciso de uma casa decimal. Assuma 2.54 centmetros por polegada e 12 polegadas por p.

Se a entrada for 333.3, a sada deveria ser: 333.33 centmetros e 10 ps ou 11.2 polegadas. Exerccio 2.8 Dada uma entrada de um nmero de segundos, exibir como sada o equivalente em horas, minutos e segundos. Recomenda-se o formato de sada alguma coisa como: 7322 segundos e equivalente a 2 horas, 2 minutos e 2 segundos. Exerccio 2.9 Faa um programa que, dada a rea de um crculo, calcule o permetro da circunferncia que o limita. Use preciso simples. A = r2, portanto r = raiz (A / ) e P = 2 r.

Exerccio 2.10 Faa um programa que determine o volume de uma esfera, sendo dado o respectivo raio. (V = 4 / 3 r3). Repare que, em C, a diviso de 4 por 3 d um valor inteiro se no tomar medidas adequadas. Exerccio 2.11 Faa um programa que determine se um ano introduzido pelo usurio ou no bissexto. Um ano bissexto se for mltiplo de 4 sem ser de 100 ou se for mltiplo de 400.

25

3 O controle do fluxo de execuo


C uma linguagem que suporta a programao estruturada, ou seja, permite agrupar comandos na forma de seqncia, seleo e repetio. 3.1 Seqncias Uma seqncia de comandos em uma funo C denotada simplesmente como uma seqncia de expresses, como exemplificado na figura a seguir (fig. 3.1). H duas possibilidades: usar comandos isolados (a forma mais utilizada) ou usar uma nica expresso com a seqncia de comandos separados pelo operador , (vrgula).

Figura 3.1 Seqncia em C - Fluxograma. Formas equivalentes em C: a = 10; b = a*5; c = a+b; ou a=10, b=a*5, c=a+b;

26

3.2 Ifs A seguir mostram-se algumas partes de programas com exemplos de uso do comando if: Exemplo 3.1 Validando a entrada de um inteiro que representa um dia do ms.

... scanf("%d", &dia); if (dia > 31 || dia < 1) /* || significa ou */ printf("Dia invalido\n"); ... Exemplo 3.2 Teste com um nmero inteiro, indicando se este positivo ou negativo.

... scanf("%d", &numero); if (numero >= 0) printf("Numero positivo\n"); else printf("Numero negativo\n"); ... Exemplo 3.3 - Determinando a alquota a ser calculada sobre a varivel fracionria salario. ... scanf("%f", &salario); if (salario < 1499.15) { printf("Aliquota de imposto 15,0%\n"); imposto = salario * 0.15; } else { printf("Aliquota de imposto 27,5%\n"); imposto = salario * 0.275; } ... Uma construo que pode aparecer so os comandos if's aninhados ou encaixados, cuja forma geral a seguinte: if (expressao) comando; else if (expressao) comando; else if (expressao) comando; ... 27

else comando; Exemplo 3.4 - O programa, Calculadora Simples, a seguir mostra um exemplo com if's encaixados e aninhados. #include <stdio.h> #include <conio.h> main(){ float num1,num2,res; char oper; printf("\nCalculadora simples\n"); printf("Por favor entre com os dois operandos.\n"); scanf("%f %f", &num1, &num2); printf("Voce digitou %.2f e %.2f\n", num1, num2); printf("Qual a operacao \n"); oper = getch(); printf("A operacao e %c\n", oper); if (oper == '+') res = num1 + num2; else if (oper == '-') res = num1 - num2; else if (oper == '*') res = num1 * num2; else if (oper == '/') if (num2 == 0.0){ printf("Divisao por 0 invalida"); getch(); return(1); } else res = num1 / num2; else{ printf("Operacao invalida!\n"); getch(); return(1); } printf("O resultado da %c vale %f.\n", oper, res); getch(); return(0); } A construo de seleo IF-THEN-ELSE expressa em C na forma if ... else (fig. 3.2). Aps a palavra-chave if deve haver uma expresso condicional entre parnteses. Se a expresso for avaliada como verdadeira, ento a expresso sob o if ser realizada; se for falsa, a expresso sob o else ser executada. Nesta figura (fig. 3.2), introduz-se o conceito de expresso composta, ou seja, a expresso da parte else deste exemplo na verdade um bloco contendo diversas expresses. Neste caso, o bloco de comandos que deve ser executado nesta condio deve ser delimitado por chaves { e }. Algumas observaes adicionais relevantes com relao a este comando so: 28

1.

2. 3. 4.

Em C, h diferenas entre letras minsculas e maisculas. Como todos os comandos em C, as palavras chaves deste comando esto em letras minsculas. Assim, as formas IF (ou If ou iF) no so formas vlidas em C para denotar o comando if. Ao contrrio do que ocorre em Pascal ou FORTRAN, a palavra then no faz parte da sintaxe deste comando em C. A clusula else pode ser omitida quando a expresso a executar na condio falsa for nula. No caso de haver mais de um if que possa ser associado a uma clusula else, esta ser associada ao comando if precedente mais prximo.

Figura 3.2 Seleo com if ... else em C. Forma equivalente em C: if (a == 10) b = b-c; else { c = a*10; b = b+a; } 3.3 Switch A construo estruturada de seleo CASE-SELECT suportada em C pelo comando switch ... case (fig. 3.3). Neste caso, aps a palavra-chave switch deve haver uma varivel do tipo inteiro ou caractere entre parnteses. Aps a varivel, deve haver uma lista de casos que devem ser considerados, cada caso iniciando com a palavra-chave case seguida por um valor ou uma expresso inteira. O comando if, em todas suas formas, suficiente para resolver problemas de seleo de comandos. Porm em alguns casos, como no exemplo anterior (ex. 3.4) o programa se torna mais trabalhoso para ser escrito. O comando switch facilita a escrita de partes de programa em que a seleo deve ser feita entre vrias alternativas. A forma geral do comando switch a seguinte:

29

switch (expressao) { case constante1: comandos; break; case constante2: comandos; break; case constante3: comandos; break; ... default: comandos; } A execuo do comando segue os seguintes passos: 1. 2. 3. A expresso avaliada; O resultado da expresso comparado com os valores das constantes que aparecem nos comandos case; Quando o resultado da expresso for igual a uma das constantes, a execuo se inicia a partir do comando associado com esta constante. A execuo continua com a execuo de todos os comandos at o fim do comando switch, ou at que um comando break seja encontrado; Caso no ocorra nenhuma coincidncia o comando default executado. O comando default opcional e se ele no aparecer nenhum comando ser executado; O comando break um dos comandos de desvio da linguagem C. O break se usa dentro do comando switch para interromper a execuo e pular para o comando seguinte ao comando switch;

4. 5.

H alguns pontos importantes que devem ser mencionados sobre o comando switch: 1. 2. 3. 4. Exemplo 3.5 O resultado da expresso deve ser um tipo compatvel com um inteiro, isto , expresses com resultados tipo char tambm podem ser usadas; Notar que caso no aparea um comando de desvio todas as instrues seguintes ao teste case que teve sucesso sero executadas, mesmo as que estejam relacionadas com outros testes case; O comando switch s pode testar igualdade, veja exemplo a seguir (ex. 3.5); No podem aparecer duas constantes iguais em um case; O programa, Calculadora Simples 2, mostra um exemplo com a utilizao do comando switch.

30

#include <stdio.h> #include <conio.h> main(){ float num1,num2,res; char oper; printf("\nCalculadora simples\n"); printf("Por favor entre com os dois operandos.\n"); scanf("%f %f", &num1, &num2); printf("Voce digitou %.2f e %.2f\n", num1, num2); printf("Qual a operacao \n"); oper = getch(); printf("A operacao e %c\n", oper); switch (oper){ case + : res = num1 + num2; break; case - : res = num1 - num2; break; case * : case x : case X : res = num1 * num2; break; case / : if (num2 == 0.0){ printf("Divisao por 0 invalida"); getch(); return(1); } else{ res = num1 / num2; break; } default:{ printf("Operacao invalida!\n"); getch(); return(1); } } printf("O resultado da %c vale %f.\n", oper, res); getch(); return(0); }

31

Figura 3.3 Seleo usando switch ... case em C. Forma equivalente em C: switch (a){ case 10: a = a+1; break; case 20: a = a+2; break; case 100:a = a+5; break; default: a = a+10; } Observe que o conjunto de aes associado a cada caso encerra-se com a palavra-chave break. Neste exemplo (ex. 3.5), a varivel a pode ser do tipo int ou char. A palavra-chave especial default indica que a ao deve ser tomada quando a varivel assume um valor que no foi previsto em nenhum dos casos. Assim como a condio else no comando if opcional, a condio default tambm opcional para o switch-case. Observe tambm a importncia da palavra-chave break para delimitar o escopo da ao de cada caso - fossem omitidas as ocorrncias de break no exemplo anterior (ex. 3.5), a semntica associada ao comando seria essencialmente diferente (fig. 3.4).

32

Figura 3.4 Seleo usando switch ... case em C, omitindo-se o break. Forma equivalente em C: switch (a){ case 10: a case 20: a case 100:a default: a } 3.4 Comando ternrio O comando ternrio tem este nome porque necessita de trs operandos para ser avaliado. O comando ternrio tem a seguinte forma: expressao1 ? expressao2 : expressao3 Para avaliar o resultado da expresso primeiro expresso1 avaliada. Caso este resultado seja correspondente ao valor verdadeiro ento o resultado da expresso ser igual ao valor da expressao2, caso contrrio a expresso3 avaliada e se torna o resultado. Exemplo 3.6 O programa determina o maior nmero entre dois valores fornecidos pelo usurio usando o comando ternrio. = = = = a+1; a+2; a+5; a+10;

#include <stdio.h> 33

#include <conio.h> main(){ float num1,num2,maior; printf("Por favor entre com os dois numeros.\n"); scanf("%f %f", &num1, &num2); maior = (num1 > num2) ? num1 : num2; printf("O maior dos numeros lidos e %f.\n", maior); getch(); return(0); } 3.5 Repeties Comandos de repetio em C so suportados em trs formas distintas. A primeira forma while, cuja construo equivale ao comando estruturado WHILEDO, enquanto que a segunda forma equivale ao comando estruturado DO-WHILE. Por fim, tem-se o comando for que equivale a estrutura FOR-DO. 3.5.1 Comando while O comando while tem a seguinte forma geral: while (expressao) comando; A expresso pode assumir o valor falso (igual a 0) ou verdadeiro (diferente de 0). Os passos para execuo do comando so os seguintes: 1. 2. 3. 4. A expresso avaliada; Se a expresso for verdadeira ento o comando executado, caso contrrio a execuo do comando terminada; Voltar para o passo 1. Uma caracterstica do comando while, como pode ser visto dos passos acima, que o comando pode no ser executado.

Figura 3.5 Repetio usando while ... em C. 34

Forma equivalente em C: while (a != 10) a = a+1; Exemplo 3.7 - O programa que mostra os nmeros de 1 5 usando o comando while. #include <stdio.h> #include <conio.h> main(){ int i = 1; while (i <= 5){ printf("Numero %d\n", i); i++; } printf("\nAcabou!\n"); getch(); return(0); } O trecho acima (ex. 3.7) escrito de forma mais compacta fica: i = 1; while (i <= 10) printf("Numero %d\n", i++); ... Este programa (ex. 3.8) solicita nmeros ao usurio at que a soma de todos os nmeros digitados for pelo menos 20. Exemplo 3.8 - Solicitar do usurio valores inteiros at que o somatrio destes seja pelo menos 20. #include <stdio.h> #include <conio.h> main(){ int total = 0, num; while(total < 20){ printf("Total = %d\n", total); printf("Entre com um numero: "); scanf("%d",&num); total += num; 35

printf("Total final = %d\n", total); } getch(); return(0); } A expresso do comando pode incluir chamada de funo. Lembrar que qualquer atribuio entre parnteses considerada como uma expresso que tem o valor da atribuio sendo feita. Por exemplo, o trecho abaixo (ex 3.9) repete um bloco de comandos enquanto o usurio usar a tecla 'c' para continuar, qualquer outra tecla o bloco interrompido. Exemplo 3.9 - O programa que o usurio pode controlar o nmero de vezes os comandos do while iro ser executados. #include <stdio.h> #include <conio.h> main(){ char c; printf("Tecle c para continuar.\n"); while ((c=getche()) == 'c'){ printf("\nNao Acabou.\n"); } printf("\nAcabou.\n"); getch(); return(0); } 3.5.2 Comando do while O comando do while tem a seguinte forma geral: do comando; while (expressao); Observar que neste comando a expresso de teste est aps a execuo do comando, portanto o comando executado pelo menos uma vez. A execuo do comando segue os seguintes passos: 1. 2. 3. Executa o comando; Avalia a expresso; Se a expresso for verdadeira ento volta para o passo 1, caso contrrio interrompe-se o do-while.

36

Figura 3.6 Repetio usando do while ... em C. Forma equivalente em C: do a = a+1; while (a != 10); Exemplo 3.10 - O programa que mostra os nmeros de 1 10 usando o comando do while. #include <stdio.h> #include <conio.h> main(){ int i = 1; do{ printf("Numero %d\n", i); i++; }while (i <= 10); getch(); return(0); } Neste exemplo (ex. 3.11), o teste do lao baseado no valor digitado pelo usurio. O lao deve ser executado pelo menos uma vez antes que o teste sobre o valor seja executado. Exemplo 3.11 - Construir um programa para garantir que a entrada fornecida pelo usurio seja um nmero par. Utilize o comando do while. #include <stdio.h> #include <conio.h> main(){ int num; 37

printf("Entre com um numero par:"); do{ scanf("%d",&num); }while(num % 2 != 0); printf("Obrigado.\n"); getch(); return(0); } 3.5.3 Comando for Este comando aparece em vrias linguagens de programao, mas na linguagem C ele apresenta um grau maior de flexibilidade. A idia bsica do comando for a seguinte: A forma geral do comando for a seguinte: for (expressao1; expressao2; expressao3) comando; equivalente a expressao1; while (expressao2){ comando; expressao3; } As trs expresses geralmente tm os seguintes significados: A expressao1 utilizada para inicializar a varivel de controle do lao; A expressao2 um teste que controla o fim do lao; A expressao3 normalmente faz um incremento ou decremento da varivel de controle. A execuo do comando for segue os seguintes passos: 1. 2. 3. 4. 5. A expressao1 avaliada; A expressao2 avaliada para determinar se o comando deve ser executado; Se o resultado da expressao2 for verdadeiro o comando executado, caso contrrio o lao terminado; A expressao3 avaliada; Voltar para o passo 2.

38

Figura 3.7 Repetio usando for ... em C. Forma equivalente em C: for (a = 0; a < MAX; ++a) b = 2 * b; Exemplo 3.12 - O programa que mostra os nmeros de 0 10 usando o comando for. #include <stdio.h> #include <conio.h> main(){ int i; for (i = 0; i <=10; i++) printf("Numero %d\n", i); getch(); return(0); } possvel omitir qualquer uma das expresses. Por exemplo, se a expressao2 for omitida o programa assume que ela sempre verdade de modo que o lao s termina com um comando de desvio como o break. Exemplo 3.13 - O programa que mostra os nmeros de 0 5 usando o comando for em conjunto com o comando break. #include <stdio.h> #include <conio.h> main(){ int i; for (i = 0; ; i++){ printf("Numero %d\n", i); if (i == 5) break; 39

} getch(); return(0); } Exemplo 3.14 - O programa que mostra a tabuada da multiplicao dos nmeros de 1 10. #include <stdio.h> #include <conio.h> main(){ int i, j; for (i = 1;i < 10; i++){ printf("Tabuada de %d\n", i); getch(); for (j = 1;j < 10; j++) printf("\n%d x%d = %d\n", i, j, i * j); } getch(); return(0); } Exemplo 3.15 - O programa que mostra como se pode calcular o fatorial de um nmero usando o comando for. #include <stdio.h> #include <conio.h> int main(){ unsigned int numero, i, fat = 1; printf("\nEntre com um numero positivo."); scanf("%u", &numero); for (i = numero; i > 1; i--) fat = fat * i; printf("O fatorial de %u vale %u.", numero, fat); getch(); return(0); }

Laos for com mais de um comando por expresso

40

Outra possibilidade que o comando for em C permite e a incluso de mais de um comando, separados por vrgulas, nas expresses. O exemplo a seguir (ex. 3.16) mostra o uso de comando for com vrios comandos nas expresses. Exemplo 3.16 - O programa que usa seqncia nas expresses do comando for. #include <stdio.h> #include <conio.h> void main(){ int i,j; for (i = 1, j = 10; i <= 10; i++, j += 10){ printf ("i = %d, j = %d\n", i, j); } getch(); } Laos for com testes com outras variveis A expresso de controle no precisa necessariamente envolver somente um teste com a varivel que controla o lao. O teste de final do lao pode ser qualquer expresso relacional ou lgica. No exemplo seguinte (ex. 3.17) o lao pode terminar porque a varivel de controle j chegou ao seu valor limite ou foi batida a tecla '*'. Obs.: getchar() necessitado do <enter> para terminar. Exemplo 3.17 - O programa que testa mais de uma expresso no comando for. #include <stdio.h> #include <conio.h> #include <ctype.h> void main(){ char c; int i; for (i = 0 ;(i < 5) && (c = getchar()) != '*';i++){ printf("%c\n", toupper(c)); c = getchar(); } getch(); } Laos for com expresses faltando Um outro ponto importante do for que nem todas as expresses precisam estar presentes. No exemplo na seqncia (ex. 3.18) a varivel de controle no incrementada. A nica maneira de programa terminar o usurio digitar o nmero -1. 41

Exemplo 3.18 - O programa que depende do usurio para terminar usando o comando for. #include <stdio.h> #include <conio.h> void main(){ int i; for (i = 0 ;i != -1; ){ printf("%d\n", i); scanf("%d", &i); } getch(); } Lao infinito Uma construo muito utilizada o lao infinito. No lao infinito o programa para quando se usa o comando break. No exemplo abaixo (ex. 3.19) o programa s para quando for digitada ou a tecla 's' ou 'S'. Exemplo 3.19 - O programa que depende do usurio para terminar usando o comando for. #include <stdio.h> #include <conio.h> #include <ctype.h> void main(){ int c; for ( ; ; ){ printf("\nVoce deseja parar?\n"); c = getche(); if (toupper(c) == S) break; } getch(); } Laos aninhados Uma importante construo aparece quando colocamos como comando a ser repetido um outro comando for. Esta construo aparece quando estamos trabalhando com matrizes. O exemplo anterior (ex. 3.14) mostra um programa que imprime uma tabuada. Desviando laos 42

Qualquer que seja a forma usada para indicar o comando de repetio - while, do while ou for - h duas formas de se desviar a seqncia de execuo do padro do comando. A primeira forma, continue, serve para indicar o fim prematuro de uma iterao. A outra forma de interrupo de um comando de repetio o comando break, que indica o fim prematuro de todo o comando de iterao. Como por exemplo: ... for (a = 0; a < MAX; ++a){ if (b == 0){ b = a; continue; } c = c / b; b = b 1 ; } ... se a linha com o comando continue for executada, o valor de a ser incrementado e ento o teste da iterao ser reavaliado para definir a continuidade ou no do lao de repetio. J no exemplo abaixo, ... for (a = 0; a < MAX; ++a){ if (b == 0) break; c = c / b; b = b - 1; } ... quando (se) b assumir o valor 0, o lao ser simplesmente interrompido. 3.6 Exerccios propostos Exerccio 3.1 Faa um programa que leia vrios nmeros e informe a mdia dos nmeros fornecidos. Quando o usurio digitar 0 (zero) o programa termina. Faa um programa que calcule que determine as razes de uma equao do tipo ax2 + bx + c = 0. Sendo = b2 - 4ac, as razes da equao so dadas por:

Exerccio 3.2

43

Se a = 0, o programa no deve efetuar nenhum clculo, mas visualizar uma mensagem adequada. Exerccio 3.3 Faa um programa que determine se um ano introduzido pelo usurio ou no bissexto. Um ano bissexto se for mltiplo de 4 sem ser de 100 ou se for mltiplo de 400. Faa um programa que calcule a soma de dez nmeros inteiros dados pelo usurio. Faa um programa que calcule a soma n nmeros inteiros consecutivos que comeam num valor dado pelo usurio. Ler um caractere do teclado e verificar se um caractere de pontuao: , ou . ou ; ou ! ou ?. Verificar se um caractere lido do teclado maisculo ou minsculo (entre a e z minsculo). Ler uma string do teclado com a funo gets(s) e imprimir o nmero de ocorrncias do caractere a. Fazer maiscula(s): transforma todas as letras minsculas em maisculas em s.

Exerccio 3.4 Exerccio 3.5 Exerccio 3.6 Exerccio 3.7 Exerccio 3.8 Exerccio 3.9

Exerccio 3.10 Escreva um programa que calcule x elevado a n. Assuma que n um valor inteiro. Exerccio 3.11 Escreva um programa que exiba um menu com as opes "1multiplicar" e "2-somar", leia a opo desejada, leia dois valores, execute a operao (utilizando o comando "if") e exiba o resultado. Exerccio 3.12 Utilizando if's em escada, inclua, no programa do exerccio anterior, as opes "3-Subtrair" e "4-Dividir". Exerccio 3.13 Simplifique os programas anteriores da seguinte forma:

44

Reescreva o programa do exerccio 1 substituindo o comando "if" pelo comando ternrio. Reescreva o programa do exerccio 2 substituindo os if's em escada pelo comando "switch". Exerccio 3.14 Utilizando um lao "while" e o comando "break", escreva um programa que exiba a mensagem HA-HA-HA!! Voc est preso at que a senha FUI!! seja digitada. Exerccio 3.15 Utilizando um lao "for" dentro de outro, escreva um programa que exiba as tabuadas de multiplicao dos nmeros de 1 a 9. Exerccio 3.16 Escreva um programa que tenha um nmero (inteiro) como entrada do usurio e escreva como sada a seqncia de bits que forma esse numero. Por exemplo, aps ter digitado o nmero 10, a sada deve ser 0000000000001010. Exerccio 3.17 Escreva um programa que imprima todos os nmeros pares entre 0 e 50 e em seguida imprima todos os impares. Deixar um espao entre os nmeros. Exerccio 3.18 Escreva um programa que leia 10 nmeros. O programa deve imprimir a media, o maior e o menor deles. Obs: Os nmeros devem ser entre 0 e 10. Exerccio 3.19 Escreva um programa que leia 10 nmeros. O programa deve imprimir a media, o maior e o menor deles. Obs: Considere agora que os nmeros podem ser quaisquer. Exerccio 3.20 Escreva um programa que exibe a tabela ascii. Exerccio 3.21 Crie um programa para verificar se um nmero dado primo. Exerccio 3.22 Escreva um programa que leia um nmero inteiro do teclado e acha se o nmero e primo ou no. O programa deve informar o menor divisor. Exerccio 3.23 Escreva um programa que leia um nmero do teclado e ache todos os seus divisores. Exerccio 3.24 Escreva um programa que imprima a seqncia "987654321876543217654321654321543214321321211", mas sem imprimir nenhuma constante use apenas variveis. Em outra linha imprima as letras maisculas de A at Z (ABCD...Z). Exerccio 3.25 Escreva um programa que conte de 100 a 999 (inclusive) e exiba, um por linha, o produto dois trs dgitos dos nmeros. Por exemplo, inicialmente o programa ir exibir:

45

0 (1*0*0) 0 (1*0*1) 0 (1*0*2) (...) 0 (1*1*0) 1 (1*1*1) 2 (1*1*2) at 9*9*9=729 Exerccio 3.26 Faa um programa que leia vrios nmeros e informar quantos esto no intervalo de 50 e 100. Quando o usurio digitar 0 (zero) o programa termina aps mostrar a quantidade de nmeros do intervalo. Exerccio 3.27 Faa um programa que leia vrios nmeros e informar quantos esto no intervalo de 50 e 100. Quando o usurio digitar 0 (zero) o programa termina aps mostrar a quantidade de nmeros do intervalo. Exerccio 3.28 Faa um programa que calcule n! (n factorial). Use a preciso dupla para o clculo de n!, porque, embora seja um valor inteiro, o seu clculo rapidamente conduz a valores elevados. O programa deve ainda no aceitar valores de n que sejam negativos ou que originem um clculo de n! superior ao limite da preciso dupla (n > 170). Exerccio 3.29 Faa um programa que leia dois valores inteiros e que visualize: A mensagem "Valores iguais" se os valores lidos forem iguais; A lista dos inteiros compreendidos entre os valores introduzidos (inclusive) por ordem crescente. Coloque 10 valores em cada linha e faa uma parada programada quando o visor estiver cheio. Considere que uma linha pode conter at 80 caracteres e que o visor pode conter at 25 linhas. Exerccio 3.30 Jos tem 1,50m e cresce 2 centmetros por ano, enquanto Juca tem 1,10m e cresce 3 centmetros por ano. Faa um programa que calcule e informe quantos anos seo necessrios para que Juca seja maior que Jos. Exerccio 3.31 Faa um programa que calcule a fatura de energia eltrica para cada consumidor. Leia o nmero do medidor, a quantidade de kWh consumidor durante o ms e o tipo de consumidor. 1 residencial, preo R$ 0,34 por kWh, 2 comercial, preo R$ 0,54 por kWh e 3 industrial, preo R$ 0,84 por kWh. Os dados devem ser lidos at que seja fornecido um cdigo 0 (zero) para um consumidor. Mostrar o total da fatura do consumidor.

46

4 Funes
Em C, diferentemente de outras linguagens como Pascal, todas as aes ocorrem dentro de funes. Na linguagem C no h conceito de um programa principal, o que existe uma funo chamada main que sempre a primeira a ser executada. A forma geral de uma funo em C a seguinte: tipo nome (tipo nome1, tipo nome2, ..., tipo nomeN){ declarao das variveis corpo da funo } O tipo na definio da funo especifica o tipo do resultado que ser devolvido ao final da execuo da funo. Caso nenhum tipo seja especificado o compilador assume que um tipo inteiro retornado. O tipo void (vazio) pode ser usado para declarar funes que no retornam valor algum. H duas maneiras bsicas de terminar a execuo de uma funo. Normalmente usa-se o comando return para retornar o resultado da funo. Portanto, quando o comando return (expressao) ; for executado, o valor da expresso devolvido para a funo que chamou. Quando no h valor para retornar o comando return no precisa ser usado e a funo termina quando a chave que indica o trmino do corpo da funo atingida. O nome da funo qualquer identificador vlido. A lista de parmetros uma lista, separada por vrgulas, de variveis com seus tipos associados. possvel que existam funes que no tenham lista de parmetros, mas ainda assim necessrio que os parnteses sejam usados. Os parmetros so valores que a funo recebe para realizar as tarefas para as quais foi programada. Por exemplo, uma funo que calcule a raiz quadrada de um nmero do tipo float, deve declarar como parmetro uma varivel deste tipo para receber o valor. importante notar que diferentemente de declaraes de variveis onde podemos associar vrios nomes de variveis a uma declarao como em: int a, dia, mes, i; na lista de parmetros necessrio associar um tipo a cada varivel como no exemplo 47

abaixo: float media (float n1, float n2, float n3) Suponha que uma determinada funo, A, deseje usar uma outra funo, B. A funo A deve colocar no local desejado o nome da funo B e a lista de valores que deseja passar. Por exemplo, uma funo que deseje usar a funo media, cujo prottipo foi definido acima, para calcular a mdia de trs valores: nota1, nota2 e nota3, deve escrever no local onde quer que a mdia seja calculada o seguinte comando: resultado = media(nota1, nota2, nota3); onde resultado a varivel que ir receber a mdia calculada. importante notar que os tipos e o nmero de parmetros que aparecem na declarao da funo e na sua chamada devem estar na mesma ordem e ter tipos equivalentes. Se os tipos so incompatveis, o compilador no gera um erro, mas podem ser gerados avisos na compilao e resultados estranhos. 4.1 Prottipos de funes O padro ANSI estendeu a declarao da funo para permitir que o compilador faa uma verificao mais rgida da compatibilidade entre os tipos que a funo espera receber e queles que so fornecidos. Prottipos de funes ajudam a detectar erros antes que eles ocorram, impedindo que funes sejam chamadas com argumentos inconsistentes. A forma geral de definio de um prottipo a seguinte: tipo nome (tipo nome1, tipo nome2, ..., tipo nomeN); Exemplo 4.1 Programa para calcular a soma de dois nmeros utilizando a declarao de uma funo e seu prottipo.

#include <stdio.h> #include <conio.h> /* Prototipo da funcao */ int soma (int a, int b); /* Funcao Principal */ main(){ int x = 3, y = 4; printf("\nSoma = %d", soma(x,y)); getch(); return (0); } /* Definicao da funcao */ 48

int soma(int a, int b){ return (a + b); } 4.2 Escopo de variveis Variveis podem ser usadas dentro de uma funo particular, e somente dentro desta funo, ou pode ocorrer que uma ou mais variveis precisem ser acessveis a diversas funes diferentes. Por esta razo temos que definir onde as variveis de um programa podem ser definidas e a partir deste local inferir onde elas estaro disponveis. As variveis podem ser declaradas basicamente em trs lugares: dentro das funes, fora de todas as funes e na lista de parmetros das funes. As variveis dentro das funes so chamadas de variveis locais, as que aparecem fora de todas as funes so conhecidas como variveis globais e aquelas que aparecem na lista de parmetros so os parmetros formais. importante notar que em C todas as funes esto no mesmo nvel, por isto no possvel definir uma funo dentro de outra funo. 4.2.1 Variveis locais As variveis locais so aquelas declaradas dentro de uma funo. Elas passam a existir quando do incio da execuo do bloco de comandos ou funo onde foram definidas e so destrudas ao final da execuo do bloco. Uma varivel local s pode ser referenciada, ou seja, usada, dentro das funes onde foram declaradas. Outro ponto muito importante que como as variveis locais deixam de existir ao final da execuo da funo, elas so invisveis para outras funes do mesmo programa. O cdigo que define uma funo e os seus dados so particulares a funo. O programa a seguir (ex. 4.2) exibe o uso de algumas variveis locais. Na funo main tem-se cinco variveis locais: numero, potencia, continua, para e linha. A funo Eleva possui somente a varivel res, enquanto que ParaMaiusculas no possui varivel local. A nica varivel nesta funo c que um parmetro. Exemplo 4.2 Programa para elevar um nmero qualquer a uma potncia inteira usando funo. O programa deve terminar ao desejo do usurio.

#include <stdio.h> #include <conio.h> #include <stdlib.h> #define SIM 1 #define NAO 0 int Eleva (int, int); char ParaMaiuscula (char c); main(){ 49

int num, pot; char continuar; int parar; char linha[80]; do{ puts("Entre com um numero"); gets(linha); num = atoi(linha); puts("Entre com a potencia"); gets(linha); pot = atoi(linha); printf("\n%d Elevado a %d ", num, pot); printf("eh = %d\n", Eleva(num, pot)); puts("Continuar? [S]im ou [N]ao? "); continuar = getchar(); getchar(); continuar = ParaMaiuscula(continuar); parar = continuar == 'S'? NAO : SIM; }while (!parar); return(0); } int Eleva(int a, int b){ int res = 1; for ( ; b > 0; b--) res *= a; return (res); } char ParaMaiuscula (char c){ if ('a' <= c && c <= 'z') c = c - 'a' + 'A'; return (c); } Alguns autores usam o termo variveis automticas para se referir as variveis locais. Em C existe a palavra chave auto que pode ser usada para declarar variveis locais. No entanto, como todas as variveis locais so por definio automticas raramente se usa esta palavra chave. Observa-se que um bloco de comandos ou escopo se inicia em um { e termina em um }. O bloco de comandos mais usado para definir uma varivel a funo. Todas as variveis que sero usadas dentro de um bloco de comandos precisam ser declaradas antes do primeiro comando do bloco. Declaraes de variveis, incluindo sua inicializao, podem vir logo aps o abre chaves que inicia um bloco de comandos, no somente o que comea uma funo. O exemplo (ex. 4.3) a seguir ilustra este tipo de declarao: Exemplo 4.3 - Declarando variveis usando o escopo de comandos C, neste caso um comando for.

50

#include <stdio.h> #include <conio.h> main(){ int i; for (i = 0; i < 10; i++){ int t; scanf("%d", &t); printf("%d\n", i*t); } getch(); return(0); } Existem algumas vantagens em se declarar variveis dentro de blocos ou escopo. Como as variveis somente passam a existir quando o bloco passa a ser executado, o programa ocupa menos espao de memria. Isto porque se a execuo do bloco for condicional a varivel pode nem ser alocada. Outra vantagem que como a varivel somente existe dentro do bloco pode-se controlar melhor o uso da varivel, evitando erros de uso indevido da varivel. 4.2.2 Variveis estticas Outra classe de variveis locais so as do tipo estticas. Uma varivel static pode ser acessada da funo na qual ela foi declarada, como uma varivel local normal. A diferena que as variveis estticas no so destrudas ao trmino da funo, ao invs disso seu valor preservado e torna-se disponvel novamente quando da prxima chamada da funo. Variveis estticas so declaradas como as variveis locais, mas a declarao precedida pela palavra static. static int contador; Variveis estticas podem ser inicializadas normalmente. A inicializao executada somente uma vez, quando o programa iniciado. 4.2.3 Variveis globais As variveis globais so definidas fora de qualquer funo e so portanto disponveis para qualquer funo. Este tipo de varivel pode servir como um canal de comunicao entre funes, uma maneira de transferir valores entre elas. Por exemplo, se duas funes tem de partilhar dados mais uma no chama a outra, uma varivel global tem de ser usada. 4.2.4 Parmetros formais

51

As variveis que aparecem na lista de parmetros da funo so chamadas de parmetros formais da funo. Eles so criados no incio da execuo da funo e destrudos ao seu final. Parmetros so valores que as funes recebem da funo que a chamou. Portanto, os parmetros permitem que uma funo passe valores para outra. Normalmente os parmetros so inicializados durante a chamada da funo, pois para isto que foram criadas. No entanto, as variveis que atuam como parmetros so iguais a todas as outras e podem ser modificadas, operadas, etc, sem nenhuma restrio. 4.2.5 Passagem de parmetros por valor Parmetros podem ser passados para funes de duas maneiras: passagem por valor ou passagem por referncia. Na passagem por valor uma cpia do valor do argumento passada para a funo. Neste caso a funo que recebe este valor ao fazer modificaes no parmetro no estar alterando o valor original que somente existe na funo que chamou. 4.2.6 Passagem de parmetros por referncia Na passagem por referncia o que passado para a funo o endereo do parmetro e portanto a funo que recebe pode por meio do endereo modificar o valor do argumento na funo que chamou. Para a passagem de parmetros por referncia necessrio o uso de ponteiros. Este assunto ser discutido nos prximos captulos e portanto neste captulo sero apresentadas somente funes com passagem por valor. 4.2.7 O comando de returno O comando return usado para retornar o valor calculado para a funo que a chamou. Qualquer expresso pode aparecer no comando, que tem a seguinte forma geral: return (expressao) ; A funo que chamou livre para ignorar o valor retornado. Alm disso a funo pode no conter o comando e portanto nenhum valor retornado e neste caso a funo termina quando o ltimo comando da funo executado. Quando o comando return no existe o valor de retorno considerado indefinido. As funes que no retornam valores devem ser declaradas como do tipo void. importante observar que funes que so declaradas com um tipo vlido podem ser includas em qualquer expresso vlidas em C. 4.2.8 Funes sem retorno As funes void so funes que no retornam qualquer valor e comportam-se, 52

por isso, de forma equivalente aos procedimentos do Pascal. Estas funes so definidas tendo como tipo de retorno a palavra void. A terminao pode fazer-se simplesmente pelo esgotar das instrues contidas na funo ou por meio de uma instruo de return sem a especificao de qualquer valor adicional. Geralmente, este ltimo tipo de terminao usado no meio das instrues da funo, como por exemplo, dentro de um comando if. A palavra void tambm dever ser usada no lugar dos parmetros se a funo no tiver nenhum (ex. 4.4). Exemplo 4.4 - Programa para calcular o quadrado dos nmeros de 1 10, utilizando uma funo sem retorno. #include <stdio.h> #include <conio.h> void quadrados(void); void main(void){ quadrados(); getch(); } void quadrados(void){ int k; for (k = 1;k <= 10;k++) printf("%d\n", k * k); } Exemplo 4.5 O programa que mostra a tabuada de um nmero fornecido pelo usurio.

#include <stdio.h> #include <conio.h> void tabuada (int n); main(){ int num; printf("Tabuada de -> "); scanf ("%d",&num); tabuada (num); getch(); return(0); } 53

void tabuada (int n){ int i; printf("Tabuada de %d\n", n); for (i = 1;i <= 10; i++){ printf("%d x %2d = %2d\n", n, i, n * i);} } Na chamada de funes sem argumentos sempre obrigatrio utilizar parnteses, sem nada l dentro, como mostra o exemplo anterior (ex. 4.4). 4.3 Recurso Funes em C podem ser usadas recursivamente, isto , uma funo pode chamar-se a si mesma. como procurar no dicionrio a definio da palavra recurso e encontrar o seguinte texto: recurso: s.f. Veja a definio em recurso. Um exemplo simples de funo que pode ser usada com chamadas recursivas o fatorial de um nmero inteiro. O fatorial de um nmero pode ser definido como o produto deste nmero pelo fatorial de seu predecessor, ou seja, n! = n * (n-1)! A funo fatorial implementada sem recurso est ilustrada em um exemplo do captulo 3 (ex. 3.15). A alternativa uma funo recursiva em que cada chamada da funo que calcula o fatorial chama a prpria funo fatorial. O exemplo (ex. 4.6) ilustrado abaixo mostra como a funo pode ser escrita recursivamente. Exemplo 4.6 Programa para calcular o fatorial de um nmero usando uma funo recursiva.

#include <stdio.h> #include <conio.h> unsigned int fat(unsigned int n); main(){ unsigned int num; printf("\nEntre com um numero positivo."); scanf("%u", &num); printf("Fatorial de %u vale %u.", num, fat(num)); getch(); 54

return(0); } unsigned int fat(unsigned int n){ unsigned int fato; if (n == 1) return(1); else fato = n * fat(n-1); return(fato); } Quando a funo fat (fatorial) recursiva chamada, primeiramente verificado se o nmero recebido como parmetro vale 1. Neste caso a funo retorna o valor 1, caso contrrio ela devolve o valor da expresso n * fat(n-1), ou seja o produto do nmero pelo valor do fatorial do nmero predecessor. Portanto, quando se inicia o processo a funo chamada com o valor do nmero e a funo sendo chamada sempre com este nmero sendo decrementado at que ele seja um. Quando o processo se reverte e as chamadas comeam a serem respondidas. Um ponto importante que toda funo recursiva deve prever cuidadosamente como o processo de recurso deve ser interrompido. No caso da funo fat o processo interrompido quando o valor do nmero vale 1. Quando uma funo chama a si mesmo recursivamente ela recebe um conjunto novo de variveis na pilha que usada para transferncia de valores entre funes. importante notar que recurso no trs obrigatoriamente economia de memria porque os valores sendo processados tm de ser mantidos na pilha. Nem ser mais rpido, e s vezes pode ser at mais lento porque temos o custo de chamada s funes. As principais vantagens da recurso so cdigos mais compactos e provavelmente mais fceis de serem lidos. 4.4 A funo printf() A funo printf parte de um conjunto de funes pr-definidas armazenadas em uma biblioteca padro (stdio.h) de rotinas da linguagem C. Ela permite apresentar na tela os valores de qualquer tipo de dado. Para tanto, printf utiliza o mecanismo de formatao, que permite traduzir a representao interna de variveis para a representao ASCII que pode ser apresentada na tela. Sintaxe: printf("string de controle", lista de argumentos); O primeiro argumento de printf uma string de controle, uma seqncia de caracteres entre aspas. Esta string, que sempre deve estar presente, pode especificar atravs de caracteres especiais (as seqncias de converso) quantos outros argumentos estaro presentes nesta invocao da funo. Estes outros argumentos sero variveis cujos valores sero formatados e apresentados na tela. Por exemplo, se o valor de uma 55

varivel inteira x 10, ento a execuo da funo, printf("Valor de x = %d", x); imprime na tela a frase Valor de x = 10. Se y uma varivel do tipo caractere com valor G, ento a execuo de printf("x = %d e y = %c\n", x, y); imprime na tela a frase x = 10 e y = G seguida pelo caractere de nova linha (\n), ou seja, a prxima sada para a tela aconteceria na linha seguinte. Observe que a seqncia de converso pode ocorrer dentro de qualquer posio dentro da string de controle. A funo printf no tem um nmero fixo de argumentos. Em sua forma mais simples, pelo menos um argumento deve estar presente a string de controle. Uma string de controle sem nenhuma seqncia de converso ser literalmente impressa na tela. Com variveis adicionais, a nica forma de saber qual o nmero de variveis que ser apresentado por inspeo da string de controle. Desta forma, cuidados devem ser tomados para que o nmero de variveis aps a string de controle esteja de acordo com o nmero de seqncias de converso presente na string de controle. Alm de ter o nmero correto de argumentos e seqncias de converso, o tipo de cada varivel deve estar de acordo com a seqncia de converso especificada na string de controle. A seqncia de converso pode ser reconhecida dentro da string de controle por iniciar sempre com o carter %. Exemplo 4.7 - Programa para ler um nmero inteiro entre 0 e 100 e verificar se igual ao nmero previamente estabelecido. #include <stdio.h> #include <conio.h> main(){ int num, vezes; char continua =s; while (continua == s){ printf("\nEntre com um numero entre 0 e 100: "); scanf("%d", &num); vezes = 1; while (num != 50){ printf("\n%d Incorreto! ", num); printf("\nTente novamente!"); scanf("%d", &num); vezes++; } printf("\nAcertou em %d Tentativa(s)", vezes); printf("\nJoga Novamente? s/n"); continua = getche(); } getch(); 56

return(0); } As principais seqncias de converso para variveis caracteres e inteiras so: %c %d %u %o %x imprime o contedo da varivel com representao ASCII; imprime o contedo da varivel com representao decimal com sinal; imprime o contedo da varivel com representao decimal sem sinal; imprime o contedo da varivel com representao octal sem sinal; imprime o contedo da varivel com representao hexadecimal sem sinal.

Uma largura de campo pode ser opcionalmente especificada logo aps o caractere %, como em %12d para especificar que o nmero decimal ter reservado um espao de doze caracteres para sua representao. Se a largura de campo for negativa, ento o nmero ser apresentado alinhado esquerda ao invs do comportamento padro de alinhamento direita. Para a converso de variveis do tipo long, o caractere l tambm deve ser especificado, como em %ld. Para converter variveis em ponto flutuante, as seqncias so: %f %e %g imprime o contedo da varivel com representao com ponto decimal; imprime o contedo da varivel com representao em notao cientfica (exponencial); formato geral, escolhe a representao mais curta entre %f e %e.

Como para a representao inteira, uma largura de campo pode ser especificada para nmeros reais. Por exemplo, %12.3f especifica que a varivel ser apresentada em um campo de doze caracteres com uma preciso de trs dgitos aps o ponto decimal. Finalmente, se a varivel a ser apresentada uma seqncia de caracteres (uma string), ento o formato de converso %s pode ser utilizado. Para apresentar o caractere %, a seqncia %% utilizada. 4.5 A funo scanf() A funo scanf() definida em stdio.h como segue: scanf("expresso de controle", lista de argumentos); Esta l caracteres da entrada padro e coloca os valores lidos e convertidos nas variveis cujos endereos so passados na lista de argumentos seguintes indicao do formato; retorna o nmero de caracteres lidos e convertidos. A indicao do formato muito semelhante especificada para printf(). A nica exceo diz respeito aos especificadores f, e ou g, que aqui se referem exclusivamente a valores do tipo float (os valores lidos e convertidos devero ser passados a apontadores para variveis do tipo float). Para especificar valores do tipo double devero ser usados os especificadores lf, le ou lg. A lista de argumentos, que iro receber os valores lidos, dever conter apenas 57

apontadores ou endereos de variveis. Por exemplo, para ler um valor inteiro do teclado e coloc-lo na varivel de tipo int i. scanf("%d", &i); %c l uma varivel com representao ASCII; %d l uma varivel com representao decimal com sinal; %u l uma varivel com representao decimal sem sinal; %o l uma varivel com representao octal sem sinal; %x l uma varivel com representao hexadecimal sem sinal; %f l uma varivel com representao com ponto decimal; %e l uma varivel com representao em notao cientfica (exponencial); %s l uma varivel string (cadeia de caracteres); %lf l uma varivel com representao com ponto decimal de preciso dupla (double); Exemplo 4.8 Programa para ler um caractere e exibir seu correspondente em decimal, octal e hexadecimal.

#include <stdio.h> #include <conio.h> main(){ char a; printf("\nEntre com um caractere:"); scanf("%c", &a); printf("\n%c = %d em decimal,", a, a); printf("\n%o em octal, %x em hexadecimal", a, a); getch(); return(0); } No caso de arrays (strings, por exemplo) o prprio nome pode ser diretamente usado na lista de argumentos, uma vez que representa o endereo da 1 posio do array. Como mostra o exemplo na seqncia: char str[80]; ... scanf("%s", str); outros exemplos, int num; scanf("%d", &num); char letra; scanf("%c", &letra);

58

4.5.1 Operador de endereo (&) Um endereo de memria o local no qual o computador armazena/retorna o dado que est sendo atribudo ou lido por meio de um identificador, ou seja, uma varivel. Toda varivel ocupa uma rea de memria e seu endereo o do primeiro byte por ela ocupado. Ex.: int float char 2 bytes 4 bytes 1 byte

Usa-se & precedendo uma varivel para indicar o endereo da mesma na memria. Assim, a funo scanf() ter a localizao exata para armazenar os dados obtidos. Veja exemplo a seguir (ex. 4.9). Exemplo 4.9 Programa para ler um nmero inteiro e exibir seu endereo.

#include <stdio.h> #include <conio.h> main(){ int num; printf("\nEntre com um numero:"); scanf("%d", &num); printf("Valor = %d, endereco = %p", num, &num); getch(); return(0); } 4.6 Funes getche() e getch() A funo scanf() exige que a tecla <enter> seja pressionada aps a entrada dos dados. Outra biblioteca (conio.h) do C oferece funes que lem dados sem esperar a tecla <enter>. Estas funes fazem a leitura dos cdigos de teclado. Estes cdigos podem representar teclas de caracteres (A, y, *, 6, etc.), teclas de comandos (<enter>, <delete>, <Page Up>, <F10>, etc.) ou combinao de teclas (<Alt> + <F>, <Shift> + <F12>, <Ctrl> + <Page Down>, etc.). getche() e getch() l um caractere do teclado sem eco-lo na tela; l um caractere do teclado ecoando-o na tela;

Ao ser executada, a funo getch() - get character, aguarda que uma tecla (ou combinao de teclas) seja pressionada, recebe do teclado o cdigo correspondente e 59

retorna este valor. A funo getche() - get character and echoe, tambm escreve na tela, quando possvel, o caractere correspondente. cdigo ASCII Ao ser pressionada uma tecla correspondente a um caractere ASCII, o teclado envia um cdigo ao buffer de entrada do computador e este cdigo lido. Por exemplo, se a tecla A for pressionada o cdigo 65 (ex. 4.10) ser armazenado no buffer e lido pela funo. Cdigo especial Ao serem pressionadas certas teclas (ou combinao de teclas) que no correspondem a um caractere ASCII, o teclado envia ao buffer do computador dois cdigos, sendo o primeiro sempre 0. Por exemplo, se a tecla <F1> for pressionada os valores 0 e 59 (ex. 4.10) sero armazenados e a funo deve ser chamada duas vezes para ler os dois cdigos. Exemplo 4.10 - Programa para a leitura de teclado. Este programa usa a funo getch() para reconhecer teclas e combinao de teclas. #include <stdio.h> #include <conio.h> main(){ int c,d; printf("\nPressione uma tecla ou combinacaos:"); printf("\nPressione [esc] para terminar!"); do{ c = getch(); if (c == 0){ d = getch(); printf("\n %3d %3d codigo extendido", c, d); } else{ printf("\n %3d codigo normal", c); } }while (c != 27); getch(); return(0); } Exemplo 4.11 - Programa para a leitura de teclado usando a funo getche(). #include <stdio.h> #include <conio.h> 60

main(){ int n = 0; char c; printf("\nDigite uma frase: "); do{ c = getche(); n++; }while (c != 13); printf("\nVoce digitou %d caracteres.", n - 1); getch(); return(0); } 4.7 Funes getchar() e putchar() A rotina bsica de entrada de dados l um caractere do teclado, retornando seu valor ASCII. Esta rotina a funo getchar(). #include <stdio.h> int getchar(); A descrio acima deve ser lida da seguinte forma: o arquivo de cabealho <stdio.h> tem que ser includo no arquivo fonte que for usar esta rotina getchar(), e esta rotina no tem nenhum argumento e retorna um valor inteiro. O seguinte exemplo (ex. 4.12) ilustra o uso desta funo. Exemplo 4.12 - Programa para a leitura de teclado usando a funo getchar(). #include <stdio.h> #include <conio.h> main(){ int ch; ch = getchar(); printf("ASCII de %c = %d (hexa %x)\n", ch, ch, ch); getch(); return(0); } Este programa (ex. 4.12), quando executado, ir aguardar que o usurio entre 61

algum caractere via teclado. A sada ser uma indicao de qual caractere foi obtido ao longo da digitao com seu valor em representao decimal e hexadecimal. A rotina correspondente a getchar() para a apresentao de um caractere na tela a funo putchar(). #include <stdio.h> int putchar(char); Por exemplo, o programa anterior (ex. 4.12) poderia ser estendido de forma a que um prompt (tal como >) indicasse ao usurio que uma entrada de dados aguardada, como no programa a seguir (ex. 4.13). Exemplo 4.13 - Programa para a leitura de teclado usando a funo getchar() e a funo putchar(). #include <stdio.h> #include <conio.h> main(){ int ch; putchar('>'); ch = getchar(); printf("ASCII de %c = %d (hexa %x)\n", ch, ch, ch); getch(); return(0); } 4.6 Exerccios propostos Exerccio 4.1 Faa um programa que leia um nmero inteiro longo e que determine o seu mdulo sem usar nenhuma funo disponvel em C para essa finalidade. Crie sua prpria funo. Faa um programa que determine se um ano introduzido pelo usurio ou no bissexto. Desenvolva uma funo que receba como parmetro um inteiro representando um ano qualquer e retorne 1 quando o ano for bisexto ou 0 caso contrrio. Um ano bissexto se for mltiplo de 4 sem ser de 100 ou se for mltiplo de 400. Faa um programa que calcule a soma de dez nmeros inteiros a partir de um nmero dado pelo usurio. Utilize uma funo para realizar o somatrio e retorn-lo. Faa um programa que calcule a soma de nmeros inteiros dados pelo usurio, o nmero 0 (zero) encerra a leitura de valores. Use uma funo recurssiva. 62

Exerccio 4.2

Exerccio 4.3

Exerccio 4.4

Exerccio 4.5

Fazer uma funo que calcula a ensima potncia de uma varivel real ou fracionria x: f(x,n) = xn

Exerccio 4.6 Exerccio 4.7

Fazer uma funo que calcula o fatorial de um nmero. Implementar uma verso recursiva e uma verso com lao. Dado que podemos calcular ex por: ex = 1 + x + x2/2! + x3/3! + ...

Fazer um trecho de programa em linguagem C que leia um valor para x e calcula o valor de ex. O valor deve ser calculado enquanto o termo calculado for maior que 10E-6. Exerccio 4.8 Exerccio: fazer um programa em "C" que solicita o total gasto pelo cliente de uma loja, imprime as opes de pagamento, solicita a opo desejada e imprime o valor total das prestaes (se houverem). 1) Opo: a vista com 10% de desconto; 2) Opo: em duas vezes (preo da etiqueta); 3) Opo: de 3 at 10 vezes com 3% de juros ao ms (somente para compras acima de R$ 100,00). Obs.: Fazer uma funo que imprima as opes, solicite a opo desejada e retorne a opo escolhida. No programa principal, testar a opo escolhida e ativar a funo correspondente (uma funo para cada opo). Exerccio 4.9 Faa um programa que calcule a soma de nmeros inteiros dados pelo usurio, o nmero 0 (zero) encerra a leitura de valores. Use uma funo recurssiva.

Exerccio 4.10 Faa um programa que calcule o horrio de chegada de um avio, sendo dado o horrio de partida (horas e minutos) e a durao do vo (horas e minutos). O programa deve ainda indicar se o avio chega no prprio dia ou no dia seguinte. Se o usurio introduzir o nmero de horas de vo igual ou superior a 24h, o programa no deve efetuar os clculos, mas deve mostrar uma mensagem apropriada. Exerccio 4.11 Construa um programa com uma funo para calcular a distncia entre dois pontos do plano cartesiano. Cada ponto um par ordenado (x,y). Exerccio 4.12 Faa um programa que dado um natural n, utilize uma funo para determinar o nmero harmnico Hn definido por:

63

Exerccio 4.13 Uma seqncia de Fibonacci uma seqncia na qual cada termo a soma dos dois termos que precedem eles. A sucesso de Fibonacci, que tem 1 como seu primeiro termo : 1, 1, 2, 3, 5, 8, 13, 21, 34, 55,... Faa um programa que com uma funo mostre os n primeiros termos da referida sucesso. O valor de n deve ser passado como parmetro. Exerccio 4.14 Calcular uma aproximao para sen x por meio da seguinte srie infinita. Utilize funes.

Exerccio 4.15 Um programa para gerenciar os saques de um caixa eletrnico deve possuir algum mecanismo para decidir o nmero de notas de cada valor que deve ser disponibilizado para o cliente que realizou o saque. Um possvel critrio seria o da "distribuio tima" no sentido de que as notas de menor valor fossem distribudas em nmero mnimo possvel. Por exemplo, se a quantia solicitada fosse R$ 87,00, o programa deveria indicar uma nota de R$ 50,00, trs notas de R$ 10,00, uma nota de R$ 5,00 e duas notas de R$ 1,00. Escreva um programa com uma funo que receba o valor da quantia solicitada e mostre a distribuio das notas de acordo com o critrio da distribuio tima. No exibir quantidades zero de notas! Exerccio 4.16 Um intervalo de tempo pode ser dado em dias, horas, minutos, segundos ou seqncias "decrescentes" destas unidades (em dias e horas; em horas e minutos; em horas, minutos e segundos), de acordo com o interesse de quem o est manipulando. Escreva um programa com uma funo que converta e exiba um intervalo de tempo dado em segundos, em horas, minutos e segundos. Por exemplo, se o tempo dado for 3 850 segundos, o programa deve fornecer 1 h 4 min 10 s.

64

5 Arranjos
Em C, arranjos so definidos e acessados por meio do operador de indexao [], como no exemplo a seguir (ex. 5.1). Exemplo 5.1 - Declarando variveis do tipo vetor de cinco posies de inteiros, inicializando-os com zeros. #include <stdio.h> #include <conio.h> main(){ int elementos[5]; int i; for (i = 0; i < 5; i++) elementos[i] = 0; ... getch(); return(0); } Neste exemplo (ex. 5.1), um arranjo de nome elementos definido na funo main(). Este arranjo tem espao para armazenar cinco valores inteiros, que sero referenciados no programa como elementos[0], elementos[1], elementos[2], elementos[3] e elementos[4]. importante lembrar que o primeiro elemento de um arranjo em C sempre o elemento de ndice 0 (elementos[0]). Conseqentemente, para um arranjo com N elementos o ltimo elemento o de ndice N-1, ou seja, elementos[4] no exemplo anterior (ex. 5.1). Assim como para variveis de tipos bsicos, os elementos de um arranjo podem ser tambm inicializados durante a declarao da varivel. Neste caso, os valores de cada um dos elementos so delimitados por chaves. Para o exemplo acima (ex. 5.1), tem-se: ... int elementos[5] = {0,0,0,0,0}; int i; ...

65

O ndice de um arranjo pode ser qualquer expresso inteira, incluindo-se variveis e constantes inteiras. C no verifica se o valor do ndice est dentro da faixa declarada - responsabilidade do programador garantir que o acesso esteja dentro dos limites de um arranjo. Arranjos podem ser multidimensionais. Por exemplo, um arranjo bidimensional pode ser declarado, inicializado e acessado como no exemplo seguinte (ex. 5.2). Exemplo 5.2 - Declarando variveis do tipo matriz 2x3 posies de inteiros, inicializando-os com zeros. #include <stdio.h> #include <conio.h> main(){ int elementos[2][3] = { {0,0,0}, {0,0,0}}; int i, j; for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) elementos[i][j] = i * 3 + j; getch(); return(0); } Em C, um arranjo bidimensional na verdade um arranjo unidimensional onde cada elemento um arranjo. Por este motivo, dois operadores de indexao so utilizados ao invs da forma [i,j]. Elementos so armazenados por linha. Em geral, arranjos com muitas dimenses no so utilizados em C visto que ocupam muito espao e o acesso a seus elementos no ocorre de forma eficiente. 5.1 Vetores Estrutura formada por um conjunto unidimensional de dados de mesmo tipo (homogneo) e possuindo nmero fixo de elementos (Esttico). Na declarao dos vetores devemos informar o seu nome, seu tipo (int, float, char, ...), e seu tamanho (quantidade de elementos). Cada elemento do vetor identificado por um ndice (unidimensional), o qual indica a sua posio no vetor. Exemplo 5.3 - Criar um programa que armazene nmeros inteiros em dois vetores com trs elementos cada. Gerar e imprimir o vetor soma. #include <stdio.h> #include <conio.h> main(){ int vetor1[3], vetor2[3], vetorSoma[3];

66

/* Entrada de elementos do vetor1 */ printf("Entre com o 1o elemento do vetor 1: "); scanf("%d",&vetor1[0]); printf("Entre com o 2o elemento do vetor 1: "); scanf("%d",&vetor1[1]); printf("Entre com o 3o elemento do vetor 1: "); scanf("%d",&vetor1[2]); /* Entrada de elementos do vetor2 */ printf("Entre com o 1o elemento do vetor 2: "); scanf("%d",&vetor2[0]); printf("Entre com o 2o elemento do vetor 2: "); scanf("%d",&vetor2[1]); printf("Entre com o 3o elemento do vetor 2: "); scanf("%d",&vetor2[2]); /* Calculo do vetor soma */ vetorSoma[0] = vetor1[0] + vetor2[0]; vetorSoma[1] = vetor1[1] + vetor2[1]; vetorSoma[2] = vetor1[2] + vetor2[2]; /* Exibindo o vetor soma */ printf("\nVetor Soma [1] = %d", vetorSoma[0]); printf("\nVetor Soma [2] = %d", vetorSoma[1]); printf("\nVetor Soma [3] = %d", vetorSoma[2]); getch(); return(0); } Exemplo 5.4 - Criar um programa que armazene nmeros inteiros em dois vetores com dez elementos cada. Gerar e imprimir o vetor soma. #include <stdio.h> #include <conio.h> #define MAX 10 main(){ int vet1[MAX], vet2[MAX]; int vetSoma[MAX]; int i; /* Entrada de elementos do vet1 */ for (i = 0; i < MAX; i++){ printf("Entre com o %do elem do vetor 1: ", i + 1); scanf("%d",&vet1[i]); } 67

/* Entrada de elementos do vetor2 */ for (i = 0; i < MAX; i++){ printf("Entre com o %do elem do vetor 2: ", i + 1); scanf("%d",&vet2[i]); } /* Calcula e Exibe o vetor soma */ for (i = 0; i < MAX; i++){ vetSoma[i] = vet1[i] + vet2[i]; printf("\nVetor Soma [%d] = %d", i+1, vetSoma[i]); } getch(); return(0); } 5.1.1 Exerccios Propostos Exerccio 5.1 Exerccio 5.2 Faa um programa que dada uma seqncia de n nmeros inteiros, imprimi-la na ordem inversa da leitura. Dada uma seqncia (10 valores) de nmeros inteiros no-nulos, armazenar em outro vetor seus quadrados e mostrar ambos na ordem primeiro valor e seu quadrado (armazenado no segundo vetor). Faa um programa que dado um nmero inteiro positivo n, imprimir os n primeiros naturais mpares. Exemplo: Para n = 4 a sada dever ser 1,3,5,7. Use uma funo para determinar se o nmero mpar. Armazene-os em um vetor (Max 500 posies), exibindo-os logo a seguir. Faa um programa que dado um nmero inteiro positivo n, imprimir os n primeiros naturais pares. Exemplo: Para n = 4 a sada dever ser 0,2,4,6. Use uma funo para determinar se o nmero par e exibi-los. Faa um programa que leia N (mximo 50) e uma lista de N nmeros e mostre a soma de todos os nmeros da lista. Escreva um programa que leia um conjunto de 100 nmeros inteiros positivos e determine o maior deles. Escreva um programa que leia um nmero inteiro N (mximo 500) e uma lista de N nmeros inteiros positivos e determine o maior nmero da lista. Escreva um programa que leia um conjunto de nmeros inteiros positivos e determine o maior deles. A leitura do valor 0 (zero) ou no 68

Exerccio 5.3

Exerccio 5.4

Exerccio 5.5 Exerccio 5.6 Exerccio 5.7

Exerccio 5.8

mximo 100 nmeros lidos indicam o fim dos dados (flag). Exerccio 5.9 Faa um programa que leia uma lista de nmeros inteiros positivos terminada pelo nmero 0 (zero) ou no mximo 1000 nmeros lidos. Ao final, o programa deve mostrar a mdia aritmtica de todos os nmeros lidos (excluindo o zero).

Exerccio 5.10 Faa um programa que leia um vetor de 10 inteiros e que calcule o seguinte: A mdia dos elementos do vector; O nmero de elementos pares e o nmero de elementos mpares; Exerccio 5.11 Faa um programa que crie um vetor de inteiros de 10 posies, leia os valores deste vetor e exiba o vetor na tela de trs para frente. Exerccio 5.12 Um caador submarino registou o tempo de cada um dos n mergulhos que realizou num dia de caa. O registo do tempo realizado em segundos. Faa um programa que leia os referidos tempos para um vetor, que determine o tempo mximo atingido num mergulho e em que mergulho(s) que esse tempo foi atingido. Considere que os mergulhos so identificados perante o usurio por um nmero de 1 a n. utilize uma funo para determinar o tempo mximo. Exerccio 5.13 Faa um programa que leia dois vetores de nmeros compostos por 5 elementos que so fornecidos de maneira ordenada (nmeros em ordem crescente). Crie um terceiro vetor que a unio dos dois primeiros vetores, sendo que este novo vetor de 10 elementos tambm deve ser um vetor onde os seus elementos esto ordenados. Exiba a soma total dos elementos contidos nos trs vetores. 5.2 Strings Um dos tipos de arranjos mais comum em C o arranjo de caracteres, ou string. O C padro no suporta um tipo bsico string; ao invs, h uma conveno para tratamento de arranjos de caracteres que permite o uso de diversas funes de manipulao de strings na linguagem. Por conveno, C considera como uma string uma seqncia de caracteres armazenada sob a forma de um arranjo de tipo char cujo ltimo elemento o caractere NUL, ou \0. Por exemplo, uma string poderia ser declarada e inicializada como em: char exemplo[4] = {a,b,c,\0}; Observa-se que o espao para o caractere \0 deve ser previsto quando dimensionado o tamanho do arranjo de caracteres que ser manipulado como string. No exemplo anterior, o arranjo de quatro caracteres pode receber apenas trs letras, j que o ltimo caractere est reservado para o NUL. A linguagem C suporta uma forma alternativa de representao de uma string constante, que atravs do uso de aspas: 69

char exemplo[4] = "abc"; Este exemplo equivalente ao anterior, a string "abc" contm quatro caracteres, sendo que o caractere \0 automaticamente anexado string exemplo[] pelo compilador. 5.2.1 Vetores de caracteres Manipular variveis contendo uma seqncia ou cadeia de caracteres poderia ser tratado da mesma forma que outras variveis numricas. Algumas linguagens de programao e entre elas a linguagem C o fazem de maneira idntica a quaisquer outras variveis. Porm, para que o C trabalhe com variveis de seqncia de caracteres (o tipo string) preciso utilizar a biblioteca <string.h>, a qual no parte do ANSI C, ainda que presente na maioria dos compiladores. Sendo assim, uma varivel string em ANSI C um vetor de caracteres terminado com um caractere nulo. O caractere nulo um caractere com valor inteiro igual a zero (cdigo ASCII igual a 0). O terminador nulo tambm pode ser escrito usando a conveno de barra invertida do C como sendo \0. Embora o assunto vetores tenha sido discutido anteriormente, apresentam-se aqui os fundamentos necessrios para poder-se utilizar as seqncias de caracteres ou strings. Ao declarar uma varivel chamada nome de 13 posies por meio de um vetor de caracteres e inicializ-la com a palavra "Programas", o programador utiliza a seguinte sintaxe: char nome[13] = "Programas"; Na memria os caracteres so armazenados com mostrado a seguir (fig 5.1). Memria (RAM)

\0

Figura 5.1 Armazenando caracteres na memria RAM. No caso anterior, as trs clulas de memria no usadas tm valores indeterminados. Isto ocorre porque o compilador no inicializa as variveis, cabendo ao programador realizar esta tarefa. Portanto as nicas clulas de memria que so inicializadas so as que contm os caracteres P, r, a, g, r, a, m, a, s e \0. Para ler uma string fornecida pelo usurio pode-se utilizar a funo scanf(). Um exemplo do uso desta funo apresentado logo a seguir (ex. 5.5). A funo scanf() coloca o terminador nulo no final do texto da string, quando o usurio pressiona a tecla <enter>.

70

Exemplo 5.5 - Criar um programa que leia o primeiro nome e o ltimo sobrenome de um aluno. Logo aps escrev-lo em ordem de: sobrenome, nome. #include <stdio.h> #include <conio.h> main(){ char nome[15], sobrenome[15]; printf("Digite seu nome: "); scanf("%s",nome); printf("Agora seu sobre nome: "); scanf("%s",sobrenome); printf("\nObrigado!\n"); printf("Sr(a): %s, %s\n",&sobrenome, &nome); getch(); return(0); } No exemplo anterior (ex. 5.5), o tamanho mximo das cadeias de caracteres ou string que voc pode fornecer uma seqncia de 14 caracteres. Se voc entrar com uma seqncia de comprimento maior, o programa ir aceitar, mas os resultados podem ser desastrosos. Como as seqncias so vetores de caracteres, para se acessar um determinado caractere de uma cadeia de caracteres, basta indexar, ou seja, usar um ndice para acessar o caractere desejado dentro da seqncia. Suponha uma seqncia chamada nome, como no exemplo anterior (char nome [13] = "Programa";). Pode-se ter acesso a quarta e stima letra da varivel nome da seguinte forma. nome [3] = g; nome [6] = m; Por qu se est acessando a quarta letra e no a terceira? Na linguagem C, o ndice comea em zero. Assim, a primeira letra da string sempre estar na posio 0. A segunda letra sempre estar na posio 1 e assim sucessivamente. Segue um exemplo (ex. 5.6) que imprimir a quarta e a stima letra da string "Algoritmo". Em seguida, ele mudar estas letras e apresentar a nova string ao final. Exemplo 5.6 - Criar um programa com uma varivel chamada nome que contenha inicialmente a palavra "Algoritmo" e em seguida altere o contedo da mesma para "Algarismo", utilize o acesso a cada caractere (ndice). #include <stdio.h> #include <conio.h> main(){ 71

char nome[15] = "Algoritmo"; printf("Palavra inicial: %s\n",&nome); printf("A quarta letra: %c\n",nome[3]); printf("A setima letra: %c\n",nome[6]); nome [3] = a; nome [6] = s; printf("Palavra atual: %s\n",&nome); printf("A quarta letra: %c\n",nome[3]); printf("A setima letra: %c\n",nome[6]); getch(); return(0); } Nesta cadeia de caracteres, o terminador nulo (\0) est na posio 9. Das posies 0 a 8, tm-se caracteres vlidos, e portanto pode-se escrev-los. Note a forma como foi inicializado a seqncia de caracteres nome com os caracteres A, l, g, o, r, i, t, m, o e \0 simplesmente declarando char nome[15] = "Algoritmo". Observe que "Algoritmo" (uma cadeia de caracteres entre aspas) uma cadeia de caracteres constante, isto , uma cadeia de caracteres que est pr-carregada com valores que no podem ser modificados. J a varivel nome, pode sofrer alteraes em seu contedo armazenado, como de fato foi realizado. No programa (ex 5.6) anterior, %s indica que printf() deve colocar uma seqncia de caracteres (string) na tela. Cadeias de caracteres (string) so vetores de caracteres (char). Nada mais e nada menos. Deve-se apenas ficar atento para o fato de que as strings tm o seu ltimo elemento como um \0. Assim, deve-se lembrar que o tamanho da string deve incluir o \0 final. A biblioteca padro do C possui diversas funes que manipulam strings. Estas funes so teis pois no se pode, por exemplo, igualar duas strings, da forma mostrada a seguir. string1 = string2; /* No faa isto */

Quando se desenvolve programas que tratam de cadeias de caracteres muitas vezes pode-se fazer bom proveito do fato de que uma cadeia termina com \0 (isto , o nmero inteiro 0). Veja o programa (ex. 5.7) a seguir que serve para igualar duas cadeias de caracteres (isto , copia os caracteres de uma string para o vetor da outra). Exemplo 5.7 - Criar um programa para copiar uma cadeia de caracteres em uma outra. #include <stdio.h> #include <conio.h>

72

main(){ int i; char nome[10], copia[10]; printf("Digite seu nome: "); scanf("%s",&nome); for (i = 0;nome[i];i++){ copia[i] = nome[i]; } copia[i] = \0; printf("Esta e uma copia: %s\n",copia); getch(); return(0); } A condio na estrutura de repetio for anterior (ex. 5.7) baseada no fato de que a seqncia de caracteres que est sendo copiada termina em \0. Quando o elemento encontrado em nome[i] o \0, o valor retornado para o teste condicional falso (nulo). Desta forma a expresso que vinha sendo verdadeira (no zero) continuamente, torna-se falsa terminado a estrutura de repetio. 5.2.2 Funes para manipulao de vetores de caracteres Uma outra funo para a leitura de uma cadeia de caracteres, bem como uma srie de funes que manipulam seqncias de caracteres ou strings, so apresentadas a seguir. gets() A funo gets(), assim como a funo scanf(), l ou obtm uma seqncia de caracteres do teclado. Sua sintaxe : #include <stdio.h> gets(variavel_string); Exemplo 5.8 - Criar um programa para copiar uma cadeia de caracteres em uma outra, usando gets() para leitura da seqncia de caracteres. #include <stdio.h> #include <conio.h> int main(){ int i; 73

char nome[40], copia[40]; puts("Digite seu nome: "); gets(nome); for (i = 0;nome[i];i++){ copia[i] = nome[i]; } copia[i] = \0; printf("Esta e uma copia: %s\n",copia); getch(); return(0); } No exemplo anterior (ex. 5.7) a funo scanf() termina a seqncia de caracteres digitados pelo usurio, quando este digita um <enter>, porm armazena somente os caracteres diferentes de espao em branco, ou seja, armazena todos os caracteres digitados at encontrar o primeiro espao ou chegar ao <enter>. J com gets() (ex. 5.8) isto no ocorre. Toda a cadeia armazenada. strcpy() A funo strcpy() copia uma cadeia de caracteres (string_origem) para uma outra cadeia de caracteres (string_destino). Seu funcionamento semelhante ao da rotina apresentada anteriormente (ex. 5.7). Esta e as demais funes apresentadas na seqncia esto definidas na biblioteca <stdio.h>, fazendo-se necessrio incluso da mesma em cada programa que as utilize. Abaixo, tem-se a sintaxe da funo strcpy() e a seguir apresentado um exemplo (ex. 5.9) de uso desta funo. #include <string.h> strcpy (string_destino, string_origem); Exemplo 5.9 - Criar um programa para copiar uma cadeia de caracteres em uma outra, usando strcpy(). #include <stdio.h> #include <conio.h> #include <string.h> main(){ char nome[40], copia[40], mensagem[20]; puts("Digite seu nome: "); gets(nome); strcpy(copia, nome); /* copia nome em copia */ strcpy (mensagem, "Obrigado Sr(a)"); 74

/* copia "Obrigado Sr(a)" em mensagem */ printf("\n%s: %s\n",mensagem,copia); getch(); return(0); } strcat() Esta funo une (concatena) duas cadeias de caracteres. Aps a execuo da funo, a cadeia de caracteres (string_destino) ter o seu contedo acrescido do contedo da cadeia de caracteres (string_origem) que permanecer inalterada. A funo strcat() apresenta a seguinte sintaxe: #include <string.h> strcat(string_destino, string_origem); Exemplo 5.10 - Criar um programa que leia um nome e um sobrenome, logo a seguir unir uma cadeia de caracteres a outra usando strcat() e uma nova varivel para armazen-la. #include <stdio.h> #include <conio.h> #include <string.h> main(){ char nome[15], sobrenome[15], nomecompleto[30] = "", mensagem[20]; puts("Digite seu nome: "); gets(nome); puts("Digite seu sobrenome: "); gets (sobrenome); strcpy(nomecompleto, nome); /* acrescenta nome em nomecompleto */ nomecompleto[strlen(nomecompleto)] = ' '; /* acrescenta espao em nomecompleto */ strcat(nomecompleto, sobrenome); /* acrescenta sobrenome em nomecompleto */ strcpy (mensagem, "Obrigado Sr(a)"); /* copia "Obrigado Sr(a)" em mensagem */ printf("\n%s: %s\n",mensagem,nomecompleto); getch(); return(0); } 75

strlen() A funo strlen() retorna o comprimento da cadeia de caracteres (string) fornecida. O terminador nulo no contado. Isto quer dizer que, de fato, o comprimento do vetor de caracteres deve ser um a mais que o inteiro retornado pela funo strlen(). Sua sintaxe a seguinte: #include <string.h> strlen(string); Exemplo 5.11 - Criar um programa que leia um nome e um sobrenome, una as cadeia de caracteres usando strcat() em uma nova varivel e encontre a quantidade de caracteres (tamanho) esta varivel possui usando a funo strlen(). #include <stdio.h> #include <conio.h> #include <string.h> main(){ int tamanho; char nome[15], sobrenome[15], nomecompleto[30] = ""; puts("Digite seu nome: "); gets(nome); puts("Digite seu sobrenome: "); gets(sobrenome); strcat(nomecompleto, nome); /* acrescenta nome em nomecompleto */ nomecompleto[strlen(nomecompleto)] = ' '; nomecompleto[strlen(nomecompleto)] = '\0'; /* acrescenta espao em nomecompleto */ strcat(nomecompleto, sobrenome); /* acrescenta sobrenome em nomecompleto */ tamanho = strlen(nomecompleto); printf("\nSeu nome completo e: %s\n",nomecompleto); printf("Numero de caracteres = %d\n",tamanho); getch(); return(0); }

76

strcmp() A funo strcmp() compara a cadeia de caracteres (string_1) com a segunda cadeia de caracteres (string_2). Se as duas forem idnticas funo retorna o valor 0 (zero). Se elas forem diferentes a funo retorna algo diferente do valor 0 (no-zero). Sua sintaxe mostrada abaixo: #include <string.h> strcmp(string_1, string_2); Exemplo 5.12 - Criar um programa que compare duas strings e mostre a mensagem So Iguais ou So diferentes dependendo da condio da funo strcmp(). #include <stdio.h> #include <conio.h> #include <string.h> main(){ char str1[15], str2[15]; puts("Digite uma string: "); gets (str1); puts("Digite outra string: "); gets(str2); if (strcmp(str1, str2)){ puts("\nSao diferentes\n"); } else{ puts("\nSao iguais\n"); } getch(); return(0); } 5.2.3 Exerccios Propostos Exerccio 5.14 Entre e exiba seu nome, endereo e idade. Exerccio 5.15 Escreva um programa que mostre vrias linhas (tal qual seu nome e endereo). Voc pode usar vrios comandos printf, cada qual com um caractere de nova linha ou um nico printf com vrias novas linhas na string. Exerccio 5.16 - Criar um programa que leia um nome e um sobrenome, una as cadeia de caracteres usando strcat() em uma nova varivel, certifique-se 77

que o nome e sobrenome esteja separado corretamente por espaos em branco. O programa deve verificar a existncia do espao em branco e caso este no esteja presente, deve ser acrescido ao nome antes de exibir o nome completo. Exerccio 5.17 - Faa um programa que leia quatro palavras pelo teclado, e armazene cada palavra em uma string. Depois, concatene todas as strings lidas em uma nica string. Por fim apresente esta como resultado ao final do programa. Exerccio 5.18 - Crie um programa que mostre o tamanho de cada varivel, incluindo a varivel que armazena todas as palavras do exerccio anterior. Exerccio 5.19 Faa um programa que leia uma lista (mximo 50) de letras terminada pela letra z. Ao final, o programa deve mostrar a quantidade lida de cada vogal. Exerccio 5.21 - Desenvolver um programa de criptografia (codificao de dados visando privacidade de acesso as informaes), onde dada uma String este programa codifique os dados atravs de um processo de substituio de letras (voc pode definir o seu prprio mtodo). Fazer um outro programa complementar a este que deve ser capaz de descriptografar a String, ou seja, deve pegar uma String codificada e retorn-la ao texto original. Exerccio 5.22 Faa um programa que crie um vetor de 26 elementos do tipo caractere. Cada elemento do vetor deve conter uma letra do alfabeto, onde o seu ndice dado pela ordem da letra no alfabeto. Exibir os elementos com ndices pares na tela, e depois os elementos com ndices mpares. 5.3 Matrizes Estrutura semelhante ao vetor, sendo que, pode possuir n dimenses. Desta forma para fazer referncia aos elementos de uma matriz, precisa-se de tantos ndices quanto forem suas dimenses. 5.3.1 Matrizes bidimensionais Nas sees anteriores viu-se como declarar matrizes unidimensionais (vetores). Agora as matrizes bidimensionais. A forma geral da declarao de uma matriz bidimensional muito parecida com a declarao de um vetor. tipo nome_da_matriz [altura] [largura]; muito importante ressaltar que, nesta estrutura, o ndice da esquerda (altura) indexa as linhas e o da direita (largura) indexa as colunas. Ao preencher ou ler uma 78

matriz no C o ndice mais direita varia mais rapidamente que o ndice esquerda. Mais uma vez bom lembrar que, na linguagem C, os ndices variam de zero ao valor declarado, menos um; mas o C no vai verificar isto para o usurio. Manter os ndices na faixa permitida tarefa do programador. Abaixo, tem-se um exemplo (ex. 5.13) do uso de uma matriz para armazenar valores inteiros. Exemplo 5.13 - Criar um programa com uma matriz de 10 linhas e 5 colunas, preenchendo-as com valores seqncias de 1 at 50. #include <stdio.h> #include <conio.h> main(){ int matriz[10][5]; int i,j,valor = 1; printf("\n

Colunas ...");

for (i = 0; i < 10; i++){ printf ("\nLinha %d: ",i); for (j = 0; j < 5; j++){ matriz[i][j] = valor; valor++; printf ("%d",matriz[i][j]); /* Experimente tambem %2d e %02d */ } } getch(); return(0); } Exemplo 5.14 - Criar um programa que leia os elementos de uma matriz inteira 6x6 e escreva os elementos da diagonal principal. #include <stdio.h> #include <conio.h> int main(){ int matriz[6][6]; int i,j; for (i = 0; i < 6; i++){ for (j = 0; j < 6; j++){ printf("Entre com M[%d,%d] = ",i,j); scanf("%d",&matriz[i][j]); } } printf("\nDiagonal principal..."); for (i = 0; i < 6; i++){ printf("\nM[%d,%d] = %d",i,i,matriz[i][i]); 79

} getch(); return(0); } 5.3.2 Matrizes de cadeias de caracteres As matrizes de cadeia de caracteres (strings) so matrizes bidimensionais. Uma string um vetor de caracteres. Ao declarar uma matriz de vetores de caracteres cria-se uma lista de vetores de caracteres. Esta estrutura uma matriz bidimensional de chars. A seguir, v-se a definio geral uma matriz de cadeias de caracteres (strings). char nome_do_variavel [num_de_strings] [compr_das_strings]; Pode ento surgir pergunta: como acessar cada string individual? Simples. Utilizando apenas o primeiro ndice. Assim, para acessar uma determinada string faa: nome_da_variavel [indice]; Exemplo 5.15 - Criar um programa que leia uma lista de 5 nomes de alunos. Aps a leitura apresent-lo em ordem inversa entrada. #include <stdio.h> #include <conio.h> int main(){ char nome[5][50]; int i; for (i = 0; i < 5; i++){ printf("Entre com Nome do Aluno[%d]:",i); gets(nome[i]); } printf("\nNomes em ordem inversa"); for (i = 4; i > -1; i--){ printf("\nNome do Aluno[%d] = %s",i+1,nome[i]); } getch(); return(0); } 5.3.3 Inicializaes Pode-se inicializar matrizes, assim como se pode inicializar variveis comuns. A forma geral de uma matriz, com inicializao : 80

tipo nome_do_variavel [tam1] [tam2] = {lista_de_valores}; A lista_de_valores composta por valores do mesmo tipo da varivel separados por vrgula. Os valores devem ser dados na ordem em que sero inseridos na matriz. A seguir (ex. 5.16) apresentado alguns exemplos de inicializaes de matrizes: Exemplo 5.16 - Inicializando matrizes. float vetor [6] = {2.3, 3.5, 3.4, 5.9, 1.0, 103.1}; int matriz [2][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char str [13] = {'J', 'o', 'a', 'o', '\0'}; char str [13] = "Joao"; char str_vetor [3][10] = {"Jesus", "Maria", "Jose"}; O primeiro (ex. 5.16) demonstra inicializao de vetores de nmeros fracionrios. O segundo exemplo demonstra a inicializao de matrizes multidimensionais, onde matriz est sendo inicializada com 1, 2, 3, 4 e 5 em sua primeira linha e 6, 7, 8, 9 e 10 na segunda e ltima linha. No terceiro exemplo v-se como inicializar uma cadeia de caracteres e, no quarto exemplo, um modo mais compacto de tambm inicializar uma seqncia de caracteres (string). O quinto exemplo combina as duas tcnicas para inicializar uma matriz de vetores de caracteres. 5.3.4 Inicializaes sem a especificao de tamanho Pode-se, em alguns casos, inicializar matrizes das quais no se sabe exatamente o tamanho a priori. O compilador C ir, neste caso verificar o contedo de inicializao e considerar como sendo este o tamanho da matriz. Isto ocorre no momento da compilao e no poder mais ser mudado durante a execuo do programa, sendo muito til, por exemplo, quando se inicializa uma string e sem no entanto precisar contar quantos caracteres sero necessrios para armazen-la. Alguns exemplos a seguir. Exemplo 5.17 - Inicializando vetores e matrizes sem especificar o tamanho destes. int matriz [][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; char str[] = "O compilador C determinarah o tamanho!"; No primeiro exemplo o valor no especificado ser 2. No segundo exemplo, a string str ter o tamanho 39. Veja que o artifcio para realizar a inicializao sem especificar o tamanho no especificar o tamanho. 5.3.5 Passagem de vetores e matrizes Matriz um caso especial e uma exceo regra que parmetros so passados sempre por valor. Como veremos mais adiante, o nome de um vetor corresponde ao endereo do primeiro elemento do array. Quando um vetor passado como parmetro, apenas o endereo do primeiro elemento passado. Existem basicamente trs maneiras de declarar um vetor como um parmetro de uma funo. Na primeira ele declarado como tem sido apresentado em todos os 81

exemplos at agora. O exemplo (ex. 5.18) seguinte mostra um programa que usa uma funo para descobrir a ocorrncia de um determinado nmero em um vetor de inteiros. Exemplo 5.18 - Determinar a ocorrncia ou no de um determinado nmero em um vetor. #include <stdio.h> #include <conio.h> #define NAO_ACHOU -1 #define MAX 10 int pesquisa_linear(int [], int ); main(){ int vet1[MAX], i, num, r; for (i = 0; i < MAX; i++){ printf("Entre com o %do elem do vetor 1: ", i + 1); scanf("%d",&vet1[i]); } printf("Entre com numero: "); scanf("%d",&num); r = pesquisa_linear(vet1, num); if (r != -1) printf("%d esta na posicao %d do vetor.\n", num, r); else printf("Numero nao pertence ao vetor!\n"); getch(); return(0); } int pesquisa_linear(int arr[], int chave){ int i; i = MAX - 1; while (i >= 0){ if (arr[i] == chave){ return(i);} i--; } return (NAO_ACHOU); } Uma outra maneira, leva em conta que apenas o endereo do vetor passado. Neste modo o parmetro declarado como um vetor sem dimenso. Isto perfeitamente possvel porque a funo somente precisa receber o endereo onde se encontra o vetor. 82

Alm disso C no confere limites de vetores e portanto a funo precisa do endereo inicial do vetor e uma maneira de descobrir o final do vetor. Esta maneira pode ser, por exemplo, uma constante, ou o caractere '\0' em um vetor de caracteres. O exemplo (ex. 5.19) mostra este modo de passar vetores com um programa que inverte o contedo de um vetor. Exemplo 5.19 - Determinar o nmero de ocorrncias de cada um dos caracteres presentes no alfabeto em um vetor. #include <stdio.h> #include <conio.h> #define DIM 6 void Le_vetor (int v[], int tam); void Imprime_vetor (int v[], int tam); void Inverte_vetor (int v[], int tam); main(){ int v[DIM]; Le_vetor(v, DIM); Imprime_vetor (v, DIM); Inverte_vetor (v, DIM); Imprime_vetor (v, DIM); getch(); return(0); } void Le_vetor (int v[], int tam){ int i; for (i = 0; i < tam; i++){ printf("%d = ? ", i); scanf("%d", &v[i]);} } void Imprime_vetor (int v[], int tam){ int i; for (i = 0; i < tam; i++){ printf("%d = %d\n", i, v[i]);} } void Inverte_vetor (int v[], int tam){ int i, temp; for (i = 0; i < tam/2; i++){ temp = v[i]; v[i] = v[tam-i-1]; v[tam-i-1] = temp;} } A terceira maneira implica no uso de ponteiros, o que ser visto no prximo 83

captulo. 5.3.6 Exerccios propostos Exerccio 5.23 Faa um programa que crie uma matriz de inteiros de 3 linhas por 3 colunas. Leia os valores desta matriz linha aps linha e exiba a matriz na tela. Exerccio 5.24 Faa um programa que crie uma matriz de inteiros de 5 linhas por 10 colunas. Leia os valores desta matriz linha aps linha e exiba a matriz na tela coluna por coluna. Exerccio 5.25 Faa um programa que leia e visualize uma matriz de nmeros inteiros e que localize a primeira ocorrncia, nessa matriz, de um valor introduzido pelo usurio. A funo deve retornar 1 se o valor recebido com parmetro estiver presente na matriz e 0 (zero) caso contrrio. Exerccio 5.26 Faa um programa que crie uma matriz 3x3x3 onde cada elemento da matriz seja igual soma dos seus ndices. Obtenha a soma de todos elementos da matriz, soma dos elementos cujos valores so pares e a soma dos elementos cujos valores so mpares. Exerccio 5.27 Faa um programa que leia trs vetores independentes compostos por 5 nmeros reais que so fornecidos pelo usurio. Crie uma matriz que rena estes trs vetores em uma nica estrutura. Exibir na tela o contedo da matriz. Encontre o maior valor contido nesta matriz. Exerccio 5.28 Programar a funo int eDigito(char c), que retorna 1 se c um dgito (entre 0 e 9) e 0 caso contrrio. Exerccio 5.29 Implementar int strtam(char s[]) que retorna o tamanho do string s. Exerccio 5.30 Fazer um programa que procura a ocorrncia de um caractere c em uma string s e imprime Achou! caso c aparea em s e Nada! caso contrrio. Exerccio 5.31 Faa um programa que, dado um nmero inteiro longo, verifique se negativo e, caso no o seja, determine se ou no capicua. Um nmero capicua quando lido da esquerda para a direita ou da direita para a esquerda representa sempre o mesmo valor, como por exemplo 77, 434, 6446 e 82328. Para obter um nmero capicua a partir de outro, inverte-se a ordem dos algarismos e soma-se com o nmero dado, um nmero de vezes at que se encontre um nmero capicua. 5.4 Definio de estruturas

84

Por meio de estruturas, a linguagem C oferece um mecanismo uniforme para a definio de unidades de informaes organizadas em campos. A forma geral de definio de uma estrutura C struct nome { /* declaracao de componentes: */ ... } [var1, var2, ..., varN]; A palavra chave struct inicia a definio da estrutura. O nome opcional, porm deve estar presente caso se deseje referenciar esta estrutura em algum momento posterior. Da mesma forma, a lista de variveis declaradas (var1, ... , varN) tambm no precisa estar presente a no ser que nome no esteja presente. Quando nome est presente, as variveis com essa mesma estrutura podem ser definidas posteriormente, como na declarao a seguir, struct nome varM; que define varM como sendo uma varivel do tipo struct nome. Alternativamente, seria possvel associar um nome de tipo para essa estrutura atravs da declarao, typedef struct nome Nome; e ento declarar varM como Nome varM; Da mesma forma que tipos bsicos, estruturas podem ser passadas como argumentos ou serem valores de retorno de funes. Uma vez que uma estrutura tem componentes internos que devem ser acessados para processamento, algum mecanismo de acesso deve ser fornecido pela linguagem. O C oferece dois operadores que permitem acessar elementos de estruturas. O operador bsico de acesso a elementos de estruturas o operador . (ponto). Uma verso simplificada da leitura de uma data sendo armazenada em uma estrutura data mostrada a seguir (ex. 5.20). A estrutura dados_pessoais tambm est presente neste programa (ex. 5.20) para demonstrar a possibilidade de reutilizar a estrutura data j existente. Exemplo 5.20 - Desenvolver um programa para ler a data atual e o dados de um estudante, usando estruturas. #include <stdio.h> #include <conio.h> struct data{ int dia; int mes; int ano; };

85

struct dados_pessoais{ char nome[40]; char endereco[50]; struct data nascimento; }; main(){ struct data hoje; struct dados_pessoais estudante; printf("\nEntre com o dia de hoje: "); scanf("%d",&hoje.dia); printf("\nEntre com o mes atual: "); scanf("%d",&hoje.mes); printf("\nEntre com o ano corrente: "); scanf("%d",&hoje.ano); getchar(); printf("\nEntre com o seu nome: "); gets(estudante.nome); printf("\nEntre com o seu endereco: "); gets(estudante.endereco); printf("\nEntre com o dia de seu nascimento: "); scanf("%d",&estudante.nascimento.dia); printf("\nEntre com o ms de seu nascimento: "); scanf("%d",&estudante.nascimento.mes); printf("\nEntre com o ano de seu nascimento: "); scanf("%d",&estudante.nascimento.ano); ... getch(); return(0); } Em aplicaes sucessivas desse operador, quando for necessrio acessar estruturas aninhadas, sua associatividade da esquerda para a direita. 5.5 Enumeraes Uma outra forma de tipo composto em C a enumerao. Usualmente, faz parte do processo de desenvolvimento de um programa associar cdigos numricos a variveis que podem assumir um nico valor dentre um conjunto finito de opes. O tipo enumerao permite associar nomes descritivos a tais conjuntos de valores numricos. Considere uma extenso da estrutura dados_pessoais apresentada acima que incorporasse tambm o sexo da pessoa. H dois estados possveis para uma varivel deste tipo: ela pode assumir o valor masculino ou o valor feminino. Uma enumerao que poderia representar este tipo de informao seria, 86

enum sex {masculino, feminino}; Uma varivel deste tipo de enumerao poderia ser ento incorporada na estrutura apresentada a seguir, struct dados_pessoais { char nome[40]; struct data nascimento; enum sex genero; }; O seguinte trecho de programa ilustra como os nomes descritivos definidos em enumeraes so utilizados como valores: Exemplo 5.21 - Determinar a idade de uma pessoa utilizando estruturas e uma funo para realizar o clculo. #include <stdio.h> #include <conio.h> enum sex {masculino, feminino}; struct data{ int dia; int mes; int ano; }; struct dados_pessoais{ char nome[40]; struct data nascimento; enum sex genero; }; int calc_idade(struct dados_pessoais p, struct data h); main(){ struct data hoje; struct dados_pessoais pessoa; printf("\nEntre com o dia de hoje: "); scanf("%d",&hoje.dia); printf("\nEntre com o ms atual: "); scanf("%d",&hoje.mes); printf("\nEntre com o ano corrente: "); scanf("%d",&hoje.ano); getchar(); printf("\nEntre com o seu nome: "); gets(pessoa.nome); 87

printf("\nEntre com o dia de seu nascimento: "); scanf("%d",&pessoa.nascimento.dia); printf("\nEntre com o ms de seu nascimento: "); scanf("%d",&pessoa.nascimento.mes); printf("\nEntre com o ano de seu nascimento: "); scanf("%d",&pessoa.nascimento.ano); printf("\nSexo: (0) masculino e (1) feminino: "); scanf("%d",&pessoa.genero); printf("\nSua idade eh: %d",calc_idade(pessoa,hoje)); getch(); return(0); } int calc_idade(struct dados_pessoais p, struct data h){ int idade; idade = h.ano - p.nascimento.ano; if (p.genero == feminino) idade -= 5; return(idade); } Internamente, o compilador designa o valor 0 para o primeiro smbolo da enumerao, e incrementa de um o valor associado a cada smbolo na seqncia. Isto pode ser modificado se o programador quiser atravs de atribuio explcita de um valor inteiro a um smbolo, como em: enum cedula {beijaflor = 1, garca = 5, arara = 10}; 5.6 Definio de nomes de tipos Embora C no permita a criao de novos tipos de dados, ela oferece uma facilidade para criar novos nomes para os tipos existentes, sejam eles bsicos ou derivados. Este mecanismo, typedef, permite principalmente melhorar a facilidade de compreenso de programas. A forma geral de uma definio de nome de tipo : typedef tipo novo_nome; Por exemplo, os tipos de estruturas data e dados_pessoais definidos anteriormente poderiam ser associados a nomes de tipos Data e Pessoa respectivamente pelas declaraes, typedef struct data Data; typedef struct dados_pessoais Pessoa; Com estas definies, as declaraes do programa que apresenta a idade de pessoas poderiam ser reescritas como: 88

Exemplo 5.22 - Calcular a idade de uma pessoa com definio de tipos, estruturas e enumeraes. #include <stdio.h> #include <conio.h> typedef enum sex {masculino, feminino} Sexo; typedef struct data{ int dia; int mes; int ano; }Data; typedef struct dados_pessoais{ char nome[40]; Data nascimento; Sexo genero; }Pessoa; int calc_idade(Pessoa p, Data d); Data le_hoje(); Pessoa le_aluno(); main(){ Data hoje; Pessoa estudande_graduacao; int idade; ... } Outros exemplos de uso de typedef so: typedef unsigned int Tamanho; typedef enum {false = 0, true} Boolean; 5.7 Exerccios propostos Exerccio 5.32 A funo abaixo que recebe a data de incio de um evento e a durao do evento em dias. Ela devolve a data de fim do evento. struct dma converte(struct dma datainicio, int duracao){ struct dma datafim; . . . . . . datafim.dia = ... datafim.mes = ... datafim.ano = ...

89

return(datafim); } O cdigo deve levar em conta a existncia de meses com 31 dias, de meses com 30 dias, com 29 dias, etc. Eis como essa funo poderia ser usada: int main(void){ struct dma inicio; struct dma fim; int dura; scanf ("%d%d%d", &inicio.dia, &inicio.mes, &inicio.ano); scanf ("%d", &dura); fim = converte (inicio, dura); printf ("%d %d %d\n", fim.dia, fim.mes, fim.ano); return(0); } Complete o cdigo da funo do exerccio. Exerccio 5.34 Escreva uma funo que receba um nmero inteiro que representa um intervalo de tempo medido em minutos e devolva o correspondente nmero de horas e minutos (por exemplo, converte 131 minutos em 2 horas e 11 minutos). Use uma struct como a seguinte: struct horasEminutos{ int horas; int minutos; }; Exerccio 5.35 Defina uma struct empregado para guardar os dados (nome, sobrenome, data de nascimento, RG, data de admisso, salrio) de um empregado de sua empresa. Defina um vetor de empregados para armazenar todos os empregados de sua empresa.. Exerccio 5.36 Suponha que No queria manter um registo informatizado, utilizando um programa em C, de todos os animais que levava na sua arca. Defina um tipo, chamado Animal, para guardar a seguinte informao: nome - cadeia de caracteres com um maximo de 30 caracteres habitat - um dos valores terra, agua e ar peso - um float a) Escreva uma funo que leia e armazene as informaes acima para cada ums dos animais guardados na arca. A funo termina quando o usurio indicar um nome vazio. b) Escreva uma funo que receba lista de todos os animais guardados na arca e calcule o peso total dos animais. c) Escreva uma funo que receba lista de todos os animais guardados 90

na arca e encontre o animal mais pesado da arca. Exerccio 5.37 Fazer uma rotina que receba como parmetro um vetor de 5 posies contendo as notas de um aluno ao longo do ano e devolve a mdia do aluno. Exerccio 5.38 Fazer uma rotina que receba um array do tipo double e o nmero de valores que devem ser solicitados ao usurio e devolve o array preenchido com os valores digitados. Exerccio 5.39 Fazer um programa em linguagem C que leia um conjunto de 10 valores inteiros e verifica se algum dos valores igual mdia dos mesmos. Exerccio 5.40 Fazer um programa que leia valores para uma matriz do tipo float de 5 linhas por 3 colunas e imprima a diferena entre a mdia dos elementos das colunas pares e a mdia dos elementos das linhas mpares. Exerccio 5.41 Fazer um programa em C que leia uma string qualquer de no mximo 80 caracteres e imprima: a) Quantos caracteres tm a string; b) Quantos caracteres so de pontuao; c) Quantos caracteres so nmeros; d) Quantos caracteres so minsculos. Exerccio 5.42 Fazer um programa em C que leia uma string contendo palavras separadas por um espao em branco cada e as imprima uma abaixo das outras. Exerccio 5.43 Fazer um programa em C que leia uma string do teclado e que se utilize uma rotina recursiva para imprimir a string de maneira normal e de traz para frente. Exerccio 5.44 Fazer uma funo para ler e retornar o valor das 3 notas de um aluno. Exerccio 5.45 Fazer um programa em C que pergunte o nome, o endereo, o telefone e a idade de uma pessoa e monte uma string com a seguinte frase: "Seu nome ..., voc tem ... anos, mora na rua ... e seu telefone ... ." Exerccio 5.46 Fazer uma rotina que aguarda uma string do teclado e retorna o valor 1 se a string digitada foi "SIM" e 0 se a string digitada foi "NAO". A rotina s deve retornar alguma coisa se a string digitada for "SIM" ou "NAO". Exerccio 5.47 Fazer uma rotina que recebe uma string como parmetro e imprime quantas palavras (separadas por espaos em branco) o mesmo contm. 91

Exerccio 5.48 Implemente uma rotina que faa a mesma coisa que a funo "strcpy". Exerccio 5.49 Fazer um programa em C que solicite um nmero inteiro e soletra o mesmo na tela. Ex: 124: um, dois, quatro. Exerccio 5.50 Escrever uma funo que recebe uma string e um caractere como parmetro e remova todas as ocorrncias do caractere da string. Exerccio 5.51 Escreva uma funo em C que receba uma string, um caractere e o ndice de uma posio da string como parmetro e insira o caractere na posio "empurrando" todos os demais para o lado. Exerccio 5.52 Fazer uma rotina em C que recebe uma string como parmetro e devolve o endereo do primeiro caractere branco encontrado. Exerccio 5.53 Fazer uma funo que retorna a soma, a diferena e o produto entre dois nmeros. Exerccio 5.54 Fazer uma funo em C que retorna a razo entre dois nmeros. A funo deve retornar pelo comando return o valor 1 se a operao for possvel e o valor 0 se a operao no for possvel (diviso por zero, por exemplo). O resultado da diviso deve retornar por um parmetro por referncia. Exerccio 5.55 Fazer uma rotina em C que recebe um vetor de nmeros inteiros como parmetro onde todos os valores exceto o ltimo so positivos e devolve: a) a mdia dos valores do vetor; b) o menor valor do vetor (sem considerar o ltimo); c) o maior valor do vetor. Exerccio 5.56 Construir um programa em C que implementa uma agenda eletrnica. O programa deve ter um menu com as seguintes opes: a) Entrar um novo nome na agenda; b) Imprimir na tela os dados de uma das pessoas cadastradas (conforme solicitao); c) Imprimir a lista de nomes cadastrados que comecem pela letra indicada; d) Fim. Cada entrada da agenda deve ter os seguintes campos: char char char long nome[30]; endereco[100]; fone[10]; int CEP; 92

Obs: A agenda deve ter capacidade para 100 entradas. Exerccio 5.57 Criar uma funo que testa um caractere recebido e verifica se vogal. Devolve o valor 1 se for vogal e 0 (zero) se for consoante. Fazer um programa principal que recebe uma frase, verifica todas as letras usando a funo e no final informa o total de vogais, consoantes e brancos. Tambm informar o valor em percentual de vogais, consoantes e brancos, com relao ao total geral de letras (+ brancos) da frase.

93

6 Ponteiros
Ponteiros constituem um dos recursos mais utilizados na programao C. Eles fornecem um mecanismo poderoso, flexvel e eficiente de acesso as variveis. Um ponteiro uma varivel que contm um endereo de outra varivel. Este mecanismo deve ser utilizado com critrio e disciplina. O uso descuidado de ponteiros pode levar a situaes onde um endereo invlido acessado, levando a erros de execues de programas. Para definir que uma varivel vai guardar um endereo, o operador unrio * utilizado na declarao, como em: /* define um ponteiro para um inteiro */ int *ap; /* algumas variaveis inteiras */ int x, y; Nas instrues acima, ap uma varivel do tipo ponteiro para inteiro, ou seja, ela ir receber um endereo de uma varivel inteira. Para se obter o endereo de uma varivel, o operador unrio & pode ser utilizado. Ainda no exemplo acima, atribui-se ap o endereo de uma varivel int, uma vez que ap um apontador para um int. /* ap recebe o endereco de x */ ap = &x; Aps esta instruo, diz-se que ap aponta para x (fig. 6.1). possvel acessar o valor da varivel x por meio do ponteiro usando o operador unrio *, como em: /* y recebe o conteudo da variavel apontada por ap */ y = *ap; Observa-se que a combinao *ap um inteiro, que pode assim ser atribudo a outro inteiro. Esta associao pode facilitar a compreenso da declarao de ponteiros. No exemplo, int *ap pode ser lido como *ap um inteiro. Tambm seria possvel definir o valor de x por meio do ponteiro, como em: /* o conteudo da variavel apontada por ap recebe y */ *ap = y; Ponteiros podem tomar parte em expresses aritmticas. Assim, a seguinte expresso perfeitamente vlida: 94

y = *ap + 1; ou seja, y receberia o valor de x (varivel apontada por ap) incrementado de 1 (uma unidade).

Figura 6.1 - Espao ocupado pelas variveis. 6.1 Exerccios propostos Exerccio 6.1 Pratique a declarao e utilizao de ponteiros. 1) defina e inicialize uma varivel inteira; 2) defina um ponteiro para inteiro; 3) modifique o valor da varivel por meio do ponteiro; 4) verifique os novos valores da varivel usando printf();

6.2 Aritmtica de Ponteiros No apenas os contedos dos ponteiros podem tomar parte em expresses aritmticas. C tambm suporta o conceito de operaes sobre endereos, embora as operaes que possam ser utilizadas neste caso sejam limitadas. Tais operaes definem a aritmtica de ponteiros. Para apresentar o conceito de aritmtica de ponteiros, considere o seguinte exemplo (ex. 6.1): Exemplo 6.1 - Inicializando um vetor de 10 posies utilizando um ponteiro para um inteiro. #include <stdio.h> #include <conio.h> main(){ int arr[10]; /* arr: arranjo com 10 inteiros */ int *el; /* el: ponteiro para um inteiro */ int i; el = &arr[0]; /* inicializa ponteiro */ /* inicializa conteudo do arranjo via ponteiro */ for (i = 0; i < 10; i++) *(el + i) = 0;

95

getch(); return(0); } O ponteiro el aponta inicialmente para o primeiro elemento do arranjo arr, ou seja, arr[0] - &arr[0] o endereo deste elemento. Assim, para acessar este elemento por meio do ponteiro, a expresso *el poderia ser utilizada. No entanto, possvel tambm acessar outros elementos do arranjo por meio do ponteiro. Para acessar o elemento seguinte, a expresso *(el + 1) retorna o endereo do prximo inteiro armazenado aps o endereo el, ou seja, o endereo de arr[1]. Portanto, o que a instruo interna ao lao no exemplo est realizando o acesso a cada elemento do arranjo por meio de um ponteiro. Um aspecto fundamental da aritmtica de ponteiros que ela libera o programador de saber qual a dimenso alocada para cada tipo de dado. Quando um ponteiro incrementado, este incremento ir refletir o tamanho do tipo da varivel que est sendo apontada. Assim, o exemplo anterior (ex. 6.1) funcionar independentemente da mquina no qual ele for executado, ocupe a representao de um inteiro dois ou quatro bytes. Quando a expresso el + i encontrada, o endereo do i-simo inteiro aps o endereo el obtido - ou seja, esta expresso aponta para o elemento arr[i]. A aritmtica de ponteiros est limitada a quatro operadores: soma, subtrao, incremento e decremento. Outra limitao que, no caso de soma, o outro operando alm do ponteiro deve ser uma expresso (ou varivel ou constante) inteira. A subtrao de dois ponteiros para um mesmo tipo de dado uma operao vlida, retornando o nmero de elementos entre os dois ponteiros. A comparao entre dois ponteiros tambm uma operao legal. H uma nica exceo ao uso legal de aritmtica de ponteiros: quando um ponteiro definido para o tipo void. Neste caso, a varivel tipo ponteiro contm um endereo genrico, sobre um tipo que no pode ser determinado. Portanto, operaes aritmticas sobre este tipo de ponteiro no so permitidas. 6.3 Ponteiros e Arranjos Como observado no exemplo anterior (ex. 6.1), ponteiros e arranjos esto intimamente relacionados em C. Na verdade, qualquer referncia a um arranjo convertida internamente para uma referncia do tipo ponteiro. Por este motivo, quando eficincia de tempo de acesso uma preocupao, muitos programadores trabalham diretamente com ponteiros. O nome de um arranjo uma expresso do tipo ponteiro que corresponde ao endereo do primeiro elemento do arranjo. Assim, a inicializao do ponteiro no exemplo acima poderia ser reescrita como el = arr; /* arr equivale a &arr[0] */ Observa-se que, uma vez que arr equivale a um ponteiro, o elemento arr[i] poderia ser acessado da mesma forma como *(arr + i). Por outro lado, o inverso (usar o operador de indexao como uma varivel ponteiro) tambm possvel. Assim, o lao de atribuio no exemplo anterior (ex. 6.1) 96

poderia ter sido escrito como: for (i = 0; i < 10; i++) el[i] = 0; Apesar da forma usando o operador * ser mais eficiente, programadores iniciantes muitas vezes acham mais simples entender o acesso usando o operador de indexao, e acabam preferindo esta forma. Uma diferena fundamental entre um ponteiro e o nome de um arranjo que o ponteiro uma varivel, enquanto que o nome de um arranjo uma constante. Assim, expresses como arr++ ou &arr no fazem sentido. Outra diferena que deve ser ressaltada o fato de que a declarao de um arranjo efetivamente reserva o espao para as variveis, enquanto que a declarao de um ponteiro reserva apenas espao para guardar um endereo. Considere o seguinte exemplo (ex 6.2): Exemplo 6.2 - Uso indevido de um ponteiro para um inteiro. #include <stdio.h> #include <conio.h> main(){ int *el; /* el: ponteiro para inteiro */ int i; /* inicializa conteudo */ for (i = 0; i < 10; i++) el[i] = 0; /* onde esta el[i]? */ getch(); return(0); } Uma vez que o ponteiro el no foi inicializado, a expresso el[i] pode estar apontando para qualquer posio da rea de memria possivelmente, para alguma posio invlida. Observa-se que o fato de ter declarado o ponteiro no significa que esta varivel possa ser utilizada como um arranjo. Para tal, o ponteiro deve estar com o endereo de alguma posio vlida, seja por meio de uma atribuio envolvendo um arranjo, seja por meio do uso de rotinas de alocao dinmica. Uma vez que ponteiros so variveis, nada impede que arranjos de ponteiros sejam definidos. De fato, uma declarao tal como: int *aa[10]; define uma varivel aa que um arranjo de dez ponteiros para variveis inteiras. Cada elemento deste arranjo, desde aa[0] at aa[9], um ponteiro para inteiro(s) que tem a mesma propriedade que os ponteiros vistos at o momento. Observa-se que esta forma suporta uma alternativa para trabalhar com arranjos multidimensionais, desde que respeitadas as diferenas entre ponteiros e arranjos. Arranjos de ponteiros trazem uma flexibilidade adicional pelo fato de que cada linha 97

pode ter tamanho varivel. No exemplo acima, cada ponteiro aa[i] pode estar apontando para um inteiro, para o primeiro elemento de um arranjo com diversos inteiros, ou mesmo para nenhum inteiro. Soma Ao somar-se um inteiro n a um ponteiro, endeream-se n elementos a mais (n positivo) ou a menos (n negativo): pf[2] equivale a *(pf+2) *(pf + n) enderea n elementos frente; *(pf - n) enderea n elementos atrs; pf++ enderea o prximo elemento do array; pf-enderea o elemento anterior do array; Operaes vlidas sobre ponteiros 1) somar ou subtrair um inteiro a um ponteiro 2) incrementar ou decrementar ponteiros 3) subtrair ponteiros (produz um inteiro) 4) comparar ponteiros No vlido 1) somar ponteiros (pi + pf) 2) multiplicar ou dividir ponteiros (pi * pf, pi / pf) 3) operar ponteiros com double ou float(pi 2.0) Exemplo 6.3 Inicialize um vetor de inteiros aleatoriamente e percorra o vetor usando ponteiro: a) endereo_base + deslocamento b) O ponteiro como um vetor. #include #include #include #include <stdio.h> <stdlib.h> <conio.h> <time.h> (pi int) (pi++, pi--) (pf - pi) (>, >=, <, <=, ==)

#define MAX 10 main(){ int A [MAX]; int *p; srand((unsigned)time(NULL)); for (int i = 0; i < MAX; i++){ A[i] = rand() % 100;} p = A; /* p = &A[0]; */ 98

printf printf printf printf

("\nEndereco inicial do vetor = %p",A); ("\nEndereco do ponteiro p = %p",&p); ("\nEndereco para o qual p aponta = %p",p); ("\nMostrando com for \n");

for (int i = 0;i < MAX; i++){ printf ("%d, ", A[i]);} printf ("\nCom ponteiro(end_base + deslocamento)\n"); for (int i = 0; i < MAX; i++){ printf ("%d, ",*(p+i));} printf ("\nCom ponteiro semelhante a um vetor\n"); for (int i = 0; i < MAX; i++){ printf ("%d, ",p[i]);} getch(); } 6.3.1 Exerccios propostos Exerccio 6.2 Exerccio 6.3 Escreva um programa que imprima um vetor de inteiros na ordem inversa endereando os elementos com um ponteiro. O C no controla os limites dos vetores, o programador deve faz-lo. Encontre os erros e corrija-os: a) void main(){ int arint[] = {1,2,3,4,5,6,7}; int size = 7, i, *pi; for (pi = arint, i = 0; i < size; i++, pi += 2) printf("%d", *pi); } b) void main(){ int arint[] = {1,2,3,4,5,6,7}; int size = 10; int i; for (pi = arint, i = 0; i < size; i++) printf("%d", arint[i]); }

6.4 Ponteiro genrico Um ponteiro genrico um ponteiro que pode apontar para qualquer tipo de dado. Define-se um ponteiro genrico utilizando-se o tipo void: Exemplo 6.4 - Definindo um ponteiro para void.

99

#include <stdio.h> #include <conio.h> main(){ void *pv; int x = 10; float f = 3.5; pv = &x; /* aqui pv aponta para um inteiro */ pv = &f; /* aqui, para um float */ } O tipo de dado apontado por um ponteiro void deve ser controlado pelo programador. Usando um type cast (converso de tipo) o programa pode tratar adequadamente o ponteiro. Exemplo 6.5 - Definindo um ponteiro para void e acessando o contedo apontado por ele com converso de tipo. #include <stdio.h> #include <conio.h> main(){ void *pv; int x = 10; float f = 3.5; pv = &x; /* aqui pv aponta para um inteiro */ printf("Inteiro: %d\n", *(int *)pv); /*=> 10*/ pv = &f; /* aqui, para um float */ printf("Fracionario: %f\n", *(float *)pv); /*=> 3.5*/ getch(); return(0); } 6.5 Ponteiro como argumento de funes A passagem por valor, padro em C, no permite que uma funo manipule diretamente uma varivel que lhe esteja sendo passada. Quando se deseja manipular diretamente a varivel, ponteiros devem ser usados como o recurso de acesso. Para ilustrar esta condio, imagine como implementar a rotina troca que recebe dois argumentos de um mesmo tipo e troca seus valores. Por exemplo, para trocar dois inteiros, algo similar seguinte funo seria desejado (ex. 6.6): Exemplo 6.6 - Definindo uma funo capaz de trocar dois valores (errado). #include <stdio.h> #include <conio.h> 100

void troca_erro(int el1, int el2); main(){ int x = 2, y = 3; printf("x = %d e y = %d\n", x, y); troca_erro(x,y); printf("x = %d e y = %d\n", x, y); getch(); return(0); } void troca_erro(int el1, int el2){ int temp; /* variavel temporaria */ temp = el1; el1 = el2; el2 = temp; } Entretanto, como pode ser observado, no comentrio inicial, esta funo no funciona. Supondo que a funo main() do programa anterior (ex. 6.6) tente acessar esta rotina, tem-se como resultado o seguinte: x = 2, y = 3 x = 2, y = 3 Como se observa, a funo troca_erro no realiza a troca de valores das variveis x e y de main(), apesar de sua lgica interna estar correta. O que troca_erro faz trocar os valores das cpias destas variveis, que so apenas suas variveis locais. A fim de obter-se o efeito desejado, ponteiros devem ser utilizados como argumentos. Assim, os elementos a serem trocados sero acessados por seus endereos, e seus contedos sero efetivamente alterados. Nesta nova verso (ex. 6.7), a funo troca definida como: Exemplo 6.7 - Definindo uma funo capaz de trocar dois valores (correto). #include <stdio.h> #include <conio.h> void troca(int *el1, int *el2); main(){ int x = 2, y = 3; printf("x = %d e y = %d\n", x, y); 101

troca(&x,&y); printf("x = %d e y = %d\n", x, y); getch(); return(0); } void troca(int *el1, int *el2){ int temp; /* variavel temporaria */ temp = *el1; *el1 = *el2; *el2 = temp; } A chamada funo deve passar os endereos das variveis, como em troca(&x,&y); a sada obtida neste caso seria: x = 2, y = 3 x = 3, y = 2 como desejado. Outros usos de ponteiros como argumentos incluem funes que devem retornar mais de um valor e a passagem de arranjos para funes. Quando um arranjo passado para uma funo, na verdade o que se passa o endereo de seu primeiro elemento. Quando o argumento um arranjo multidimensional, apenas a dimenso do primeiro ndice pode ser omitida - as demais devem ser fornecidas. Caso contrrio, seria impossvel saber como acessar corretamente os elementos do arranjo. 6.6 Ponteiros e estruturas Uma vez que variveis do tipo estrutura so tratadas exatamente da mesma forma que variveis de tipos bsicos, possvel definir variveis do tipo ponteiro para estruturas, como em: struct dados_pessoais *pa; Componentes de uma estrutura podem ser ponteiros para outros tipos de dados ou estruturas. Em algumas situaes, pode haver a necessidade de ter como um dos componentes da estrutura um ponteiro para um tipo da prpria estrutura. Um exemplo tpico a construo de listas ligadas (ser visto em detalhes no captulo 7), compostas por ns onde um dos dados armazenados em cada n um ponteiro para o prximo n. Esta situao seria representada como:

102

struct no_lista { /* conteudo do no: */ ... /* ponteiro ao proximo no: */ struct no_lista *proximo; }; Uma forma bsica de acesso aos membros de uma estrutura (por meio do operador (.) ponto) j foi descrita. A outra forma de acesso aos membros das estruturas facilitam a notao quando ponteiros para estruturas esto envolvidos. Para ilustrar esta forma, suponha que uma funo que leia os dados de um aluno no programa a seguir (ex. 6.8) retorne na verdade um ponteiro para uma estrutura do tipo dados_pessoais. struct dados_pessoais *le_aluno(); /* prototipo */ struct dados_pessoais *aluno_pt; /* ponteiro */ aluno_pt = le_aluno(); O acesso a membros da varivel aluno_pt poderia ser feito da forma usual, ou seja, *aluno_pt uma estrutura, ento seria possvel acessar seus membros como em: printf("%s nasceu em %2d/%2d/%4d\n", (*aluno_pt).nome, (*aluno_pt).nascimento.dia, (*aluno_pt).nascimento.mes, (*aluno_pt).nascimento.ano); A notao simplificada utiliza o ponteiro -> (seta) para substituir uma construo na forma (*A).M por A -> M. Exemplo 6.8 - Calculando a idade de um aluno usando funes e ponteiros. #include <stdio.h> #include <conio.h> struct data{ int dia; int mes; int ano; }; struct dados_pessoais{ char nome[40]; struct data nascimento; }; int calc_idade(struct dados_pessoais *p, struct data *h); struct data le_hoje(void); struct dados_pessoais *le_aluno(struct dados_pessoais *pp); main(){ 103

struct data hoje; struct dados_pessoais *aluno_pt, pessoa; int idade; hoje = le_hoje(); getchar(); /* Limpa o buffer de entrada */ aluno_pt = le_aluno(&pessoa); idade = calc_idade(aluno_pt, &hoje); printf("Idade de %s: %d\n", aluno_pt->nome, idade); getch(); return(0); } struct data le_hoje(void){ struct data h; printf("\nEntre com o dia de hoje: "); scanf("%d",&h.dia); printf("\nEntre com o mes atual: "); scanf("%d",&h.mes); printf("\nEntre com o ano corrente: "); scanf("%d",&h.ano); return(h); } struct dados_pessoais *le_aluno(struct dados_pessoais *pp){ printf("\nEntre com o seu nome: "); gets(pp->nome); printf("\nEntre com o dia de seu nascimento: "); scanf("%d",&pp->nascimento.dia); printf("\nEntre com o ms de seu nascimento: "); scanf("%d",&pp->nascimento.mes); printf("\nEntre com o ano de seu nascimento: "); scanf("%d",&pp->nascimento.ano); return(pp); } int calc_idade(struct dados_pessoais *p, struct data *h){ int idade; idade = h->ano - p->nascimento.ano; return(idade); } para realizar o clculo.

104

6.7 Exerccios propostos Exerccio 6.4 Procure determinar quais valores so impressos ao final deste programa. Confira sua resposta testando o programa na ferramenta de programao (C Quietly). Execute-o passo a passo conferindo o valor das variveis em cada momento.

a)

void main(){ int a,b,*c; a = 3; b = 4; c = &a; b++; *c = a+2; printf("%d %d",a,b); } void main(){ int a,b,*c; a = 4; b = 3; c = &a; *c = *c +1; c = &b; b = b+4; printf("%d %d %d",a,b,*c); } void main(){ int a,b,*c,*d,*f; a = 4; b = 3; c = &a; d = &b; *c /= 2; f = c; c = d; d = f; printf("%d %d",*c,*d); } int calcula(int); void main(){ int a, b, c; char d; a = 1;b = 2;c = 3;d = 'A'; a += b * c; d = (a > 7) ? d - 1 : d + 1; b = calcula(b); c = calcula(calcula(a)); a = c++; printf("%d - %d - %d - %c\n", a, b, c, d); 105

b)

c)

d)

} int calcula(int x){ int i; if ((x = x * 2) > 5) return(x + 3); for(i = 0;i < 10; i++){ if (i < 5) continue; if (x > 8) break; x += 2;} return(x); } Exerccio 6.5 Ciar um programa que utilize um ponteiro para exibir uma string inserida pelo usurio. Mostrando a string completa num nico comando. Repita o exerccio anterior (ex. 6.5) mostrando agora caractere a caractere. Desenvolva um programa que leia uma frase e um caractere e procure utilizando uma funo que devolve um ponteiro para a posio do caractere na string lida. Utilize a funo do exerccio anterior (ex. 6.7) para imprimir a string a partir de um caractere informado.

Exerccio 6.6 Exerccio 6.7

Exerccio 6.8

Exerccio 6.9 Seja o seguinte trecho de programa: int int p = q = i=3,j=5; *p, *q; &i; &j;

Qual o valor das seguintes expresses? a) p == &i; b) *p - *q c) *&p d) 3* - *p/(*q)+7

Exerccio 6.10 Qual sero as sadas do seguinte programa? #include <stdio.h> #include <conio.h> int main() { int valor; int *p1; float temp; float *p2; char aux; char *nome = "Algoritmos"; char *p3; int idade; int vetor[3]; 106

int int

*p4; *p5;

/* (a) */ valor = 10; p1 = &valor; *p1 = 20; printf("(a) %d \n", valor); /* (b) */ temp = 26.5; p2 = &temp; *p2 = 29.0; printf("(b) %.1f \n", temp); /* (c) */ p3 = &nome[0]; aux = *p3; printf("(c) %c \n", aux); /* (d) */ p3 = &nome[4]; aux = *p3; printf("(d) %c \n", aux); /* (e) */ p3 = nome; printf("(e) %c \n", *p3); /* (f) */ p3 = p3 + 4; printf("(f) %c \n", *p3); /* (g) */ p3--; printf("(g) %c \n", *p3); /* <h> */ vetor[0] = 31; vetor[1] = 45; vetor[2] = 27; p4 = vetor; idade = *p4; printf("(h) %d \n", idade); /* (i) */ p5 = p4 + 1; idade = *p5; printf("(i) %d \n", idade); /* (j) */ p4 = p5 + 1; idade = *p4; printf("(j) %d \n", idade); 107

/* (l) */ p4 = p4 - 2; idade = *p4; printf("(l) %d \n", idade); /* (m) */ p5 = &vetor[2] - 1; printf("(m) %d \n", *p5); /* (n) */ p5++; printf("(n) %d \n", *p5); return(0); } Exerccio 6.11 Qual o resultado do seguinte programa? #include <conio.h> #include <stdio.h> void main(){ float vet[5] = {1.1,2.2,3.3,4.4,5.5}; float *f; int i; f = vet; printf("contador/valor/valor/endereco/endereco"); for(i = 0 ; i <= 4 ; i++){ printf("\ni = %d",i); printf(" vet[%d] = %.1f",i, vet[i]); printf(" *(f + %d) = %.1f",i, *(f+i)); printf(" &vet[%d] = %X",i, &vet[i]); printf(" (f + %d) = %X",i, f+i);} } Exerccio 6.12 Assumindo que pulo[] um vetor do tipo int, quais das seguintes expresses referenciam o valor do terceiro elemento da matriz? a) *(pulo+2) b) *(pulo + 4) c) pulo + 4 d) pulo + 2

Exerccio 6.13 Supor a declarao: int mat[4], *p, x; Quais expresses so vlidas? Justifique: a) p=mat+1; b) p=mat++; c) p=++mat; d) x=(*mat)++;

Exerccio 6.14 O que fazem os seguintes programas? #include <conio.h> #include <stdio.h> 108

void main(){ int vet[] = {4,9,13}; int i; for(i=0;i<3;i++){ printf("%d ",*(vet+i));} } #include <conio.h> #include <stdio.h> void main(){ int vet[] = {4,9,13}; int i; for(i=0;i<3;i++){ printf("%X ",vet+i);} } #include <conio.h> #include <stdio.h> void main(){ int vet[] = {4,9,13}; int i; for(i=0;i<3;i++){ printf("%X ",vet+i);} } Exerccio 6.15 O que faz o seguinte programa quando executado? #include <conio.h> #include <stdio.h> void main() { int vet[] = {4,9,12}; int i,*ptr; ptr = vet; for(i = 0 ; i < 3 ; i++) { printf("%d ",*ptr++);} } #include <conio.h> #include <stdio.h> void main(){ int vet[] = {4,9,12}; int i,*ptr; ptr = vet; for(i = 0 ; i < 3 ; i++){ 109

printf("%d ",(*ptr)++);} } Exerccio 6.16 Verifique o programa abaixo. Encontre o seu erro e corrija-o para que escreva o nmero 10 na tela. #include <stdio.h> int main() { int x, *p, **q; p = &x; q = &p; x = 10; printf("\n%d\n", &q); return(0); } Exerccio 6.17 Um ponteiro pode ser usado para dizer a uma funo onde ela deve depositar o resultado de seus clculos. Escreva uma funo hm que converta minutos em horas-e-minutos. A funo recebe um inteiro mnts e os endereos de duas variveis inteiras, digamos h e m, e atribui valores a essas variveis de modo que m seja menor que 60 e que 60*h + m seja igual a mnts. Escreva tambm uma funo main que use a funo hm. Exerccio 6.18 Escreva uma funo mm que receba um vetor inteiro v[0..n-1] e os endereos de duas variveis inteiras, digamos min e max, e deposite nessas variveis o valor de um elemento mnimo e o valor de um elemento mximo do vetor. Escreva tambm uma funo main que use a funo mm.

110

7 Estruturas de dados
Apresentam-se a seguir os conceitos de filas, pilhas e listas como estruturas de armazenamento de dados. Estas estruturas so criadas a partir de tipos elementares, vetores e estruturas. 7.1 Filas Uma FILA uma coleo ordenada de elementos na qual estes podem ser retirados de uma das extremidades da fila conhecida como incio ou frente da fila. Novos elementos podem ser inseridos na outra extremidade, ou seja, fim da fila. Filas: First In First Out (FIFO). Um exemplo de aplicao chamado de buffer como em uma comunicao assncrona entre dois equipamentos, especialmente quando um deles mais lento que o outro. Exemplo: computador-impressora. Operaes elementares Insere (fila, elemento) Insere novo elemento no fim da fila. Ex.: Insere(fila,'D'); elemento = Remove (fila) Remove elemento da frente da fila. Ex.: elemento_frente = Remove (fila); Um elemento s pode ser retirado da fila, se ela no estiver vazia, evidentemente. Assim como, s se pode inserir um elemento em uma fila que no esteja cheia. Operaes auxiliares FilaVazia (fila) Retorna V (1) se a fila estiver vazia e F (0) caso contrrio. Ex.: if (FilaVazia(fila)) printf("Fila vazia");

111

FilaCheia (fila) Retorna V (1) se a fila estiver cheia, e F (0) caso contrrio. Ex.: if (FilaCheia(fila)) printf("Fila Cheia"); InicializaFila (fila) Cria fila vazia. Ex.: InicializaFila(fila); Declarao do tipo de dados fila Usar um vetor para guardar os elementos da fila e as duas variveis frente e final para guardar as posies (ndices), dentro do vetor, do primeiro e do ltimo elemento da fila, respectivamente. A declarao do tipo de dados fila cujos elementos so valores inteiros aparece no exemplo a seguir (ex. 7.1) Exemplo 7.1 - Definindo uma estrutura de fila. ... #define MAXFILA 20 typedef int TipoDado; typedef struct{ TipoDado dados[MAXFILA]; int frente, final; } Fila; ... Uma fila vazia definida como tendo o fim "antes" da frente, ou seja, final < frente. Inicialmente a fila vazia deve ter: frente = 0 e final = -1. Implementao das operaes: SOLUO 1 void InicializaFila (Fila *f){ f->frente = 0; /* valores iniciais */ f->final = -1; } int FilaVazia (Fila *f){ /* a fila est vazia quando final < frente */ } int FilaCheia (Fila *f){ /* A fila est cheia quando final == MAXFILA - 1 */ } void Insere (Fila *f, TipoDado dado){ /* se fila cheia, no faz nada (ou erro) 112

se fila no estiver cheia, incremente o valor do final coloque dado na posio final dos dados da fila */ } TipoDado Remove (Fila *f){ /* se fila vazia, no faz nada (ou erro) guarda elemento da posio frente da fila soma 1 frente da fila retorne elemento guardado */ } Exerccio 7.1 Implemente um programa em C as operaes sobre fila conforme o modelo proposto anteriormente. Considere MAXFILA = 5 e as seguintes seqncias de operaes sobre uma fila f: InicializaFila(f); Insere(f,1); Insere(f,2); Insere(f,3); x = Remove(f); x = Remove(f); Insere(f,4); Insere(f,5); x = Remove(f); x = Remove(f); x = Remove(f); No final destas operaes, f->final == 4 e f->frente == 5. Isto significa que a fila est vazia e ao mesmo tempo est cheia! Problema... Implementao das operaes: SOLUO 2 Alterar a operao Remove de forma a deslocar todos os elementos para a "esquerda" (posio zero do vetor) cada vez que o elemento da frente for retirado (o elemento da frente estar sempre na posio zero). Exerccio 7.2 Altere a operao remove para implementar esta soluo.

Esta soluo, apesar de correta muito ineficiente. Imagine deslocar todos os elementos de uma fila com milhares de elementos para se retirar apenas quele que est frente! Implementao das operaes: SOLUO 3 - Vetores circulares Ver o vetor contendo os elementos da fila como sendo circular ao invs de linear. Problema - determinar quando a fila est vazia. Soluo - frente o ndice do vetor que precede o ndice do primeiro elemento. 113

Se i ndice de um vetor circular: Prox(i) = 0, se i == MAXFILA-1 i+1, caso contrrio. A fila estar vazia quando frente == final. A fila est cheia quando, fim vier logo antes de frente no vetor circular, isto , Prox(final) == frente. Exerccio 7.3 Implemente em C as operaes sobre filas considerando o vetor de dados como sendo circular.

7.1.1 Filas com prioridades Uma fila com prioridades uma estrutura de dados na qual a ordem intrnseca dos elementos determina os resultados das suas operaes bsicas, em particular, a operao Remove. Tipos 1) Fila com prioridade ascendente: uma coleo de elementos na qual novos elementos podem ser inseridos normalmente (como em filas sem prioridade) e da qual somente o MENOR elemento pode ser removido. 2) Fila com prioridade descendente: uma coleo de elementos na qual novos elementos podem ser inseridos normalmente (como em filas sem prioridade) e da qual somente o MAIOR elemento pode ser removido. 3) Elementos com mesmo valor (ou mesma prioridade) so retirados na ordem em que foram inseridos, seguindo a regra para filas normais ou FIFO. Aplicaes: Transmisso assncrona com prioridades (cancelamento de job de impresso, ...). Normalmente, os elementos de uma fila com prioridades so compostos de dois campos: os dados propriamente ditos + as prioridades dos dados.

dado prioridade ndice

A 1 0

C 7 1

D 4 2

F 3 3

H 2 4

K 5 5

Figura 7.1 Fila com prioridade descendente. Se a fila anterior (fig 7.1) for uma fila com prioridade descendente, o primeiro 114

elemento a sair ser o C e no o A que est na frente da fila, pois aquele (o C) tem prioridade maior (7). Uma pilha pode ser vista como sendo uma fila com prioridades descendentes cujos elementos esto ordenados pelo instante no tempo representando a ordem de insero. Todas as operaes em filas com prioridades so idnticas s operaes em filas normais, exceto a operao Remove, na qual o elemento que tiver maior ou menor prioridade deve ser retirado, estando ele ou no na frente da fila. int RemovePriorDesc(Fila *f){ /* busca o maior elemento na fila guardando-o em varivel auxiliar */ /* desloca o fim ou comeo da fila para preencher lugar do maior elemento*/ /* retorna o maior elemento armazenado na varivel auxiliar */ } Exerccio 7.4 Exerccio 7.5 Altere/Implemente a operao RemovePriorDesc acima em C, de forma a remover o maior elemento da uma fila de inteiros. Elabore um programa que implemente uma FILA controlada por um array de ponteiros para char *, char *ptr[DIM]. A fila deve armazenar datas de reunies que vo sendo alocadas por ordem de entrada e vo sendo retiradas de acordo com o princpio F.I.F.O.

7.2 Pilhas O problema do abre/fecha parnteses. Este problema consiste em verificar se uma expresso matemtica est corretamente formada em termos de abre/fecha parnteses. Com este exemplo (ex. 7.2) pretende-se mostrar a aplicabilidade de pilhas como estruturas de armazenamento de dados. Exemplo 7.2 - Expresses matemticas diversas. 7-((X*((X+Y)/(J-3))+Y)/(4-2.5)) ((A+B) ) A + B ( - C (A + B)) - (C + D Soluo: O nmero de ) deve ser igual ao nmero de (. Cada ")" deve ser precedido por um "(". Para tanto, pode-se utilizar um contador inicialmente igual a zero que, ao percorrer a expresso da esquerda para a direita, incrementado quando se encontra um "(" e decrementado quando se encontra um ")". O contador no final da expresso deve ser igual a zero. 115

Em nenhum momento o contador deve ser menor que zero. Exerccio 7.6 Implemente um programa C que leia uma expresso com parnteses e verifique se ela est corretamente formada em termos de abre/fecha parnteses usando o mtodo acima.

E em caso de existncia tambm de chaves e de colchetes? E a ordem chavescolchetes-parnteses seja importante? Soluo complicada... Melhor soluo - a estrutura de dados pilha Uma pilha uma coleo ordenada de elementos na qual os elementos so inseridos e retirados de uma das extremidades somente, chamada topo da pilha. Tipicamente, todos os elementos da pilha so do mesmo tipo (por exemplo, char, int, float ou at struct). Vetores permitem com que elementos sejam inseridos e lidos em qualquer posio. Mas em pilhas, a insero/remoo de elementos somente pode acontecer no topo. O ltimo elemento inserido em uma pilha o primeiro a ser retirado e por esta razo, uma pilha uma estrutura "LIFO" (Last In First Out). Como o problema do abre e fecha: parnteses, chaves e colchetes pode ser resolvido com uma pilha de caracteres? Outras aplicaes de pilhas: desfazer (undo); voltar; endereo de retorno de funes pelo registrador; etc. Operaes elementares Push (pilha, elemento) Insere novo elemento no topo da pilha. Ex.: Push(pilha,'A'); elemento = Pop (pilha) Remove elemento do topo da pilha. Ex.: elemento_topo = Pop (pilha); Operaes auxiliares PilhaVazia (pilha) Retorna V (1) se a pilha estiver vazia, e F (0) caso contrrio. Ex.: if (PilhaVazia(pilha)) printf("Pilha vazia"); PilhaCheia (pilha) Retorna V (1) se a pilha estiver cheia, e F (0) caso contrrio. Ex.: if (PilhaCheia(pilha)) printf("Pilha Cheia");

116

InicializaPilha (pilha) Cria pilha vazia. Ex.: InicializaPilha(pilha); Declarao do tipo de dados pilha Coleo ordenada em C, vetores. Uma pilha em C pode ser definida como sendo uma estrutura contendo dois campos: 1) Um vetor contendo os dados ("dados"); e 2) Um inteiro indicando a posio do topo no vetor ("topo"). Exemplo 7.3 - Declarao do tipo de dados pilha cujos elementos so valores inteiros. ... #define MAXPILHA 200

typedef int TipoDado; typedef struct{ TipoDado dados[MAXPILHA]; int topo; } Pilha; ... Implementao das funes void InicializaPilha (Pilha *p){ /* inicializa topo da pilha end. de p (valor = -1) */ } int PilhaVazia (Pilha *p){ /* retorna 1 (V) se topo p -1. 0 (F) c.c. */ } int PilhaCheia (Pilha *p){ /* retorna 1 (V) se topo p == MAXPILHA-1. 0 (F) c.c. */ } void Push (Pilha *p, TipoDado x){ /* se pilha p cheia, erro */ /* seno, incremente o valor do topo de p */ /* coloque x no vetor dados na posio topo de p */ } TipoDado Pop (Pilha *p){ /* se pilha p vazia, erro */ /* c. c., armazene elemento do topo da pilha p */ /* decremente o topo de p */ /* retorne elemento armazenado */ 117

} TipoDado elemTopo(Pilha *p){ /* se pilha p vazia, erro */ /* seno, retorne elemento armazenado */ } Exerccio 7.7 Implemente em C as operaes sobre pilhas acima. Crie inicialmente um tipo pilha no qual os elementos so valores inteiros. Crie um programa principal que leia 10 valores colocando-os um a um na pilha que, em seguida deve ser esvaziada. Altere o programa do exerccio anterior (ex. 7.7) para que implemente uma pilha na qual os elementos so do tipo char.

Exerccio 7.8

Notao completamente Parentizada: acrescentam-se sempre parnteses a cada par de operandos e seu operador. Exemplo: tradicional: parentizada: Notao Polonesa: A * B - C / D ((A*B)-(C/D))

os operadores aparecem imediatamente antes dos operandos. Esta notao especifica quais operadores e em que ordem eles devem ser calculados. Por esse motivo dispensa o uso de parnteses, sem ambigidades. A * B - C / D - * A B / C D como a polonesa, exceto que os operandos aparecem aps os operadores.

Exemplo: tradicional: polonesa:

Notao Polonesa Reversa (ou ps-fixa):

Exemplo: tradicional: A * B - C / D polonesa reversa: A B * C D / Exemplo 7.4 - Exemplo de uso do mtodo RPN para clculo de: (3+5) (7+6) = x. Mtodo algbrico: some 3 + 5 = 8. Escreva a resposta ou guarda na memria. Some 7 + 6 = 13. Agora digite 8 da primeira resposta e a seguir divida-o digitando a segunda resposta para obter x = 0,62. Mtodo RPN: digite 3 e depois a tecla ENTER. Digite 5 e depois a tecla +. Digite 7 e depois ENTER. Digite 6 e depois a tecla +. Note que a resposta para a segunda soma exibida. Agora aqui est a parte mgica. Pressione a tecla de dividir e a calculadora exibe a resposta 0,62. 13 toques, no contando o esforo de escrever ou memorizar a primeira resposta enquanto calcula a segunda resposta. 118

Algbrico:

RPN:

9 toques e no h necessidade de escrever nada.

Funcionamento das calculadoras RPN O RPN mantm um registro dos clculos colocando-os em uma pilha (2). No exemplo acima, quando voc pressionar a tecla ENTER pela segunda vez, a resposta da primeira soma foi empurrada (3) para cima na pilha, aguardando a prxima ao. Aps digitar uma segunda soma, pressione a tecla dividir para chamar a primeira soma, dividi-la pela segunda e recuperar (4) a resposta da pilha. Em outras palavras, o RPN executou um clculo em uma ordem lgica. Aprender como usar uma calculadora RPN geralmente leva apenas alguns minutos e pode economizar muito tempo e esforo a longo prazo. Aqui est um exemplo prtico que usa RPN. 1) Modo algbrico: este o nome da notao matemtica usada em todas as calculadoras que no usam RPN quando voc digitar uma equao matemtica como esta 1+3*(3+(2-5)/3). No modo algbrico, parntesis e a ordem dos operadores so extremamente importantes. 2) Pilha: uma pilha, tambm chamada LIFO a base do sistema RPN, assim como a memria que permite ao usurio digitar nmeros. 3) Empurrar/empurrando: esta a ao de adicionar o nmero na base de uma pilha empurrando todos os outros nmeros para cima. 4) Limpar/limpando: esta a ao de remover o ltimo nmero que foi empurrado em uma pilha.
Fonte: http://h30091.www3.hp.com/produtos/calculadoras/rpn.html

Algoritmo para transformao de notao infixa para ps-fixa com parnteses Passos para criao de um programa para transformao de notao infixa para ps-fixa ou Notao Polonesa Reversa. Passo 1: Entrar com uma expresso devidamente com parnteses; Passo 2: Percorrer a expresso da esquerda para a direita, e para cada smbolo encontrado tomar a seguinte deciso: Se for parntese de abertura, ignor-lo; Se for operando, copi-lo para a expresso ps-fixa (sada); Se for operador, coloc-lo na pilha; Se for parntese de fechamento, desempilhar o operador presente no topo da pilha; Ao final do passo 2, a pilha deve estar vazia, caso contrrio algo de errado ocorreu na converso da notao infixa para ps-fixa. Veja exemplo (ex. 7.4) a seguir. Exemplo 7.4 - Converso de notao infixa completamente parentizada para ps-fixa. Para o perfeito funcionamento deste programa necessrio a construo 119

de outras funes auxiliares. ... InicializaPilha(p); i = pos = 0; while (infixa[i] != '\0'){ if (infixa[i] >= A && infixa[i] <= Z){ posfixa[pos++] = infixa[i]; } else{ switch (infixa[i]){ case * : case / : case + : case - : Push(p, infixa[i]); break; case ) : posfixa[pos++] = Pop(p); break; } } i++; } posfixa[pos] = \0; ... Exerccio 7.9 Implemente em C as operaes sobre pilhas da Notao Polonesa Reversa para clculo de uma expresso neste formato. Faa os teste de evoluo da pilha.

Algoritmo genrico para converso de notao infixa para ps-fixa Para que a soluo apresentada anteriormente funcione corretamente necessrio inserir manualmente todos os parnteses com o objetivo de determinar a precedncia de operaes. O programa (ex. 7.5) a seguir pretende eliminar a esta necessidade estabelecendo prioridades para os operadores. Exemplo 7.5 - Usando uma escala de prioridade para os operadores de uma notao infixa. Para o perfeito funcionamento deste programa necessrio a construo de outras funes auxiliares. ... switch (infixa[i]){ case ( : prioridade = 1; break; case - : case + : prioridade = 2; break;

120

case * : case / : prioridade = 3; break; } ... Aps determinar a prioridade dos operadores sugere-se a seqncia de passos a seguir, o programa apresentado logo na seqncia (ex. 7.6). Passo 1: Iniciar uma pilha vazia; Realizar uma varredura na expresso infixa, copiando todos os operandos diretamente para expresso de sada; Passo 2: Ao encontrar um operador: Enquanto a pilha no estiver vazia e houver um operador no seu topo de prioridade maior ou igual ao encontrado na expresso infixa, desempilhe o operador e copie-o na a expresso de sada; Empilhe o operador encontrado na expresso; Passo 3: Ao encontrar parntese de abertura, empilhe-o; Passo 4: Ao encontrar um parntese de fechamento remova um smbolo da pilha e copie-o na sada. Repita esse passo at que seja desempilhado o parntese de abertura; Passo 5: Ao final da varredura, esvazie a pilha, movendo dessa forma os smbolos desempilhados para a sada. Pronto! Desta forma possvel obter na sada a notao ps-fixa, partindo da notao infixa de entrada. Exemplo 7.6 - Converso de notao infixa em ps-fixa usando a escala de prioridade definida anteriormente (ex. 7.5). Para o perfeito funcionamento deste programa necessrio a construo de outras funes auxiliares. ... InicializaPilha(p); i = pos = 0; while (infixa[i] != '\0'){ if (infixa[i] >= A && infixa[i] <= Z){ posfixa[pos++] = infixa[i]; } else{ switch (infixa[i]){ case * : case / : case + : case - : pr = prioridade(infixa[i]); while (!PilhaVazia(p) && prioridade(elemTopo(p))>=pr){ 121

posfixa[pos++] = Pop(p); } Push(p, infixa[i]); break; case ( : Push(p, infixa[i]); break; case ) : x = Pop(p); while (x != (){ posfixa[pos++] = x; x = Pop(p); } break; } } i++; } while (!PilhaVazia(p)){ posfixa[pos++] = Pop(p); } posfixa[pos] = \0; ... Avaliando as expresses em notao ps-fixa As transformaes realizadas at aqui tm o objetivo de facilitar a avaliao (ex. 7.7) da expresso, ou seja, resolv-la levando em considerao os valores numricos de cada uma das variveis presentes na expresso infixa e convertidas para a notao psfixa. Passo 1: Iniciar uma pilha vazia; Passo 2: Varrer a expresso, e para cada smbolo encontrado: Se for operando, empilha-se seu valor; Se for operador, desempilhar os dois ltimos valores. Em seguida, efetuar a operao com eles. O resultado ser empilhado novamente. Passo 3: O resultado da avaliao da expresso estar no topo da pilha; Exemplo 7.7 - Avaliao da expresso em notao ps-fixa. Para o perfeito funcionamento deste programa necessrio a construo de outras funes auxiliares. ... InicializaPilha(p); i = pos = 0; while (posfixa[i] != '\0'){ 122

if (posfixa[i] >= A && posfixa[i] <= Z){ printf(Entre com o valor de %c = , posfixa[i]); scanf(%d,&val); Push(p, val); } else{ switch (infixa[i]){ case * : case / : case + : case - : y = Pop(p); z = Pop(p); switch (infixa[i]){ case * : Push(p, z * y); break; case / : Push(p, z / y); break; case + : Push(p, z + y); break; case - : Push(p, z - y); break; } break; } i++; } resultado = Pop(p); ... Exemplo 7.8 A funo fatorial recurssiva.

... int fatorial(unsigned int n){ int res = 1; if (n > 0) res = n * fatorial(n-1); return(res); } fatorial(5) => (5 != 0) return(5 * fatorial(4)) => (4 != 0) return(4 * fatorial(3)) => (3 != 0) return(3 * fatorial(2)) => (2 != 0) return(2 * fatorial(1)) => (1 != 0) 123

return(1 * fatorial(0)) => (0 == 0) <= return(1) <= return(1 * 1) (1) <= return(2 * 1) (2) <= return(3 * 2) (6) <= return(4 * 6) (24) <= return(5 * 24) (120) 120 7.2.1 Exerccios propostos Exerccio 7.10 Calcule manualmente o valor das expresses em notao ps-fixa a seguir. Assuma que os valores de A, B, C e D so respectivamente, 5, 6, 7, 8. AB*CD+ ABC+*D/ ABC+DAD/CB+-

Exerccio 7.11 Transforme as expresses a seguir de infixa em notao ps-fixa. A +B*CD A/B-C+D ABC+D(A + D) / (C B) + E / F

Exerccio 7.12 Usando o algoritmo genrico de converso da notao infixa para psfixa, passe a expresso aritmtica a seguir para a converso ps-fixa. Mostre a evoluo da pilha para cada caractere da expresso. Ao final permita o clculo do valor da expresso para valores fornecidos pelo usurio. Sendo: A * B (C / D * E F / G) + H + I. Exerccio 7.13 Desenvolva um programa que inverta o contedo de uma pilha, ou seja, o elemento do topo passe a ser a base, o elemento antes do topo ser o segundo aps a base e assim por diante. Diga: utilize outra pilha. Exerccio 7.14 Crie um programa que faa a converso de nmeros decimais para binrios. 7.3 Listas lineares ligadas Vetores estavam sendo utilizados para o armazenamento de dados nas sees anteriores. Eles facilitam o entendimento e compreenso de filas e pilhas, porm apresentam alguns inconvenientes, tais como sub-dimensionamento ou super-dimensionamento do tamanho do vetor. Caso tenham-se trs vetores v1, v2 e v3 com capacidade de 50, 200 e 300 posies respectivamente e, durante a execuo do programa, tenha 124

sido necessrio armazenar 60 posies em v1, 140 em v2 e 240 em v3. Fica evidente que ocorrer um estouro em v1, enquanto v2 e v3 ocupam reas de memria, que no esto sendo utilizadas. Para evitar tais situaes que a alocao dinmica de memria apresentada a seguir. Uma lista ligada ou encadeada uma estrutura de dados linear e dinmica. Ela composta por clulas que apontam para o prximo elemento da lista. Para se ter uma lista ligada basta guardar seu primeiro e seu ltimo elemento, sendo que este ltimo aponta para uma clula nula. O esquema a seguir (fig. 7.2) representa uma lista ligada com 4 elementos: Clula 1 Clula 2 Clula 3 Clula 4 Nulo

Figura 7.2 Lista ligada simples. Para manipular estas listas, ou seja, inserir ou remover dados necessrio ter-se sempre em ateno um ponteiro que aponte para o 1 elemento e outro que aponte para o fim. Isto porque ao inserir ou apagar dados que estejam no incio ou no fim da lista a operao rapidamente executada. Caso seja um n que se encontra no meio da lista haver a necessidade de uma procura at encontrar a posio desejada. Esta seo apresenta uma viso sobre a alocao de memria necessria para construo de listas, alm de algumas funes imprescindveis para o entendimento das mesmas. Muitas destas funes esto incompletas ou a implementar, o que deve despertar o interesse no desenvolvimento das mesmas por parte do programador. Vantagens A insero de um elemento no meio da lista no implica mover todos os elementos. Desvantagens O acesso seqencial, para eliminao ou insero de um elemento no meio da lista. Espao alocado para uma estrutura struct aluno{ char *nome; short idade; char matricula[8]; }; struct aluno al; /* ponteiro 2 bytes */ /* 2 bytes */ /* array 8 bytes */

al.nome = "John"; al.idade = 30; strcpy(al.matricula, "00/0001");

125

7.3.1 Funo sizeof() A funo sizeof(tipo) retorna o tamanho em bytes ocupado em memria pelo tipo de dado passado como parmetro. Ex.: sizeof(int) => 2 bytes sizeof(char) => 1 byte 7.3.2 Alocao dinmica de memria As funes calloc e malloc permitem alocar blocos de memria em tempo de execuo. #include <alloc.h> void * malloc(); retorna um ponteiro void para n bytes de memria no iniciados. Se no h memria disponvel malloc retorna NULL. nmero de bytes alocados size_t n #include <alloc.h> void * calloc(size_t n, size_t size); calloc retorna um ponteiro para um array com n elementos de tamanho size cada um ou NULL se no houver memria disponvel. Os elementos so iniciados em zero. O ponteiro retornado por malloc e calloc deve ser convertido para o tipo de ponteiro que invoca a funo. int *pi = (int *) malloc (sizeof(int)); /* aloca espao para um inteiro */ int *ai = (int *) calloc (n, sizeof(int)); /* aloca espao para um array de n inteiros */ Toda memria no mais utilizada deve ser liberada por meio da funo free(). free(ai); /* libera todo o array */ free(pi); /* libera o inteiro alocado */ Estruturas auto-referenciadas possvel definir dentro de uma estrutura um ponteiro para a prpria estrutura: struct Qualquer{ tipo_dado_1 dado_1; 126

... struct Qualquer *proximo; } proximo aponta para uma estrutura do mesmo tipo. Lista de inteiros Um exemplo de lista encadeada a lista de inteiros, onde raiz um ponteiro para o primeiro n da lista. Aps definio da struct alocada memria para struct No e seu ponteiro guardado em raiz. Um valor inteiro atribudo raiz>dado e finalmente raiz->proximo aponta para NULL. struct No{ int dado; struct No *proximo; } *raiz; int main(){ raiz = (struct No *)malloc(sizeof(struct No)); raiz->dado = 15; raiz->proximo = NULL; ... return(0); } Inserindo um segundo elemento na lista A seguir apresenta-se uma forma de inserir um valor x a uma lista encadeada de inteiros, sendo que este ser inserido no fim da lista. O endereo (ponteiro) do novo n da lista atribudo para pnode e em seguida pnode->dado recebe o valor i. Em seguida a manipulao de ponteiro realizada para garantir a integridade da lista, assim a raiz que em um momento inicial apontava para o primeiro elemento agora ir apontar para pnode. Enquanto pnode->proximo assume NULL. struct No *insere_int (int i){ struct No *pNo; pNo = (struct No *)malloc(sizeof(struct No)); pNo->dado = i; pNo->proximo = NULL ; raiz->proximo = pNo; return(pNo); } Algo no est muito certo com esta funo, voc no acha? Ser que ela 127 /*terminador de lista*/

funcionar para novas inseres? Algo precisa ser feito para melhor-la! Percorrendo a lista Percorre-se uma lista encadeada por meio de um ponteiro, veja funo exibe() a seguir. Tendo-se o incio da lista em raiz fica relativamente simples percorrer toda a lista utilizando-se de um ponteiro mvel e de uma estrutura de repetio. De forma, o ponteiro mvel pNo recebe o endereo do primeiro elemento da lista raiz e ir receber sempre o endereo seguinte na lista, aps apresentao do dado propriamente dito, por meio de pNo->proximo. void exibe(){ struct No *pNo; pNo = raiz; while (pNo != NULL){ printf(%d, pNo->dado); pNo = pNo->proximo; } Insere Nodo antes do incio da lista (novo incio) Mudar o n raiz e desta forma inserir um novo dado antes dele na da lista declarar um novo incio para a lista. Para realizar esta tarefa basta alocar espao para uma nova estrutura e manipular corretamente os ponteiros da raiz e do novo espao alocado. pNo->proximo recebe o endereo do primeiro elemento da lista raiz e raiz ir receber o endereo de pNo. Desta maneira, pNo torna-se o novo n raiz. struct No *insere_int (int i){ struct No *pNo; pNo = (struct No *) malloc(sizeof(struct No)); if (pNo){ pNo->dado = i; pNo->proximo = raiz; raiz = pNo; } return(pNo); } Insere Nodo entre nodos da lista Esta situao de insero bastante comum em lista encadeada ordenadas. Para realizar esta tarefa necessrio alocar espao para uma nova estrutura e manipular corretamente os ponteiros da pos e do novo espao alocado. A funo ir receber o endereo a partir do qual o novo n dever ser inserido. Desta maneira, pNo>proximo apontar para o endereo contido em pos->proximo e pos->proximo 128

receber o endereo de pNo, recentemente alocado. Ser que esta funo permite tambm a insero de um novo n ao final da lista? Teste! struct No *insere_int (int i; struct No *pos){ struct No *pNo; pNo = (struct No *)malloc(sizeof(struct No)); if (pNo){ pNo->dado = i; pNo->proximo = pos->proximo; pos->proximo = pNo; } return(pNo); } Imprime a lista Esta funo recebe o incio da lista em pNo e lista todos os dados da lista. Compare-a com a funo exibe(), apresentada anteriormente. void imprime(struct No *pNo){ printf("\nLista = "); while (pNo){ printf(" %d ", pNo->dado); pNo = pNo->proximo; } } Busca em uma lista encadeada Veja como fcil verificar se um inteiro x pertence a uma lista encadeada, ou seja, se ele igual ao contedo de algum n ou clula da lista. A funo busca(x, ini) recebe um inteiro x e uma lista encadeada de inteiros. O endereo da lista ini e a funo devolve o endereo de uma clula que contm x. Se tal clula no existe, a funo devolve NULL. struct No *busca(int x, struct No *ini){ struct No *pNo; pNo = ini; while (pNo != NULL && pNo->dado != x) pNo = pNo->proximo; return(pNo); } Remoo em uma lista 129

Para remover uma certa clula da lista, a idia mais bvia seria apontar para a clula que se quer remover. Pode-se perceber que essa idia no muito boa. melhor apontar para a clula anterior que se quer remover. Suponha que p o endereo de uma clula da lista e que se deseja remover a clula apontada por p->proximo. Note que a funo de remoo no precisa saber onde a lista comea. Esta funo recebe o endereo p de uma clula de uma lista encadeada. A funo remove da lista a clula p->proximo. A funo supe que p != NULL e p->proximo != NULL. void remove(struct No *p){ struct No *morta; morta = p->prox; p->prox = morta->prox; free(morta); } Esvaziando a lista Remover toda a lista utilizando-se uma nica chamada de funo. void esvazia_lista(){ No *tmp; while (raiz != NULL){ tmp = raiz; raiz = raiz->proximo; free(tmp); } } Busca e remoo Suponha-se que ini o endereo de uma lista encadeada. O problema: Dado um inteiro y, remover da lista a primeira clula que contm y, se tal clula no existir, no faa nada. void buscaEremove (int y, struct No *ini){ struct No *p, *q; q = ini; while (q != NULL && q->dado != y){ p = q; q = q->proximo; } if (q != NULL){ p->proximo = q->proximo; 130

free(q);} } No incio de cada iterao imediatamente antes da comparao de q com NULL, tem-se q == p->proximo, ou seja, q est sempre um passo frente de p. Busca e insero Mais uma vez, suponha que se tenha uma lista encadeada ini. O problema: Inserir na lista uma nova clula com contedo x imediatamente antes da primeira clula que tiver contedo y, se tal clula no existir inserir x no fim da lista. void buscaEinsere(int x, int y, No *ini){ struct No *p, *q, *pNo; pNo = (struct No *) malloc (sizeof(struct No)); pNo->dado = x; q = ini; while (q != NULL && q->dado != y){ p = q; q = q->proximo; } pNo->proximo = q; p->proximo = pNo; } As funes, apresentadas anteriormente, so a base para criao de novas funes para manipulao de listas de armazenamento de dados. 7.3.3 Lista ordenada Os ns de uma lista podem aparecer em qualquer seqncia na lista. Porm em vrios casos prefervel que estes estejam. Um polinmio, expresso em uma lista encadeada, um exemplo de uma lista que deve estar ordenada para o perfeito entendimento do polinmio. Vejam a seguir quais as funes sero necessrias para a criao, a insero, a apresentao e, como no poderia ficar de fora, a resoluo de polinmios. Representao de Polinmios em uma lista Uma fila ordenada apresenta uma maneira adequada para armazenar e posteriormente permitir o acesso a cada elemento do polinmio na forma: P(X) = Cn Xn + Cn-1 Xn-1 + ... + C3 X3 + C2 X2 + C1 X1 + C0 possvel representar a estrutura anterior por um conjunto de pares associados a 131

X, que correspondem ao coeficiente e a potncia. Por exemplo, P(X) = 5X6 - 2X4 + 7X3 - 3X2 - 8 seria representado pelos pares {(5,6), (-2,4), (7,3), (-3,2), (-8,0)}. Para cada par o primeiro elemento representa o coeficiente de X, e o segundo elemento representa o valor da potncia de X. A potncia de X poder ser utilizada como chave de ordenao de uma lista ordenada que representar o polinmio. Ao usar a potncia de X para ordenar a lista, o exemplo anterior ficaria assim: {(-8,0), (-3,2), (7,3), (-2,4), (5,6)} Definio de ns do polinmio Sobre as consideraes anteriores, pode-se definir a seguinte representao para cada um dos ns da lista para armazenamento de polinmios. struct Polin{ float coeficiente; int expoente; struct Polin *prox; }; typedef struct polin NO; Criando um polinmio nulo A criao de um elemento 0X0 na lista facilitar a insero, posteriormente, de novos ns na lista. void criaLista (NO **plista){ NO *p; p = getNo(); p->coeficiente = 0; p->expoente = 0; p->prox = NULL; *plista = p; } Observa-se uma nova funo getNo()sendo utilizada. Definio a seguir. NODO *getNo(void){ NO *p; p = (NO *)malloc (sizeof(NO)); return(p); } Inserindo um termo Uma funo chamada insTermo (NO *p, float c, int e) ser responsvel pela insero de novos termos do polinmio na lista ordenada. Observa-se que durante a incluso de um novo termo realizada uma pesquisa para identificar se o 132

termo j est presente no polinmio. Caso afirmativo, o coeficiente ser acrescido ao j existente, evitando que seja gerada uma nova posio na lista com a repetio do expoente. Caso o expoente no esteja presente, um novo n ser criado na lista mantendo a ordenao da mesma. void insTermo (NO *p, float c, int e){ NO *n; if (e == p->expoente) p->coeficiente = p->coeficiente + c; else{ while ((p->prox!=NULL)&&(e>p->prox->expoente)) { p = p->prox; } if ((p->prox!=NULL)&&(e==p->prox->expoente)) p->prox->coeficiente = p->prox->coeficiente+c; else{ n = getNo(); n->coeficiente = c; n->expoente = e; n->prox = p->prox; p->prox = n; } } } Simular a criao do polinmio P(X) = 7X2 - 3X - 8 usando as funes descritas anteriormente, como segue: ... NO *p; p = NULL; criaLista(&p); insTermo(p, insTermo(p, insTermo(p, insTermo(p, 7, 2); -3, 1); -8, 0); -3, 2);

mostra(p, P); printf("\nP ( 2 ) = %.2f ", calPolin(p,2)); printf("\nDigite uma tecla para finalizar! "); getch(); ... A simulao prev ainda a incluso de -3X2, o que resulta em P(X) = 4X2 3X - 8. Exibindo o contedo do polinmio 133

Criar uma funo de exibio torna-se uma tarefa simples uma vez que a lista apresenta-se ordenada. Considera-se, x^y com sendo xy. void mostra (NO *p, char ch){ float coef; printf("%c ( X ) = ", ch); while (p != NULL){ if (p->coeficiente != 0){ if (p->coeficiente < 0) printf(" - "); else printf(" + "); coef = fabs(p->coeficiente); printf("%.2f", coef); if (p->coeficiente < 0) printf("*X^%i", p->expoente); } p = p->prox; } } Resolvendo o polinmio A funo calPolin() calcula o valor do polinmio armazenado na lista ordenada. Veja a seguir: float calPolin (NO *p, float x){ float s = 0.0; while (p != NULL){ s = s + p->coeficiente * pow(x, p->expoente); p = p->prox; } return(s); } 7.3.4 Exerccios propostos Exerccio 7.15 - Elabore um programa que implemente uma FILA com uma estrutura de lista ligada simples, no ordenada, com uma funo guardar(), para armazenar elementos cabea da lista e retirar(), para retirar elementos na cauda da lista. Os elementos da fila/lista so definidos do seguinte modo: typedef struct elememtos{ char nome[30]; char telef[10]; struct elementos *seg; /* ponteiro para o seguinte */ 134

} ELEMENTOS; ELEMENTOS *fila; /* ponteiro para inicio da fila */

Exerccio 7.16 - Elabore um programa que implemente uma FILA CIRCULAR suportada por uma lista ligada simples, com um nmero finito de elementos, definidos pelo valor de uma constante, NL. A estrutura dos elementos da Fila/Lista. Dever ser definida do seguinte modo: typedef struct elementos{ char matric[30]; /* campo de dados */ struct elementos *seg; /* ponteiro para o seguinte */ } ELEMENTOS; O programa dever incluir funes para guardar() e retirar() matrculas de viaturas na Fila, de acordo com o princpio F.I.F.O. e ainda funes para listar as matrculas armazenadas e procurar uma matrcula qualquer na fila. Permiti-se o uso de trs variveis globais do tipo ponteiro para ELEMENTOS. ELEMENTOS *fila; /* ponteiro para inicio da fila */ ELEMENTOS *sai, *entra; /* ponteiro para as posies de sada e de entrada na FILA CIRCULAR */ Exerccio 7.17 - Altere o exerccio anterior (ex.: 7.16), criando uma FILA CIRCULAR controlada pelo array de ponteiros de dimenso fixo: char *ptr[DIM]. Onde DIM uma constante que define a dimenso do array. Exerccio 7.18 - Escreva uma funo que converta um vetor de caracteres (char) numa lista ligada simples cujos elementos contm os caracteres do vetor antes referido. A funo deve ter como argumento de entrada o ponteiro para a string e devolver um ponteiro para lista recm criada. Exerccio 7.19 - Escreva uma funo idntica anterior considerando que o vetor do tipo: typedef struct aluno{ unsigned long numero; char nome[50]; char morada[100]; char telefone[9]; char cod_postal[7]; } ALUNO; Exerccio 7.20 - Formule uma estrutura que permita guardar informao relativa a DVD, nomeadamente: titulo, atores (3), tipo de vdeo (ao, romance, drama, etc.), durao (minutos). a) Escreva uma funo que tendo como argumentos de entrada: o ponteiro para 135

uma lista simplesmente ligada e a informao relativa a um vdeo, efetue a insero de um n com a referida informao. b) Escreva uma funo que efetue a listagem, no vdeo, dos vdeos existentes na lista. c) Escreva uma funo que verifique a existncia de um vdeo na lista e devolva o ponteiro para o n onde se encontra o vdeo (passe a informao do nmero do vdeo em questo por argumentos de referncia). d) Escreva uma funo que aceitando como argumento a lista resultante em a), a inverta. Exerccio 7.21 - O restaurante Mac Donalds em Porto Alegre possui um sistema de atendimento que funciona mais ou menos assim: existem trs filas consecutivas pelas quais o cliente passa.

Nome do cliente: Joo

a) inserir na fila de pedido b) remover da fila de pedido c) remover da fila de pagamento d) remover da fila de encomenda digite sua opo (a, b, c, d): a

Fila Pedidos 1. Pedro 2. Lucas 3. Joo

Fila Pagamento 1. Maria 2. Abrao 3. Jonas

Fila Encomenda 1. Maria 2. Rui 3. Ana Cliente Atendido: Salomo

A primeira a fila na qual o cliente faz seu pedido; saindo desta fila ele entra em uma segunda fila, na qual faz o pagamento de seu pedido; saindo desta segunda fila ele entra em uma terceira fila, na qual lhe entregue a sua encomenda. Construa um programa em linguagem C que simule o funcionamento deste sistema. As seguintes funcionalidades so esperadas: insero de cliente na fila de pedido; remoo de cliente da fila de pedido; remoo de cliente da fila de pagamento; remoo de cliente da fila de pegar encomenda. Para facilitar a compreenso do funcionamento deste programa, sugere-se a interface anterior para o mesmo. Exerccio 7.22 - Critique a funo abaixo. Ao receber uma lista encadeada e um inteiro x, ela promete devolver o endereo de uma clula com contedo x. Se tal clula no existe, promete devolver NULL. celula *busca (int x, celula *ini){ 136

int achou; celula *p; achou = 0; p = ini; while (p != NULL && !achou){ if (p->conteudo == x) achou = 1; p = p->prox; } if (achou) return(p); else return(NULL); } Exerccio 7.23 - Escreva uma funo que receba uma lista encadeada e devolve o endereo de um n que esteja o mais prximo possvel do meio da lista. Aps determinar o provvel n central, exiba o contedo da lista e mostre uma mensagem ao chegar no n central encontrado anteriormente. Exerccio 7.24 - Critique a seguinte verso da funo remove: void remove(celula *p, celula *ini){ celula *morta; morta = p->prox; if (morta->prox == NULL) p->prox = NULL; else p->prox = morta->prox; free(morta); } Exerccio 7.25 - Escreva uma funo que copie um vetor para uma lista encadeada. Exerccio 7.26 - Escreva uma funo que copie uma lista encadeada para um vetor. Exerccio 7.27 - Escreva uma funo que faa uma cpia de uma lista dada. Exerccio 7.28 - Escreva uma funo que concatena duas listas encadeadas (isto , "amarra" a segunda no fim da primeira). Exerccio 7.29 - Escreva uma funo que conta o nmero de clulas de uma lista encadeada. Exerccio 7.30 - Escreva uma funo que insere na lista uma nova clula com contedo x entre a k-sima e a k+1-sima clulas.

137

Exerccio 7.31 - Escreva uma funo que verifica se duas listas dadas so iguais, ou melhor, se tem o mesmo contedo. Exerccio 7.32 - Escreva uma funo que libera() (funo free()) todos os ns de uma lista encadeada. Considere que cada n da lista foi originalmente alocado por malloc(). Exerccio 7.33 - Escreva uma funo que inverte a ordem das clulas de uma lista encadeada (o primeiro passa a ser o ltimo, o segundo passa a ser o penltimo etc.). Faa isso sem usar espao auxiliar: somente altere os ponteiros. Exerccio 7.34 - A partir de agora, tudo festa: voc pode inventar uma grande variedade de tipos de listas encadeadas. Por exemplo, voc pode fazer uma lista encadeada circular: a ltima clula aponta para a primeira e no para NULL. Para especificar uma lista circular basta fornecer um endereo (por exemplo, o endereo da ltima clula). Exerccio 7.35 - Outro tipo til a lista duplamente encadeada: cada clula contm o endereo da clula anterior e o da clula seguinte. Pense como seria isto? Exerccio 7.36 - Pense nas seguintes questes, apropriadas para qualquer tipo de lista encadeada. Em que condies a lista est vazia? Como remover a clula apontada por p? Idem para a clula seguinte apontada por p? Idem para a clula anterior apontada por p? Como inserir uma nova clula entre o elemento apontado por p e o seu antecessor? Idem entre p e seu sucessor? Exerccio 7.37 - Descreva, em linguagem C, a estrutura de uma das clulas de uma lista duplamente encadeada. Exerccio 7.38 - Escreva uma funo que remove de uma lista duplamente encadeada a clula apontada por p. (Que dados sua funo recebe? Que coisa devolve?) Exerccio 7.39 - Escreva uma funo que insira em uma lista duplamente encadeada, logo aps a clula apontada por p, uma nova clula com contedo y. (Que dados sua funo recebe? Que coisa devolve?) Exerccio 7.40 - Escreva uma funo para remover de uma lista encadeada todos os elementos que contm y.

138

Bibliografia
HOLZNER, Steven, GROUP, The Peter Norton Computing . Programando em C++: um guia prtico para programao profissional. Traduo de Sylvio Carlos Montenegro Branco. Rio de Janeiro: Campus, 1993. HUBBARD, John R. Teoria e problemas de programao em C++ / John R. Hubbard; Trad. Edson Furmankigwicz. 2. ed. Porto Alegre : Bookman, 2003. JAMSA, Kris. Programando em C++ - A bblia / Kris Jamsa e Lars Klander. Traduo: e reviso Tcnica: Jeremias Ren D. Pereira dos Santos So Paulo : Makron Books, 1999. KERNIGHAN, Brian W., RITCHIE, Dennis M. Ritchie. C a linguagem de programao: Padro ANSI. Traduo Daniel Viera. Rio de Janeiro: Campus, 1989. LOPES, Anita, GARCIA, Guto. Introduo programao. Rio de Janeiro: Campus, 2002. MANZANO, Jos Augusto N. G., OLIVEIRA, Jayr Figueiredo de. Estudo Dirigido de Algoritmos. So Paulo: rica, 1997. PEREIRA, Silvio do Lago. Estruturas de dados fundamentais: conceitos e aplicaes / Silvio do Lago Pereira. So Paulo : rica, 1996. SCHILDT, Herbert. C, completo e total. 3 ed; Traduo e reviso tcnica: Roberto Carlos Mayer. So Paulo: Pearson Makron Books, 1997. SENNE, Edson Luiz Frana. Primeiro curso de programao em C. 2 ed; Florianpolis: Visual Books, 2006.

139

Apndice A - Palavras reservadas em C e C++


asm catch continue double float if new public signed switch try virtual auto char default else for inline operator register sizeof template typedef void break class delete enum friend int private return static this union volatile case const do extern goto long protected short struct throw unsigned while

140

Anexo A Tabela de caracteres ASCII


DEC HEX 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 A 11 B 12 C 13 D 14 E 15 F 16 10 17 11 18 12 19 13 20 14 21 15 22 16 23 17 24 18 25 19 26 1A 27 1B 28 1C 29 1D 30 1E 31 1F 32 20 33 21 34 22 35 23 36 24 37 25 38 26 39 27 40 28 41 28 42 2A ASC NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US SP ! " # $ % & ' ( ) * DEC 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 HEX 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 65 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A ASC @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j DEC 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 HEX 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA ASC DEC 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 HEX C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA ASC + + + + + + i + + _ _ _

141

43 44 45 46 47 48 48 50 51 52 53 54 55 56 57 58 59 60 61 62 63

2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F

+ , . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F

k l m n o p q r s t u v w x y z { | } ~ DEL

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF

_ _ _ + + +

235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

_ _ DEL

142