Sie sind auf Seite 1von 41

INTRODUO

Este material apresenta as estruturas de dados mais importantes para programao no numrica, servindo de referncia para os cursos de graduao em cincia e engenharia da computao. Foi elaborado para um curso de um semestre sobre estruturas de dados e programao. A estrutura de dados a disciplina que estuda as formas e mtodos de soluo de problemas por meio do uso de algoritmos computacionais. Permite tambm o tratamento adequado da informao por meio da computao eletrnica. uma disciplina fundamental para a cincia da computao uma vez que se ocupa com o desenvolvimento de algoritmos, estrutura dos dados, suas representaes e transformaes para soluo de problemas. Os programas implementados neste material foram desenvolvidos e testados no ambiente Turbo C.

1 OBJETIVO
Ao final dos estudos do contedo deste livro o estudante deve estar apto a manipular as estruturas mais utilizadas na construo de soluo de problemas computacionais, bem como aperfeioar a capacidade de programao do estudante, contribuindo para a formao adequada dos profissionais de computao.

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

2 PR-REQUISITOS
Para obter o mximo de rendimento nesta disciplina, bem como ser capaz de implementar os problemas solveis pelas estruturas aqui apresentadas o estudante dever ter domnio de lgica de programao e uma linguagem de programao como C, Java ou Pascal. Devido s limitaes do computador, necessrio que utilizemos a abstrao para a representao e soluo de problemas do mundo real. atravs da abstrao que podemos capturar o que existe em uma situao real tornando possvel a construo de modelos que podem ser implementados nos computadores por meio de uma linguagem de programao. Para construir modelos devemos conhecer bem os detalhes da situao real e express-los por meio da estrutura de dados e de correspondentes algoritmos que atuaro sobre as mesmas. A Cincia da Computao se ocupa, entre outras coisas, com as seguintes reas abaixo. Mquina para processar algoritmos Linguagens para desenvolver algoritmos Fundamentos dos algoritmos Anlise dos algoritmos

3 ORGANIZAO

DO

LIVRO

Este livro est organizado de forma a apresentar o seu contedo de forma ordenada tal que os tpicos mais simples e que formam pr-requisitos dos seguintes sejam apresentados na ordem dos captulos. Cada captulo tem um resumo, sintetizando os tpicos abordados e exerccios cujos resultados esto no apndice B. Assim, os captulos esto distribudos conforme passamos a expor a seguir. O Captulo I apresenta e discute as definies bsicas, tais como tipos de dados, estrutura de uma linguagem de programao procedural, uma pequena reviso da linguagem C, que a linguagem adotada para implementao dos exemplos e exerccios apresentados neste livro. Tambm sero apresentados tpicos sobre funes, pois estas sero amplamente utilizadas ao longo de todo o livro.

INTRODUO

XI

O Captulo II ser destinado reviso das estruturas homogneas tais como vetores e matrizes. Tambm neste captulo veremos as estruturas heterogneas denominadas de registros, pois os tipos de estruturas de dados so bsicas e fundamentais para nosso estudo de estrutura de dados. O Captulo III apresenta, de forma introdutria, algumas ferramentas de anlise de algoritmos. Este tpico muito importante para que o aluno tenha noo de como projetar e identificar um algoritmo eficiente, avaliar uma soluo que pode ser ou no tratada do ponto de vista computacional. Neste captulo no abordaremos o assunto com profundidade, pois um tpico amplo e muito complexo. Mas introduziremos os conceitos de funes matemticas assintticas e como deduzir uma notao O com base em anlise de um algoritmo. O Captulo IV apresenta listas estticas e cadeias de caracteres como estruturas lineares. Aborda vrias operaes primitivas para estas estruturas tais como: tamanho, sub-cadeia, concatenao, inverso, insero em posies definidas, excluso de elementos em listas ordenadas bem como em listas desordenadas. O Captulo V trata as pilhas utilizando a estrutura de lista esttica. Optamos por esta ordem de apresentao da disciplina por se tornar mais fcil e acessvel para os estudantes que enfrentam grandes dificuldades em tratamento de estruturas dinmicas. Abordaremos as operaes primitivas tais como: criao, insero, retirada e acesso aos elementos desta estrutura. Veremos tambm as amplas aplicaes de pilhas na soluo de problemas computacionais. O Captulo VI aborda as filas utilizando a estrutura de listas estticas por ser mais fcil o entendimento por parte dos estudantes. So tratadas todas as operaes envolvendo filas, bem como suas aplicaes e importncia para a cincia da computao. O Captulo VII trata das listas encadeadas e duplamente encadeadas. Utilizamos as abordagens estticas e dinmicas para implementao destas estruturas a fim de mostrar que no h necessidade de utilizao de ponteiros para implementao das listas encadeadas, podendo ser implementadas em vetores tambm. Discutiremos e implementaremos todas as operaes primitivas desta estrutura e ficaro como sugesto exerccios para que o estudante possa praticar. O Captulo VIII discute a estrutura de dados pilha utilizando listas encadeadas com implementao em vetores. Neste ponto j se pode utilizar estruturas encadeadas para

XII

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

implementao de pilhas, pois j teremos visto em captulo anterior a implementao de estruturas lineares de forma encadeada. O Captulo IX abordar novamente filas utilizando listas encadeadas com implementao em vetores. Desta forma, alm de realizar uma reviso de pilhas e filas nos Captulos VIII e IX, apresentamos tambm uma nova aplicao para as listas encadeadas, pois filas e pilhas so casos particulares de listas. O Captulo X abordar recursividade que tem como objetivo rever estes tpicos e preparar o estudante para o estudo do tpico do Captulo XII que envolver recursividade para realizao de busca em rvores. O Captulo XI abordar classificao de dados que tambm um tpico preparatrio para o Captulo XII, onde estudaremos rvores de busca binria. Este tpico tem ampla aplicao na organizao de dados a fim de melhorar o tempo de acesso aos dados, que cada vez mais se torna crtico em razo do aumento da capacidade de armazenamento. O Captulo XII abordar rvores, com nfase em rvores binrias de busca, sendo apresentadas implementaes tanto em listas dinmicas como em lista encadeada por vetores. Sero abordadas todas as operaes primitivas sobre rvores binrias de busca, como buscas, balanceamento, insero e excluso. Esta uma das estruturas mais importantes na cincia da computao devido versatilidade e eficincia na soluo de problemas computacionais. Tem ampla aplicao na soluo de inmeros problemas. O Captulo XIII abordar grafos e suas aplicaes mais utilizadas para a soluo de problemas do mundo real. Comearemos pela introduo de grafos e exporemos as tcnicas de sua implementao, de solues para os problemas mais comuns pelo seu uso. O Captulo XIV apresenta as tcnicas de espalhamento ou hashing para clculo de endereamento como forma eficiente para armazenamento e recuperao de dados. O Captulo XV abordar alguns mtodos e algoritmos para a pesquisa de dados. Abordaremos pesquisa binria, seqencial, pesquisa por rvore binria de busca, pesquisa por transformao de chaves. Este tpico tem ampla aplicao na computao no que tange melhoria de velocidade de acesso aos dados.

CAPTULO 1

Definies Bsicas

Este captulo apresenta as definies bsicas e necessrias para o tratamento das estruturas de dados estudadas neste volume. Tambm define uma linguagem em pseudocdigo para a manipulao das estruturas de dados, pois para compreender os conceitos aqui apresentados e realizar a manipulao destas estruturas, suficiente o domnio de uma pseudo linguagem que denominamos de pseudocdigo, especialmente queles que no desejam utilizar uma linguagem de programao. Para aqueles que queiram utilizar a linguagem C, ns apresentaremos nas sees seguintes uma reviso dos conceitos essenciais e bsicos da linguagem C, o que ser suficiente para o aluno que j domina uma outra linguagem ou mesmo pseudocdigo trabalhar com as estruturas de dados aqui expostas. Os estudantes que desejarem aprofundar-se na linguagem C podem utilizar-se da bibliogrfica citada no final deste livro.

1.1 ESTRUTURAS PRIMITIVAS (TIPOS

DE

DADOS)

So os tipos de dados ou elementos primitivos que sobre os quais so construdas outras mais complexas. A seguir esto os tipos bsicos implementados na maioria das linguagens de programao.

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Inteiro ou integer que so os tipos de dados do conjunto de inteiros representados pelos nmeros naturais 1, 2, 3,,,n+1. Sobre esta classe de dados podem ser realizadas as operaes (+ , - , / , * , mod). O mod e o resto de uma diviso. Real (float, double) - So os nmeros do conjunto dos reais ou fracionrios representados por 0.1, 1.2, 3.14, 12.00. Sobre esta classe de dados podemos realizar as seguintes operaes e resultando valores fracionrios (+ , - , * , / ). Logical (boolean) - So tipos de dados que assumem somente dois valores lgicos (V, F), Verdadeiro ou Falso. Sobre esta classe de dados podemos realizar somente as operaes lgicas que so (e, ou , no). Caracter (char) - So tipos de dados que representam valores literais que pode ser uma letra ou um nmero ou um smbolo qualquer. Esta classe de dados suporta operaes de concatenao, substring, tamanho.

Para armazenar valores inteiros, a linguagem C oferece alguns tipos bsicos, tais como: char, short int, long int. Estes tipos diferem entre si pelo espao de memria utilizado e conseqentemente pelo intervalo de valores que podem representar. O tipo char, por exemplo, ocupa 1 byte, podendo representar 28 = 256 valores distintos. Os tipos short int e long int podem ser referenciados simplesmente com short e long, respectivamente. O tipo int transformado para o tipo inteiro natural da mquina. O tipo char um literal e usado para representar cdigos de caracteres, podendo ser convertido para inteiro se for um literal de 0 a 9. Para mais detalhes sobre converso (cast) de tipos de dados, consultar a bibliografia sobre linguagem C. Abaixo apresentamos uma tabela contendo os detalhes sobre os tipos primitivos usados na linguagem C. O tipo boolean ou lgico no existe na linguagem C. Esta linguagem utiliza os valores inteiros 0 para falso e qualquer outro valor para verdadeiro.
Tabela 1.1 Faixa de valores para os tipos primitivos Nome char int float long int double tamanho em bits 8 16 32 32 64 faixa de valores -128 a 127 -32.768 a 32.767 10-38 a 1038

-2.147.483.648 a 2.147.483.647 10-308 a 10308

CAPTULO 1 DEFINIES BSICAS

1.2 VARIVEIS
Variveis so identificadores de dados que podem assumir vrios valores, como o prprio nome j diz. A cada momento de execuo de um algoritmo, uma varivel pode estar com um valor diferente. Uma varivel representa um espao na memria do computador para armazenar um dado qualquer. Na linguagem C, todas as variveis devem ser explicitamente declaradas. Na declarao de uma varivel, obrigatoriamente, devem ser especificados seu tipo e seu nome. O nome da varivel serve de referncia (endereamento relativo) ao dado armazenado no espao de memria e o tipo do dado determina a natureza do dado que ser armazenado. Mesmo em pseudocdigo, devemos declarar as variveis seguindo um certo formalismo para que fique claro para o projetista que tipos de dados sero manipulados. Ao utilizarmos uma linguagem como C, devemos declarar variveis seguindo a sintaxe desta linguagem. A declarao de uma varivel reserva um espao na memria para armazenar um dado do tipo da varivel e associa o nome da varivel a este espao de memria. Mostraremos alguns exemplos de declarao de algumas variveis com os seus respectivos tipos. Por exemplo, nas declaraes abaixo, a e b so variveis do tipo inteiro e x uma varivel do tipo float. J em pseudocdigo, no necessitamos utilizar as palavras reservadas de uma linguagem. Por exemplo, int, float so palavras reservadas da linguagem C. Podemos simplesmente utilizar inteiro, int ou numrico, no h uma necessidade de seguir uma gramtica rgida, desde que fique claro o que se quer dizer. Exemplos de declarao de variveis: int a; int b; float x;

Atribuies de valores s variveis podem ser diretamente ou por meio de clculo ou leitura como mostraremos logo a seguir. a = 5; b= 4; x = 4.5;

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

ou ainda; a = b + 1;

A linguagem C permite que variveis de mesmo tipo sejam declaradas juntas. Assim, as duas primeiras declaraes acima poderiam ser substitudas por: int a, b; /* declara duas variveis do tipo int */

Uma vez declarada a varivel, podemos armazenar valores nos respectivos espaos de memria. Estes valores devem ter o mesmo tipo da varivel, conforme ilustrado acima. Em C, as variveis podem ser inicializadas na declarao. Podemos, por exemplo, escrever: int a; a = 4; /* a varivel armazenar o valor 4 */

int a = 5, b = 10; /* declara e inicializa as variveis a e b */ float c = 5.3; /* atribui o valor 5.3 a varivel c */

Podemos usar tambm valores constantes. Quando escrevemos a atribuio seguinte a = b + 123, sendo a e b variveis supostamente j declaradas, reserva-se um espao para a armazenar a constante 123. No caso, a constante do tipo inteiro, ento um espao de dois bytes (em geral) reservado e o valor 123 armazenado nele. A diferena bsica em relao s variveis, como os nomes dizem (variveis e constantes), que o valor armazenado numa rea de constante no pode ser alterado. As constantes tambm podem ser do tipo real. Uma constante real deve ser escrita com um ponto decimal ou valor de expoente. Sem nenhum sufixo, uma constante real do tipo double. Se quisermos uma constante real do tipo float, devemos, a rigor, acrescentar o sufixo F ou f. Alguns exemplos de constantes reais so: 12.45 - real do tipo double; 1245e-2 - real do tipo double; 12.45F - real do tipo float;

CAPTULO 1 DEFINIES BSICAS

Alguns compiladores exibem uma advertncia quando encontram o trecho de cdigo seguinte. float x; ... x = 12.45

O cdigo, a rigor, armazena um valor double (12.45) numa varivel do tipo float. Desde que a constante seja representvel dentro de um float, no precisamos nos preocupar com este tipo de advertncia. Um dos erros comuns em programas de computador o uso de variveis cujos valores ainda esto indefinidos. Por exemplo, o trecho de cdigo abaixo est errado, pois o valor armazenado na varivel b est indefinido e tentamos us-lo na atribuio de c. Assim, a varivel b tem lixo ou resqucio de dados na memria, pois a linguagem C no inicializa variveis ao serem declaradas. int a, b, c; a = 2; c = a + b; /* ERRO: b tem lixo */

Alguns destes erros so bvios e o compilador capaz de nos reportar uma advertncia. No entanto, muitas vezes o uso de uma varivel no definida fica difcil de ser identificado no cdigo. Repetimos que um erro comum em programas e uma razo para alguns programas funcionarem na parte da manh e no funcionarem na parte da tarde (ou funcionarem durante o desenvolvimento e no funcionarem quando entram em produo. Poder funcionar uma vez e no funcionar outra que, apesar de indefinido, o valor da varivel existe. No nosso caso acima, pode acontecer que o valor armazenado na memria ocupada por b seja 0, fazendo com que o programa funcione. Pode acontecer da varivel tr o valor 354332 e o programa no funcionar.

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

1.3 OPERADORES
Os operadores so instrues que realizam transformaes e comparaes dos dados ou operandos e podem ser divididos em trs grupos como descrito abaixo: A linguagem C oferece uma gama variada de operadores, entre binrios e unrios. Os operadores bsicos so apresentados a seguir.

1.3.1 Operadores Aritmticos e Associatividades


Os operadores aritmticos binrios so: +, -, *, / e o operador mdulo %. A operao feita na preciso dos operandos. Assim, a expresso 5/2 resulta no valor 2, pois a operao de diviso feita em preciso inteira, j que os dois operandos (5 e 2) so constantes inteiras. A diviso de inteiros trunca a parte fracionria, pois o valor resultante sempre do mesmo tipo da expresso. Conseqentemente, a expresso 5.0/ 2.0 resulta no valor real 2.5, pois a operao feita na preciso real (double, no caso). O operador mdulo, %, no se aplica a valores reais, seus operandos devem ser do tipo inteiro. Este operador produz o resto da diviso do primeiro pelo segundo operando. Como exemplo de aplicao deste operador, podemos citar o caso em que desejamos saber se o valor armazenado numa determinada varivel inteira x par ou mpar. Para tanto, basta analisar o resultado da aplicao do operador %, aplicado varivel e ao valor dois, x % 2, se resultado for zero. Um nmero dito par se (x % 2) for igual a zero e mpar, caso contrrio. Os operadores *, / e % tm precedncia maior que os operadores + e -. Operadores com mesma precedncia so avaliados da esquerda para a direita. Assim, na expresso: a + b * c /d executa-se primeiro a multiplicao, seguida da diviso, seguida da soma. Podemos utilizar parnteses para alterar a ordem de avaliao de uma expresso. Assim, se quisermos avaliar a soma primeiro, podemos escrever: (a + b) * c /d. A tabela dos operadores da linguagem C, Tabela 1.2 descrevendo as precedncias apresentada na seo 1.3.6. A tabela a seguir mostra a precedncia, em ordem decrescente, dos principais operadores da linguagem C.

CAPTULO 1 DEFINIES BSICAS

Tabela 1.2 Precedncia de operadores em C. ( ) [ ] -> . ! ~ ++ - (tipo) * & sizeof(tipo) */% +<< >> < <= > >= == != & | && || ?: = += -= etc. esquerda para direita direita para esquerda esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita esquerda para direita direita para esquerda direita para esquerda

A linguagem C tambm permite utilizar os chamados operadores de atribuio compostos. Comandos do tipo: i = i + 2; em que a varivel esquerda do sinal de atribuio tambm aparece direita, podem ser escritas de forma mais compacta: i += 2; usando o operador de atribuio composto +=. Analogamente, existem, entre outros, os operadores de atribuio: -=, *=, /=, %=. De forma geral, comandos do tipo: var op= expr; so equivalentes a: var = var op (expr); Salientamos a presena dos parnteses em torno de expr. Assim: x *= y + 1; equivale a x = x * (y + 1) e no a x = x * y + 1. H dois outros operadores no convencionais, que so os de incremento e decremento que servem para incrementar e decrementar uma unidade nos valores armazenados nas variveis. Assim, se n uma varivel que armazena um valor, o comando: n++; incrementa em uma unidade o valor de n. O aspecto no usual que ++ e podem ser usados tanto como operadores prefixados (antes da varivel, como em ++n) ou ps-fixados (aps a varivel, como em n++). Em ambos os casos, a varivel n incrementada. Porm, a expresso ++n incrementa n antes de usar seu valor, enquanto n++ incrementa n aps seu valor ser usado. Isto significa que, num contexto onde o valor de n usado, ++n e n++ so diferentes. Se n armazena o valor 5, ento: x = n++; atribui 5 a x, mas: x = ++n; atribuiria 6 a x. Em ambos os casos, n passa a valer 6, pois seu valor foi incrementado em uma unidade.

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Os operadores de incremento e decremento podem ser aplicados somente em variveis. Uma expresso do tipo x = (i + 1)++ incorreta. A linguagem C oferece diversas formas compactas para escrevermos um determinado comando. Mesmo para programadores experientes, o uso das formas compactas deve ser feito com critrio. Por exemplo, os comandos: a = a + 1; a += 1; a++; ++a; so todos equivalentes e o programador deve escolher o que achar mais adequado e simples.

1.3.2 Operadores Relacionais


Os operadores relacionais so aqueles que estabelecem uma relao entre dois operandos ou expresses. Na linguagem em C so os seguintes. < menor que; > maior que; <= menor ou igual que; >= maior ou igual que; == igual a; != diferente de.

Estes operadores comparam dois valores. O resultado produzido por um operador relacional 0 ou 1. Em C, no existe o tipo booleano (true ou false). O valor zero interpretado como falso e qualquer valor diferente de zero considerado verdadeiro. Assim, se o resultado de uma comparao for falso, produz-se o valor 0, caso contrrio, produz-se o valor 1.

1.3.3 Operadores Lgicos


Os operadores lgicos combinam expresses booleanas. A linguagem oferece os seguintes operadores lgicos: && operador binrio E (AND); || operador binrio OU (OR); ! operador unrio de NEGAO (NOT).

CAPTULO 1 DEFINIES BSICAS

Expresses conectadas por && ou || so avaliadas da esquerda para a direita, e a avaliao pra assim que a veracidade ou falsidade do resultado for conhecida. Recomendamos o uso de parnteses em expresses que combinam operadores lgicos e relacionais. Os operadores relacionais e lgicos so normalmente utilizados para tomada de decises. No entanto, podemos utiliz-los para atribuir valores a variveis. Por exemplo, o trecho de cdigo abaixo vlido e armazena o valor 1 em a e 0 em b. int a, b; int c = 23; int d = c + 4; a = (c < 20) || (d > c); /* verdadeiro */ b = (c < 20) && (d > c); /* falso */

Devemos salientar que, na avaliao da expresso atribuda varivel b, a operao (d>c) no chega a ser avaliada, pois independente do seu resultado a expresso como um todo ter como resultado 0 (falso), uma vez que a operao (c<20) tem valor falso.

1.3.4 Operador sizeof


Outro operador fornecido por C, sizeof, resulta no nmero de bytes de um determinado tipo. Por exemplo, int a = sizeof(float). Armazena o valor 4 na varivel a, pois um float ocupa 4 bytes de memria. Este operador pode tambm ser aplicado a uma varivel, retornando o nmero de bytes do tipo associado varivel.

1.3.5 Converso de Tipo


Existem converses automticas de valores na avaliao de uma expresso. Assim, na expresso 3/1.5, o valor da constante 3 (tipo int) promovido (convertido) para double antes de a expresso ser avaliada, pois o segundo operando do tipo double (1.5) e a operao feita na preciso do tipo mais representativo. Quando, numa atribuio, o tipo do valor atribudo diferente do tipo da varivel, tambm h uma converso automtica de tipo. Por exemplo, se escrevermos: int a = 3.5; o valor 3.5 convertido para inteiro (isto , passa a valer 3) antes de a atribuio ser efetuada. Como resultado, o valor atribudo varivel 3 (inteiro). Alguns

10

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

compiladores exibem advertncias quando a converso de tipo pode significar uma perda de preciso ( o caso da converso real para inteiro, por exemplo). O programador pode explicitamente requisitar uma converso de tipo atravs do uso do operador de molde de tipo (operador cast). Por exemplo, so vlidos os comandos abaixo. int a, b; char c; c = 5; // declara duas variveis inteiras // declara uma varivel do tipo caractere. // atribuio de um caractere 5 para c. // a varivel a recebe o valor 3 convertido para inteiro

a = (int) 3.5;

b = (int) 3.5 % 2; // a varivel b recebe um valor inteiro 1. b = c + a; // a varivel b ficar com o valor 8 que 3 + 5.

1.4 ENTRADAS

SADAS

As operaes de entrada e sada so realizadas por funes. Existe em C uma biblioteca padro que possui as funes bsicas necessrias. Na biblioteca padro, podemos encontrar funes matemticas do tipo raiz quadrada, seno, cosseno etc., funes para a manipulao de cadeias de caracteres e funes de entrada e sada. Nesta seo, sero apresentadas as duas funes bsicas de entrada e sada disponibilizadas pela biblioteca padro. necessrio escrever: #include <stdio.h> no incio do programa que utiliza as funes da biblioteca de entrada e sada.

1.4.1 Funo printf


A funo printf possibilita a sada de valores (sejam eles constantes, variveis ou resultado de expresses), segundo um determinado formato. Informalmente, podemos dizer que a forma da funo : printf (formato, lista de constantes/variveis/expresses...). O primeiro parmetro uma cadeia de caracteres, em geral delimitada com aspas, que especifica o formato de sada das constantes, variveis e expresses listadas em seguida.

CAPTULO 1 DEFINIES BSICAS

11

Para cada valor que se deseja imprimir, deve existir um especificador de formato correspondente na cadeia de caracteres formato. Os especificadores de formato variam com o tipo do valor e a preciso em que queremos que eles sejam impressos. Estes especificadores so precedidos pelo caractere % e especificam os seguintes tipos: %c - char; %d - int; %i - int; %u - unsigned int; %f - double (ou float); %e - double (ou float) no formato cientfico; %g - double (ou float) no formato mais apropriado (%f ou %e); %s - cadeia de caracteres.

Com base nesses conceitos, vamos apresentar alguns exemplos como segue. A funo printf (%d %g\n, 33, 5.3) tem como resultado a impresso da linha: 33 5.3, ou ainda: printf (Inteiro = %d Real = %g\n, 33, 5.3), com sada: Inteiro = 33 Real = 5.3. Isto , alm dos especificadores de formato, podemos incluir textos no formato, que so mapeados diretamente para a sada. Assim, a sada formada pela cadeia de caracteres do formato onde os especificadores so substitudos pelos valores correspondentes. Existem alguns caracteres de escape que so freqentemente utilizados nos formatos de sada. So eles: \n - nova linha; \t - tabulao; \r - de retrocesso; \ o caractere ; \\ o caractere \.

12

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Ainda, se desejarmos ter como sada um caractere %, devemos, dentro do formato, escrever %%. possvel tambm especificar o tamanho dos campos, como segue: %4d; %7.2f;

A funo printf retorna o nmero de campos impressos. Salientamos que para cada constante, varivel ou expresso listada devemos ter um especificador de formato apropriado.

1.4.2 Funo scanf


A funo scanf permite capturarmos valores fornecidos via teclado pelo usurio do programa. Informalmente, podemos dizer que sua forma geral : scanf (formato, lista de endereos das variveis). O formato deve possuir especificadores de tipos similares aos mostrados para a funo printf. Para a funo scanf, no entanto, existem especificadores diferentes para o tipo float e double como segue: %c - char; %d - int; %u - unsigned int; %f,%e,%g - float; %lf, %le, %lg - double; %s - cadeia de caracteres.

A principal diferena que o formato deve ser seguido por uma lista de endereos de variveis (na funo printf passamos os valores de constantes, variveis e expresses). Por ora, basta saber que, para ler um valor e atribu-lo a uma varivel, devemos passar o endereo da varivel para a funo scanf. O operador & retorna o endereo de uma varivel. Assim, para ler um inteiro, devemos ter: int n; scanf (%d, &n);

CAPTULO 1 DEFINIES BSICAS

13

Para a funo scanf, os especificadores %f, %e e %g so equivalentes. Aqui, caracteres diferentes dos especificadores no formato servem para restringir a entrada. Por exemplo: scanf (%d:%d, &h, &m); obriga que os valores (inteiros) fornecidos sejam separados pelo caractere dois pontos (:). Um espao em branco dentro do formato faz com que sejam pulados eventuais brancos da entrada. Os especificadores %d, %f, %e e %g automaticamente pulam os brancos que precederem os valores numricos a serem capturados. A funo scanf retorna o nmero de campos lidos com sucesso.

1.5 CONTROLE

DE

FLUXO

Nas linguagens procedurais existem estruturas de controles do fluxo de execuo do programa. As construes fundamentais de controle de fluxo necessrias para programas bem estruturados so agrupamentos de comandos, tomadas de deciso (ifelse), laos com teste de encerramento no incio (while, for) ou no fim (do-while), e seleo de um dentre um conjunto de possveis casos (switch).

1.5.1 Deciso ou Seleo com if


O comando de seleo ou deciso if um comando de deciso bsico. A forma de se usar este comando est exemplificado a seguir, onde temos exemplos de seleo simples e composta.
if (expr) { bloco de comandos 1 ... } ou if ( expr ) { bloco de comandos 1 ... } else { bloco de comandos 2 ... }

14

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Se expr produzir um valor diferente de 0 (verdadeiro), o bloco de comandos 1 ser executado. A incluso do else requisita a execuo do bloco de comandos 2, se a expresso produzir o valor 0 (falso). Cada bloco de comandos deve ser delimitado por uma chave aberta e uma chave fechada. Se dentro de um bloco tivermos apenas um comando a ser executado, as chaves podem ser omitidas, como vemos abaixo. Na verdade, deixamos de ter um bloco.
if ( expr ) comando1; else comando2;

A indentao (recuo de linha) dos comandos fundamental para uma maior clareza do cdigo. O estilo de indentao varia a gosto do programador. Podemos aninhar comandos if. Um exemplo simples ilustrado a seguir:
#include <stdio.h> void main (void) { int a, b; printf(Digite dois nmeros inteiros:); scanf(%d%d,&a,&b); if (a%2 == 0) if (b%2 == 0) printf(VoceDigitou dois numeros pares!\n); }

Primeiramente, notamos que no foi necessrio criar blocos ( {...} ) porque a cada if est associado apenas um comando. Ao primeiro, associamos o segundo comando if, e ao segundo if, o comando que chama a funo printf. Assim, o segundo if s ser avaliado se o primeiro valor fornecido for par, e a mensagem s ser impressa se o segundo valor fornecido tambm for par. Outra construo para o mesmo exemplo produzir resultados idnticos como escrito a seguir.
void main (void) { int a, b;

CAPTULO 1 DEFINIES BSICAS

15

printf(Digite dois numeros inteiros:); scanf(%d%d,&a,&b); if ((a%2 == 0) && (b%2 == 0)) printf ( Voce digitou dois numeros pares!\n); }

Devemos ter cuidado com o aninhamento de comandos if-else. A indentao utilizada pode nos levar a erros de interpretao. Para os casos em que a associao entre if e else no est clara, recomendamos a criao explcita de blocos, mesmo contendo um nico comando. Reescrevendo o programa, podemos obter o efeito desejado.
/* temperatura */ #include <stdio.h> void main (void) { int temp; printf ( Digite a temperatura: ); scanf ( %d, &temp ); if ( temp < 30 ) { if ( temp > 20 ) printf ( Temperatura agradavel \n ); } else printf ( Temperatura muito quente \n ); }

Esta regra de associao do else propicia a construo do tipo else-if, sem que se tenha o comando elseif explicitamente na gramtica da linguagem. Na verdade, em C, construmos estruturas else-if com ifs aninhados. O exemplo a seguir vlido e funciona como esperado.
/* temperatura (versao 1) */ #include <stdio.h> void main (void) { int temp; printf(Digite a temperatura: );

16

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

scanf(%d, &temp); if (temp < 10) printf(Temperatura muito fria \n); else if (temp < 20) printf( Temperatura fria \n); else if (temp < 30) printf(Temperatura agradavel \n); else printf(Temperatura muito quente \n); }

1.5.2 Estruturas de Bloco


Uma funo composta por estruturas de blocos. Cada chave aberta e fechada em C representa um bloco. As declaraes de variveis s podem ocorrer no incio do corpo da funo ou no incio de um bloco, isto , devem seguir uma chave aberta. Uma varivel declarada dentro de um bloco vlida apenas dentro do bloco. Aps o trmino do bloco, a varivel deixa de existir. Por exemplo:
... if ( n > 0 ) { int i; ... } ... /* a varivel i no existe neste ponto do programa */

A varivel i, definida dentro do bloco do if, s existe dentro deste bloco. uma boa prtica de programao declarar as varveis o mais prximo possvel dos seus usos.

1.5.3 Construes com Laos


A interatividade um dos recursos mais poderosos em programas computacionais. So procedimentos interativos, isto , procedimentos que devem ser executados em vrios passos. Para calcular o fatorial de um nmero atravs de um programa de computador, utilizamos tipicamente um processo interativo, em que o valor da varivel varia de 1

CAPTULO 1 DEFINIES BSICAS

17

a n. A linguagem C oferece diversas construes possveis para a realizao de laos iterativos. O primeiro a ser apresentado o comando while. Sua forma geral :
while (expr) { bloco de comandos ... }

Enquanto expr for avaliada em verdadeiro, o bloco de comandos executado repetidamente. Se expr for avaliada como falso, o bloco de comando no executado e a execuo do programa prossegue aps o final do bloco do lao. Uma possvel implementao do clculo do fatorial usando while mostrada a seguir.
/* fatorial */ #include <stdio.h> void main (void){ int I, n; int f = 1; printf(Digite um nmero inteiro:); scanf(%d, &n); /* calcula fatorial */ i = 1; while (i <= n) { f *= i; i++; } printf( Fatorial = %d \n, f); }

Uma segunda forma de construo de laos, mais compacta e amplamente utilizada, atravs de laos for. A forma geral do for :
for (expr_inicial; expr_relacional; expr_de_incremento) { bloco de comandos ... }

18

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

A implementao do lao for pode ser verificada no cdigo a seguir, onde ilustramos a utilizao do comando for no programa para clculo do fatorial.
/* fatorial ) */ #include <stdio.h> void main (void) { int I, int n; int f = 1; printf(Digite um nmero inteiro:); scanf(%d, &n); /* calcula fatorial */ for (i = 1; i <= n; i++) { f *= i; } printf( Fatorial = %d \n, f); }

Observamos que as chaves que seguem o comando for, neste caso, so desnecessrias, j que o corpo do bloco composto por um nico comando. Tanto a construo com while como a construo com for avaliam a expresso booleana que caracteriza o teste de encerramento no incio do lao. Assim, se esta expresso tiver valor igual a zero (falso), quando for avaliada pela primeira vez, os comandos do corpo do bloco no sero executados nenhuma vez. H um outro comando para construo de laos cujo teste de encerramento avaliado no final. Esta construo o do-while, cuja forma geral :
do{ bloco de comandos } while (expr_booleana);

Um exemplo do uso desta construo mostrado abaixo, onde validamos a insero do usurio, isto , o programa repetidamente solicita a insero de um nmero enquanto o usurio inserir um inteiro negativo.
/* f atorial #include <stdio.h> */

CAPTULO 1 DEFINIES BSICAS

19

void main (void) { int I, n; int f = 1; do{ printf(Digite um valor inteiro nao negativo:); scanf (%d, &n); } while (n<0); /* calcula fatorial */ for (i = 1; i <= n; i++){ f *= i; } printf( Fatorial = %d\n, f); }

1.5.4 Interrupes com break e continue


O comando break, quando utilizado dentro de um lao, interrompe e termina a execuo do mesmo. A execuo prossegue com os comandos subseqentes ao bloco. O cdigo abaixo ilustra o efeito de sua utilizao.
#include <stdio.h> void main (void) { int i; for (i = 0; i < 10; i++) if (i == 5) break; printf(%d , i); } printf(fim\n); }

A sada deste programa, se executado, ser: 0 1 2 3 4 fim pois, quando i tiver o valor 5, o lao ser interrompido e finalizado pelo comando break, passando o controle para o prximo comando aps o lao, no caso uma chamada final de printf. O comando continue tambm interrompe a execuo dos comandos de um lao. A diferena bsica em relao ao comando break que o lao no automaticamente finalizado. O comando continue interrompe a execuo de um lao passando para a

20

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

prxima interao pulando os comandos existentes, como podemos ver no cdigo abaixo.
#include <stdio.h> void main (void) { int i; for (i = 0; i < 10; i++ ) { if (i == 5) continue; printf(%d , i); } printf(fim\n); }

O resultado de sada do programa acima o seguinte conjunto. {0 1 2 3 4 6 7 8 9 fim}. Devemos ter cuidado com a utilizao do comando continue nos laos while. Observe um programa INCORRETO escrito logo abaixo.
/* Verso INCORRETA */ #include <stdio.h> void main (void) { int i = 0; while (i < 10) { if (i == 5) continue; printf(%d , i); i++; } printf(fim\n); }

O programa acima est INCORRETO, pois o lao criado no tem fim. A execuo do programa no termina. Isto porque a varivel i nunca ter valor superior a 5, e o teste ser sempre verdadeiro. O que ocorre que o comando continue provoca um salto dos demais comandos do lao quando i for igual a 5, inclusive o comando que incrementa a varivel i.

CAPTULO 1 DEFINIES BSICAS

21

1.5.5 Seleo
Alm da construo else-if, temos tambm o comando (switch) para selecionar um dentre um conjunto de possveis casos. Sua forma geral est exemplificada abaixo.
int op = 1; scanf(%d,&op); switch (op){ case 1: ... /* comandos executados se op == 1 break; case 2: ... /* comandos executados se op == 2 break; case 3: ... /* comandos executados se op == 3 break; default: ... /* executados se op for diferente break; }

*/

*/

*/

de todos */

A varivel op deve ser um nmero inteiro ou uma constante caractere. Se op resultar no valor op, os comandos que se seguem ao caso op so executados, at que se encontre um break. Se o comando break for omitido, a execuo do caso continua com os comandos do caso seguinte. O caso default (nenhum dos outros) pode aparecer em qualquer posio, mas normalmente colocado por ltimo. Para exemplificar, mostramos a seguir um programa que implementa uma calculadora convencional que efetua as quatro operaes bsicas. Este programa usa constantes caracteres.
/* Calculadora de quatro operaes */ #include <stdio.h> void main (void) { float num1, num2; char op; printf(Digite: numero op numero\n);

22

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

scanf (%f %c %f, &num1, &op, &num2); switch (op) { case +: printf( = %f\n, num1+num2); break; case -: printf( = %f\n, num1-num2); break; case *: printf( = %f\n, num1*num2); break; case /: printf( = %f\n, num1/num2); break; default: printf(Operador invalido!\n); break; } }

1.6 PROCEDIMENTOS

FUNES

So sub-rotinas que implementam uma determinada quantidade de cdigo que realizam uma tarefa bem determinada. So exemplos de funes ou procedimentos: calcular raiz quadrada, obter uma substring, calcular potncia etc. H uma diferena entre procedure e funo. Procedure uma rotina que no retorna valor e Funo uma rotina que retorna um valor determinado. A funo s retorna um valor. Os prximos procedimentos ilustram o uso de rotinas em pseudocdigo e em seguida a implementao correspondente em linguagem C. O uso do pseudocdigo livre dos rigores da sintaxe exigida pelo compilador, facilitando o entendimento do problema e a conseqente soluo atravs da lgica de programao. A seguir esto alguns exemplos de rotinas que chamam sub-rotinas, tanto em pseudocdigo como em linguagem C. Algumas rotinas realizam chamadas a outras funes. Observe os exemplos seguintes de pseudocdigos que ilustram o que estamos estudando. O fragmento de cdigo que segue apresenta um procedimento principal (void) que instancia algumas variveis e realiza as chamadas a uma funo obtendo o retorno que

CAPTULO 1 DEFINIES BSICAS

23

ser armazenado na varivel r e em seguida utiliza outro procedimento imprime (r) para imprimir o valor que foi retornado. Aps a impresso do resultado da funo produto, temos um procedimento denominado de soma que calcula a soma e imprime o resultado. Devemos notar que este ltimo procedimento no retorna valor algum.
/* procedimento principal */ inicio int x,y,r; x = 2; y=3; r = produto(x,y); imprime(r); soma(x,y); fim

// chamada da funo com passagem de parmetros

/* Rotina/funo produto */ int produto(int k,int z) inicio return(k * z); fim // Procedimento soma // procedimento soma(x,y) inicio var x,y:inteiro; imprime(x + y); fim

Aps o entendimento de como funcionam os procedimentos apresentados anteriormente em pseudocdigo, vamos codific-los na linguagem C. Os prximos cdigos so implementaes em C para os algoritmos anteriores.
/* rotina principal da linguagem C */ void main() { int x,y,r;

24

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

x=2; y=3; r = produto(x,y); printf(%i,r); soma(x,y); }

// chamada da funo com passagem de parmetros

/* - funo produto */ int produto(int k,int z) { return(k * z); } /* Procedimento soma */ void soma(x,y) { int x,y; printf(%d,x+y); }

A construo de funes tem o objetivo de dividir grandes tarefas de computao em tarefas menores. A criao de funes evita a repetio de cdigo, de modo que um procedimento que repetido deve ser transformado numa funo que, ento, ser chamada diversas vezes. Um programa bem estruturado deve ser planejado em termos de funes, e estas, por sua vez, podem esconder do corpo principal do programa detalhes ou particularidades de implementao. Nesta seo, discutiremos a codificao de nossas prprias funes. A forma geral para definir uma funo pode ser verificada no exemplo a seguir.
tipo_retornado nome_da_funo (lista de parmetros...) { corpo da funo }

CAPTULO 1 DEFINIES BSICAS

25

Para ilustrar a criao de funes, consideraremos o clculo do fatorial de um nmero. Podemos escrever uma funo que, dado um determinado nmero inteiro no negativo n, imprime o valor de seu fatorial. Um programa que utiliza esta funo pode ser escrita como segue:
/* imprime um fatorial */ #include <stdio.h> void fat (int n);

/* prottipo da funo fat() */

/* funo principal */ void main (void) { int n; scanf(%d, &n); fat(n); } /* funo que imprime o fatorial */ void fat ( int n ) { int i; int f = 1; for (i = 1; i <= n; i++) f *= i; printf(Fatorial = %d\n, f); }

Notamos, neste exemplo, que a funo fat recebe como parmetro o nmero cujo fatorial deste deve ser impresso. Os parmetros de uma funo devem ser listados, com seus respectivos tipos, entre os parnteses que seguem o nome da funo. Devemos notar que main() tambm uma funo. Sua nica particularidade consiste em ser a funo automaticamente executada aps o programa ser carregado. No exemplo do clculo do fatorial, a funo fat no tem nenhum valor de retorno, portanto colocamos a palavra void antes do nome da funo, indicando a ausncia de um valor de retorno.

26

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

void fat (int n) { . . . }

Ressaltamos que C exige que se coloque o prottipo da funo antes desta ser chamada, se estas funes forem implementadas aps a funo main(). O prottipo de uma funo consiste na repetio da linha de sua definio seguida do caractere (;). A rigor, no prottipo no h necessidade de indicarmos os nomes dos parmetros, apenas os seus tipos, portanto seria vlido escrever: void fat (int). O prottipo da funo necessrio para que o compilador verifique os tipos dos parmetros na chamada da funo. devido a esta necessidade que se exige a incluso do arquivo stdio.h para a utilizao das funes de entrada e sada da biblioteca padro. Neste arquivo, encontram-se, entre outras coisas, os prottipos das funes printf e scanf. Uma funo pode ter um valor de retorno associado. Para ilustrar a discusso, vamos reescrever o cdigo acima, fazendo com que a funo fat retorne o valor do fatorial.
#include <stdio.h> int fat (int n); /* prottipo */ void main (void) { int n, r; scanf(%d, &n); r = fat(n); printf(Fatorial = %d\n, r); } /* funcao fatorial */ int fat (int n) { int i; int f = 1; for (i = 1; i <= n; i++) f *= i; return(f) }

CAPTULO 1 DEFINIES BSICAS

27

1.7 USO DE PONTEIRO


Nesta seo apresentaremos uma reviso de ponteiros em linguagem C, o que servir como base para a implementao de listas encadeadas utilizando ponteiros. Para cada tipo de dado existente, h um tipo ponteiro que pode armazenar endereos de memria onde existem valores do tipo correspondente armazenados. Por exemplo, quando escrevemos: int a; declaramos uma varivel com nome a que pode armazenar valores inteiros. Automaticamente, reserva-se um espao na memria suficiente para armazenar valores inteiros (geralmente 2 bytes). Da mesma forma que declaramos variveis para armazenar inteiros, podemos declarar variveis que, em vez de servirem para armazenar valores inteiros, servem para armazenar valores de endereos de memria onde h variveis inteiras armazenadas. Para declararmos um ponteiro, usamos a mesma palavra do tipo com os nomes das variveis precedidas pelo caractere *. Assim, podemos escrever: int *p para declarar um ponteiro do tipo int. Neste caso, declaramos uma varivel com nome p que pode armazenar endereos de memria onde existe um inteiro armazenado. Para atribuir e acessar endereos de memria. Podemos usar o operador unrio & (endereo de), que resulta no endereo da posio da memria reservada para a varivel. O operador unrio * (contedo de), aplicado a variveis do tipo ponteiro, acessa o contedo do endereo de memria armazenado pela varivel ponteiro. Para trabalharmos com alocao dinmica, devemos alocar pores de memria utilizando a funo malloc() que ser mostrada a seguir.
main ( ){ int *ptr, i; ptr = (int *) malloc (sizeof(int)); *ptr = 5800; i = *ptr; printf(%i,i); /* imprimir 5800 */ i = 4200; printf(%i,i); /* imprimir 4200 */ }

28

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Ao analisarmos o cdigo acima notamos que a varivel *ptr foi declarada como inteiro para ponteiro e na linha seguinte foi reservado 2 bytes para ptr que recebe o valor 5800. A varivel i recebe o contedo de do endereo de ptr que 5800, como podemos verificar pela impresso da antepenltima linha.
main(){ int x; *px; ... px = &x; }

O fragmento do cdigo acima atribui o endereo de x para px. O contedo de px o endereo da varivel x. Vamos exemplificar o uso de ponteiro utilizando o fragmento de cdigo abaixo.
main(){ char c, *pc, x; c = A; pc = &c; print f (%c, *pc); x = *pc; }

Para compreendermos melhor o uso de ponteiros, vamos estudar o cdigo do programa acima, observando os mapas de memrias na seqncia de quadros a seguir.

C 1000 Lixo

pc 1001 lixo

x 1003 Lixo

CAPTULO 1 DEFINIES BSICAS

29

Fazemos a varivel c receber o valor A como segue: c = A

c 1000 A

pc 1001 lixo

x 1003 Lixo

A varivel pc recebe o endereo da varivel c que dado pela expresso seguinte: pc = &c:

c 1000 A

Pc 1001 1000

X 1003

Ao imprimirmos o contedo da varivel pc, teremos como sada, o valor A que est no endereo 1000. Basta executar esta linha printf (%c, *pc). Ao atribuirmos o contedo de pc (*pc) a varivel x, temos x = c. A seguir, apresentamos outros exemplos de uso de ponteiros. No cdigo abaixo, declaramos duas variveis do tipo inteiro, a primeira um inteiro simples, a segunda um inteiro para ponteiro. Em seguida a varivel p, que destinada a armazenar endereos, recebe o endereo da varivel a. Ao atribuirmos 2 a *p, estamos colocando o valor 2 no endereo da varivel a. Assim, o programa ir imprimir o valor 2. Sugerimos ao leitor que implemente este cdigo para comprovar o que estamos apresentando.
int main ( void ) { int a; int *p; p = &a; *p = 2; printf( %d , a); return; }

30

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

Agora que vimos como usar ponteiros, j podemos aplicar este conceito na utilizao de estruturas para implementar listas. Abaixo apresentaremos a definio da estrutura node ou n de uma lista encadeada. Aps a definio, usamos a funo malloc() para reservar uma poro de memria correspondente ao tamanho do n da lista.
struct node{ int info; struct node *prox; }; struct node *ptr; ptr = (struct node*) malloc(sizeof(struct node));

De maneira anloga, podemos declarar ponteiros de outros tipos: float *m; char *s, alm de outros tipos que podemos construir na linguagem C, como vimos acima com a funo malloc() e struct;

1.8 PASSAGEM

DE

PONTEIROS

PARA

FUNES

Os ponteiros oferecem meios de alterarmos valores de variveis acessando-as indiretamente. As funes no podem alterar diretamente valores de variveis da funo que fez a chamada. No entanto, se passarmos para uma funo os valores dos endereos de memria onde suas variveis esto armazenadas, a funo pode alterar, indiretamente, os valores das variveis da funo que a chamou. Vamos analisar o uso desta estratgia atravs de um exemplo. Consideremos uma funo projetada para trocar os valores entre duas variveis. O prximo cdigo no funciona como esperado (sero impressos 5 e 7), pois os valores de a e b da funo main() no so alterados. Alterados so os valores de x e y dentro da funo troca, mas eles no representam as variveis da funo main(), apenas so inicializados com os valores de a e b.
/* funcao troca (versao INCORRETA) */ #include <stdio.h> void troca (int x, int y ) { int temp;

CAPTULO 1 DEFINIES BSICAS

31

temp = x; x = y; y = temp; } void main ( void ) { int a = 5, b = 7; troca(a, b); printf(%d %d \n, a, b); }

A alternativa fazer com que a funo receba os endereos das variveis e, assim, alterar seus valores indiretamente. Reescrevendo o programa acima, corrigindo os erros, temos:
/* funcao troca (versao CORRETA) */ #include <stdio.h> void troca (int *px, int *py ) { int temp; temp = *px; *px = *py; *py = temp; } void main ( void ) { int a = 5, b = 7; troca(&a, &b); /* passamos os endereos das variveis */ printf(%d %d \n, a, b); }

O cdigo mostrado ilustra a execuo deste programa mostrando o uso da memria. Assim, conseguimos o efeito desejado. Agora fica explicado por que passamos o endereo das variveis para a funo scanf(), pois, caso contrrio, a funo no conseguiria devolver os valores lidos. Para finalizar, vamos apresentar a passagem de estruturas por parmetro. No cdigo a seguir temos duas funes que recebem parmetros. A funo imp1() recebe um ponteiro para variveis simples ou primitiva, a outra funo imp() recebe uma estrutura.

32

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

/* passagem de parmetros por referncia */ # include <stdio.h> struct teste{ /* definio da estrutura teste int m; char n[10]; };

*/

void imp(struct teste te); /* prottipo da funo imp. */ void imp1(int x, int y); /* prottipo da funa imp1() */ void main(){ int i,j; struct teste te; te.m = 5; te.n[0] = T; te.n[1] = e; te.n[2] = s; te.n[3] = t; te.n[4] = e; i = 10; j = 20; imp1(&i,&j); imp(&te); /* passagtem da estrutura */ getch(); } /* recebe um endereo da estrutura teste como parmetro */ void imp(struct teste *te){ int i; printf(Estrutura\n); printf(%d\n,te->m); for (i=0; i < 5; i++) printf(%c,te->n[i]); printf(\n); } /* recebe os endereos das variveis x e y e imprime os seus contedos*/ void imp1(int *x, int *y){ printf(inteiros x e y\n); printf(%d\n,*x); printf(%d\n,*y); }

CAPTULO 1 DEFINIES BSICAS

33

1.9 RESUMO DO CAPTULO I DEFINIES BSICAS


Nesta seo apresentamos o resumo dos principais tpicos do captulo.

1.9.1 Tipos de Dados (int, char, float, double) Operaes


Faixa de valores para os tipos primitivos Nome char int float long int double tamanho em bits 8 16 32 32 64 faixa de valores -128 a 127 -32.768 a 32.767 10-38 a 1038 -2.147.483.648 10-308 a 10308 a 2.147.483.647

1.9.2 Variveis (declarao, atribuio) 1.9.3 Operadores:


Aritmtico(+, -, *, /, %); Relacionais(==, >=, <=, !=, <, >,); Lgicos(&&, ||, !).

1.9.4 Converso de Tipo(cast (int)5.4, (float) 5, (int) 4) 1.9.5 Funes de E/S


Entrada: scanf(), getchar() gets(). Sada: printf(), puts, putchar()).

34

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

1.9.6 Formatos para as Funes printf() e scanf()


%c - char; %d - int; %i - int; %u - unsigned int; %f - double (ou float); %e - double (ou float) no formato cientfico; %g - double (ou float) no formato mais apropriado (%f ou %e); %s - cadeia de caracteres.

1.9.7 Funo printf()


\n - nova linha; \t - tabulao; \r - de retrocesso; \ o caractere ; \\ o caractere \.

1.9.7 Controle de Fluxo


if else; switch case; while do; do while; for;

CAPTULO 1 DEFINIES BSICAS

35

1.9.8 Exemplos de Controle de Fluxo por switch-case


int op = 1; scanf(%d,&op); switch (op){ case 1: ... /* comandos executados se op == 1 break; case 2: ... /* comandos executados se op == 2 break; case 3: ... /* comandos executados se op == 3 break; default: ... /* executados se op for diferente break; }

*/

*/

*/

de todos */

1.9.9 Exemplos de Controle de Fluxo por Laos while e do-while


# include stdio.h # include conio.h main(){ int x=0; clrscr(); while (x< 10) { x++; printf(%d, , x); } x = 0; do { x++; printf(%d ,x); }while(x < 10); getch(); }

36

ESTRUTURA DE DADOS E ALGORITMOS USANDO C

1.9.10 Exemplo da Quebra do Loop pelo commando break


void main (void) { int i; for (i = 0; i < 10; i++) if (i == 5) break; printf(%d , i); } printf(fim\n); }

1.9.11 Ponteiros(int x,*px; x=5, *px = &x)


main ( ){ int *ptr, i; ptr = (int *) malloc (sizeof(int)); *ptr = 5800; i = *ptr; printf(%i,i); /* imprimir 5800 */ i = 4200; printf(%i,i); /* imprimir 4200 */ }

1.9.12 Funes:
prottipos, declaraes; passagem de parmetros: ! ! por valor realiza uma cpia da varivel, por referncia passa somente o endereo da varivel.

tipos de retorno;

CAPTULO 1 DEFINIES BSICAS

37

1.9.13 Exemplos:
#include <stdio.h> void troca (int *px, int *py ) { int temp; temp = *px; *px = *py; *py = temp; } void main ( void ) { int a = 5, b = 7; troca(&a, &b); /* passamos os endereos das variveis */ printf(%d %d \n, a, b); }

1.10 EXERCCIOS
i) ii) Declarar um conjunto de variveis inteiras, reais e char. Construir um loop para realizar 10 interaes e imprimir somente os nmeros pares das interaes.

iii) Calcular o somatrio dos quadrados dos valores de um at n. iv) Construir um procedimento para imprimir o produto de dois valores recebidos por parmetro. v) Construir uma funo que retorne o resto de uma diviso entre dois nmeros inteiros.

vi) Construir uma funo que recebe como parmetro o endereo de uma varivel e altere o valor para que a funo principal possa imprimir. vii) Elabore uma funo que receba uma estrutura por referncia, altere os valores dos membros da estrutura e faa a funo principal imprimir esses valores alterados. viii) Elabore uma funo que receba uma estrutura por valor, altere os valores dos membros da estrutura e devolva para a funo principal imprimir esses valores alterados.

Das könnte Ihnen auch gefallen