Você está na página 1de 83

Linguagem de Programao I

Linguagem de Programao I

Ed. v0.2.3
i

Linguagem de Programao I

Sumrio

I
1

Contedos programticos
Reviso 1.1 1.2 1.3 Algoritmos computacionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A linguagem de programao C . . . . . . . . . . . . . . . . . . . . . . . . . . . . Estruturas de dados e estruturas de controle . . . . . . . . . . . . . . . . . . . . . . 1.3.1 1.3.2 1.3.3 Declarao de variveis em C . . . . . . . . . . . . . . . . . . . . . . . . . Estruturas de controle sequenciais e de deciso . . . . . . . . . . . . . . . . Estruturas de repetio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3.1 1.3.3.2 1.3.3.3 1.3.4 Estrutura de repetio para um nmero denido de repeties (estrutura for) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Estrutura de repetio para um nmero indenido de repeties (estrutura while) . . . . . . . . . . . . . . . . . . . . . . . . . . . . Estrutura de repetio para um nmero indenido de repeties e teste no nal da estrutura (estrutura do-while) . . . . . . . . . . . Arrays unidimensionais ou vetores . . . . . . . . . . . . . . . . . Arrays bidimensionais ou multidimensionais . . . . . . . . . . . .

1
2 2 3 4 4 6 7 7 8 9 9 9 10 12 12 17 17 19 19 20 20 21 22

Arrays em C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.4.1 1.3.4.2

1.4 1.5 2

Estrutura geral de um programa em C . . . . . . . . . . . . . . . . . . . . . . . . . Atividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Registros 2.1 2.2 2.3 2.4 Denio de registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sintaxe para criao de registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . Identicadores de registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Anlise para criao de Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 2.4.2 2.4.3 Situao do clculo das notas de um aluno . . . . . . . . . . . . . . . . . . . Situao do clculo e consulta do IMC de uma pessoa . . . . . . . . . . . . Situao sobre manipulao de pontos no plano cartesiano . . . . . . . . . .
ii

Linguagem de Programao I 2.4.4 2.4.5 2.5 Situao sobre cadastro de produtos no supermercado . . . . . . . . . . . . . Situao sobre gerenciamento de contas bancrias . . . . . . . . . . . . . . 23 24 26 26 27 27 28 29 30 32 34 36 39 40 40 41 43 43 43 46 46 48 52 52 53 56 58 59 62 62 63 65 68

Exemplos de utilizao dos Registros . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 2.5.2 2.5.3 Aluno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Produto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pontos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.6

Exerccios resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 Programa do clculo de mdias de alunos . . . . . . . . . . . . . . . . . . . Problema do clculo e consulta do IMC de uma pessoa . . . . . . . . . . . . Problema de pontos no plano cartesiano . . . . . . . . . . . . . . . . . . . . Problema sobre cadastro de produtos no supermercado . . . . . . . . . . . . Problema sobre gerenciamento de contas bancrias . . . . . . . . . . . . . .

2.7 2.8

Inicializando registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Composio de Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8.1 2.8.2 Tringulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Informao Pessoal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.9

Comparao entre Arranjo e Registro . . . . . . . . . . . . . . . . . . . . . . . . .

2.10 Recapitulando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.11 Atividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Ponteiros e Alocao Dinmica de Memria 3.1 3.2 3.3 Armazenamento de dados no computador . . . . . . . . . . . . . . . . . . . . . . . Denio de ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ponteiros em funes ou sub-rotinas . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 3.3.2 3.4 4 Contextualizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.2 Passagem de parmetros em funes: passagem por valor vs passagem por referncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Atividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Alocao Dinmica de Memria 4.1 4.2 3.4.2 Alocao dinmica de memria . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.3 Arrays dinmicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 4.2.2 4.2.3 4.3 3.4.3.1 Vetores dinmicos . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.3.2 Matrizes dinmicas . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.4 Registros (estruturas) dinmicas . . . . . . . . . . . . . . . . . . . . .

Atividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

iii

Linguagem de Programao I 5 Respostas das atividades 5.1 5.2 Captulo 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Captulo 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 70 70

ndice Remissivo

72

iv

Linguagem de Programao I

Prefcio
TODO.

Pblico alvo
O pblico alvo desse livro so os alunos de Licenciatura em Computao, na modalidade distncia 1 . Ele foi concebido para ser utilizado numa disciplina de Linguagem de Programao I, no segundo semestre do curso.

Como voc deve estudar cada captulo


Leia a viso geral do captulo Estude os contedos das sees Realize as atividades no nal do captulo Verique se voc atingiu os objetivos do captulo NA SALA DE AULA DO CURSO Tire dvidas e discuta sobre as atividades do livro com outros integrantes do curso Leia materiais complementares eventualmente disponibilizados Realize as atividades propostas pelo professor da disciplina

Caixas de dilogo
Nesta seo apresentamos as caixas de dilogo que podero ser utilizadas durante o texto. Conra os signicados delas.

Nota Esta caixa utilizada para realizar alguma reexo.


1 Embora ele tenha sido feito para atender aos alunos da Universidade Federal da Paraba, o seu uso no se restringe a esta universidade, podendo ser adotado por outras universidades do sistema UAB.

Linguagem de Programao I

Dica Esta caixa utilizada quando desejamos remeter a materiais complementares.

Importante Esta caixa utilizada para chamar ateno sobre algo importante.

Cuidado Esta caixa utilizada para alertar sobre algo que exige cautela.

Ateno Esta caixa utilizada para alertar sobre algo potencialmente perigoso.

Os signicados das caixas so apenas uma referncia, podendo ser adaptados conforme as intenes dos autores.

Vdeos
Os vdeos so apresentados da seguinte forma:

Figura 1: Como baixar os cdigos fontes: http://youtu.be/Od90rVXJV78


Nota Na verso impressa ir aparecer uma imagem quadriculada. Isto o qrcode (http://pt.wikipedia.org/wiki/C%C3%B3digo_QR) contendo o link do vdeo. Caso voc tenha um celular com acesso a internet poder acionar um programa de leitura de qrcode para acessar o vdeo. Na verso digital voc poder assistir o vdeo clicando diretamente sobre o link ou acionando o play (na verso em HTML).

vi

Linguagem de Programao I

Compreendendo as referncias
As referncias so apresentadas conforme o elemento que est sendo referenciado: Referncias a captulos Prefcio [v], Captulo 5 [70] Referncias a sees Como voc deve estudar cada captulo [v], Caixas de dilogo [v]. Referncias a imagens e tabelas Figura 3 [x] Tabela 1 [ix]
Nota Na verso impressa, o nmero que aparece entre chaves [ ] corresponde ao nmero da pgina onde est o contedo referenciado. Nas verses digitais do livro voc poder clicar no link da referncia.

Cdigos e comandos
Os cdigos ou comandos so apresentados com a seguinte formao: cc -S helloworld.c No exemplo a seguir, temos outra apresentao de cdigo fonte. Desta vez de um arquivo helloworld.c, que se encontra dentro do diretrio livro/capitulos/code/cap1. O diretrio cap1 indica o captulo onde o cdigo ser apresentado. Cdigo fonte code/cap1/helloworld.c Hello world em C
/* Hello World program */ #include<stdio.h> // 1x

int main() { printf("\nHello World!\n"); return 0; }

// 2x imprime "Hello Word" na tela.

Dica Nas verses digitais do livro voc poder clicar no nome do arquivo indicado em Cdigo fonte para acessar a verso mais nova do arquivo, atravs da internet. Na seo Baixando os cdigos fontes [viii] apresentado como baixar os cdigos do livro.

vii

Linguagem de Programao I

Baixando os cdigos fontes


Existem duas formas de acessar os cdigos fontes contidos neste livro. Acesso on-line individual Voc pode acessar individualmente os arquivos deste livro pelo endereo: https://github.com/edusantana/linguagem-de-programacao-i-livro/tree/master/livro/capitulos/code. Baixando todos os cdigos Voc tambm pode baixar o cdigo fonte do livro inteiro, que contm todos os cdigos mencionados no livro. Existem duas formas de baixar o cdigo inteiro, atravs de um arquivo zip ou clonando o repositrio. Arquivo zip https://github.com/edusantana/linguagem-de-programacao-i-livro/archive/master.zip. Depois de baixar o arquivo, descompacte-o. Clonando o repositrio Use o comando: git clone https://github.com/edusantana/linguagem-de-programacao-ilivro

Figura 2: Como baixar os cdigos fontes: http://youtu.be/Od90rVXJV78


Nota Independente do mtodo utilizado para acessar os arquivos, os cdigos fontes esto organizados por captulos no diretrio livro/capitulos/code.

Ateno Os cdigos acessados por estes mtodos so referentes verso mais nova do livro (em produo). possvel que eles sejam diferentes da verso do livro que voc esteja lendo. Para baixar os cdigos de uma verso especca troque a palavra master no link para uma verso desejada, exemplo: v0.2.0.

Dica Para manter os cdigos atualizados em sua mquina, clone o repositrio e em seguida utilize o mando git pull para baixar as atualizaes do repositrio.

viii

Linguagem de Programao I

Compilando e executando os arquivos


A forma mais simples e compilar e executar os arquivos do livro, entrando no diretrio do captulo e digitando o seguinte comando make: Comandos para compilar os programas do captulo cd livro/capitulos/code/cap1 make Comando para executar o programa helloworld ./helloworld Comando para apagar todos os programas compilados make clean

Contribuindo com o livro


Voc pode contribuir com a atualizao e correo deste livro. A tabela a seguir resume os mtodos de contribuies disponveis: Tabela 1: Mtodos para contribuio do livro Mtodo de contribuio

Habilidades necessrias

Descrio

Inscrio no site do github Issue track Preenchimento de um formulrio

Consiste em acessar o repositrio do livro e submeter um erro, uma sugesto ou uma crtica atravs da criao de um Issue. Quando providncias forem tomadas voc ser noticado disso.

Submisso de correo

Realizar fork de projetos Atualizar texto do livro Realizar PullRequest

Consiste em acessar os arquivos fontes do livro, realizar a correo desejada e submet-la para avaliao. Este processo o mesmo utilizado na produo de softwares livres.

Importante Quando for enviar sua contribuio lembre-se de informar qual a verso e pgina do livro que est se referindo.

ix

Linguagem de Programao I Contribuio atravs do Issue track Para contribuir com um erro, sugesto ou crtica atravs de um envio de uma mensagem acesse: https://github.com/edusantana/linguagem-de-programacao-i-livro/issues/new

Figura 3: Exemplo de contribuio atravs do Issue track

Atividades
No nal de cada captulo h uma seo Atividades com exerccios para serem resolvidos. O signicado dos cones relativos aos exerccios so: Resposta disponvel a reposta do exerccio se encontra disponvel no Captulo 5 [70]. Resoluo disponvel a resoluo do exerccio se encontra disponvel.

Nota Voc pode contribuir enviando respostas ou solues dos exerccios.

Baixando a edio mais nova deste livro


Ns estamos constantemente atualizando o nosso material didtico. Todas as verses deste livro encontram-se disponveis para download.

Linguagem de Programao I

Dica Acesse https://github.com/edusantana/linguagem-de-programacao-i-livro/releases para baixar a verso mais nova deste livro.

xi

Linguagem de Programao I

Parte I Contedos programticos

1 / 72

Linguagem de Programao I

Captulo 1 Reviso
O BJETIVOS DO CAPTULO Ao nal deste captulo voc dever ser capaz de: Entender e relembrar os principais conceitos vistos na disciplina Introduo Programao; Ser capaz de utilizar em programas em linguagem C estruturas de controle (estruturas de seleo ou deciso, estruturas de repetio); Ser capaz de elaborar programas em linguagem C que utilizem arrays (vetores, matrizes, etc.) e funes ou sub-rotinas. A Informtica uma rea que se caracteriza por sofrer transformaes em um curto espao de tempo. Isso, principalmente, em decorrncia do surgimento e aprimoramento de novas tecnologias de hardware, de novas tcnicas e paradigmas de desenvolvimento de software e do contnuo desenvolvimento de ferramentas e aplicativos para a Internet. Entretanto, mesmo com todo o avano e rpidas mudanas, ainda preciso ter prossionais com conhecimento em programao de computadores, tanto nos paradigmas mais tradicionais e em programao estruturada e orientada a objeto, quanto nos paradigmas mais modernos como o de programao concorrente. A porta de entrada para o mundo da programao de computadores ainda continua sendo o aprendizado da construo de algoritmos, pois aprender programao de computadores no signica aprender apenas a sintaxe de uma linguagem de programao, mas, principalmente, saber modelar um problema a ser resolvido em uma linguagem computacional. O ciclo de aprendizado se completa quando se usa uma linguagem de programao para exercitar e representar o problema modelado previamente e execut-lo em um computador. Neste captulo sero revisados os principais conceitos vistos na disciplina Introduo Programao, no entanto, no objetivo rever a denio de algoritmo e aspectos bsicos de programao, j que entende-se que estes tpicos j foram abordados na referida disciplina.

1.1

Algoritmos computacionais

Na resoluo de problemas atravs de computadores, a tarefa desempenhada por eles apenas parte do processo de soluo. H outras etapas que no so realizadas pelos computadores. As etapas na soluo de problemas so: i. Entendimento do problema (realizada por pessoas);
2 / 72

Linguagem de Programao I ii. Criao de uma sequncia de operaes (ou aes) que, quando executadas, produzem a soluo para o problema e a traduo para uma linguagem de programao (realizada por pessoas); iii. Execuo dessa sequncia de operaes (realizada pelo computador); iv. Vericao da adequao da soluo (realizada por pessoas). A etapa (i) fundamental para que o programador saiba exatamente o que deve ser resolvido, quais so os requisitos do problema, necessidades do cliente interessado na soluo, dentre outras coisas. Na etapa (ii) feita a modelagem do problema em uma linguagem computacional, ou seja, desenvolvido o algoritmo, e, em seguida, feita a traduo do algoritmo para uma linguagem de programao que seja mais apropriada ao problema. Neste ponto, pode-se perguntar qual a melhor linguagem de programao? A resposta para essa pergunta direta. No existe uma linguagem de programao que seja a melhor para todos os tipos de problemas. A escolha da linguagem depende da natureza do problema, logo, pode-se usar C ou C++ em uma situao e Java em outra, e assim por diante. Com o tempo, o aluno vai ganhando conhecimento e maturidade e ser capaz de saber qual paradigma de programao (estruturado, orientado a objeto, recorrente, . . . ) mais adequado e qual linguagem de programao pertencente ao paradigma escolhido mais apropriada. Nas disciplinas Introduo Programao e Linguagem de Programao I ser estudado o paradigma de programao estruturada. Exemplos de linguagens de programao pertencentes a este paradigma so C, Fortran e Pascal. Na etapa (iii) o algoritmo e/ou programa de computador desenvolvido na etapa anterior executado em um computador gerando uma resposta ou soluo para o problema. A resoluo do problema no acaba aps a execuo do programa pelo computador. preciso avaliar e analisar com calma se a soluo encontrada vivel ou correta. muito comum a ocorrncia de erros na modelagem/entendimento do problema na etapa (i) ou na construo do algoritmo ou programa na etapa (ii). Esses erros geraro como consequncia uma soluo que no est correta. Caso isso acontea, preciso rever as etapas (i) e (ii) com cuidado para que os erros sejam encontrados at que a soluo obtida na etapa (iii) passe a ser correta. Finalmente, perceba que das quatro etapas, apenas um delas executada por um computador. Note tambm que a resoluo de problemas atravs de computadores no inicia com a construo direta do programa ou cdigo em uma linguagem de programao. preciso antes entender e modelar o problema.

1.2

A linguagem de programao C

O C nasceu na dcada de 1970 e teve como inventor Dennis Ritchie no AT&T Bell Labs. Ele derivado de uma outra linguagem: o B, criado por Ken Thompson. O B, por sua vez, veio da linguagem BCPL, inventada por Martin Richards. C uma linguagem de programao genrica que utilizada para a criao de programas diversos como processadores de texto, planilhas eletrnicas, programas para a automao industrial, sistemas operacionais, implementao de protocolos de comunicao, gerenciadores de bancos de dados, programas de projeto assistido por computador, programas para a soluo de problemas da Engenharia, Fsica, Qumica e outras Cincias. C uma linguagem Case Sensitive, isto , letras maisculas e minsculas fazem diferena. Se declararmos uma varivel com o nome soma ela ser diferente de Soma, SOMA, SoMa ou sOmA. Da mesma maneira, os comandos do C if e for, por exemplo, s podem ser escritos em minsculas, caso contrrio, o compilador no ir interpret-los como sendo comandos, mas sim como variveis ou outra estrutura do programa.
3 / 72

Linguagem de Programao I Existe um conjunto de palavras que so reservadas da linguagem e usadas para representar comandos de controle do programa, operadores e diretivas ou bibliotecas. A Tabela 1.1 [4] mostra palavras que so reservadas na linguagem C. Tabela 1.1: Palavras reservadas em C auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

Programas em C tm estrutura exvel. possvel escrever programas desorganizados que funcionam, porm, esses programas so ilegveis e de difcil correo. Por esse motivo, fundamental aprender e utilizar os conceitos e potencialidades da programao estruturada que sero abordados nesta disciplina e na disciplina Introduo Programao.

1.3

Estruturas de dados e estruturas de controle

Um programa de computador contm basicamente dois tipos de estruturas, a saber, as estruturas de dados e as estruturas de controle. As estruturas de dados podem ser entendidas como estruturas que so utilizadas para armazenar e/ou representar as informaes (dados) que so teis para a resoluo ou entendimento do problema e sero utilizados nos programas e algoritmos. Basicamente, h dois tipos de estruturas de dados, a saber, esttica e dinmica. Pode-se entender como estruturas de dados estticas: variveis, arrays unidimensionais (tambm conhecidos como vetores), arrays multidimensionais (tambm conhecidos como matrizes de duas, trs ou mais dimenses), registros (tambm conhecidos como estruturas ou tipos estruturados) e arquivos. So classicadas como estruturas de dados dinmicas: las, pilhas, listas encadeadas, rvores e tabelas de disperso. As estruturas de dados estticas so abordadas neste livro, enquanto que as estruturas de dados dinmicas sero abordadas na disciplina Estrutura de Dados. As estruturas de controle so utilizadas para manipular e controlar as estruturas de dados vistas no pargrafo anterior, ou seja, controlar o uxo de informao, e tambm para controlar as tomadas de deciso dentro de um programa ou algoritmo. Podem ser divididas em trs tipos: estruturas sequenciais, estruturas de seleo ou condicionais, e estruturas de repetio.

1.3.1

Declarao de variveis em C

A linguagem C possui cincos tipos bsicos que podem ser usados na declarao das variveis, a saber, int, float, double, void e char. A partir desses tipos so utilizadas palavras-chaves para qualicar outras variveis. So elas:

4 / 72

Linguagem de Programao I i. short ou long, que se referem ao tamanho ou espao de representao numrica da varivel; ii. signed ou unsigned, que se referem ao tipo denido com ou sem sinal, respectivamente. A Tabela 1.2 [5] mostra os tipos de dados com suas variantes, a faixa de valores numricos que pode representar, o formato para uso nos comandos printf e scanf, e o tamanho em bytes usado para armazenamento na memria. Os bytes so armazenados de forma contnua na memria. O cdigo a seguir ajuda a calcular os s bytes usados como tamanho das variveis que cada computador utiliza para armazenar na memria. Para o inteiro, por exemplo, dependendo do computador pode-se usar 16 ou 32 bits (ou 8*s na Tabela 1.2 [5]). Tabela 1.2: Tipos de dados em C. Tipo Faixa de valores Formato1 Tamanho em bits (aproximado) 8 8 8 8*s 8*s 8*s 16 16 16 32 32 32 32 64 80

char unsigned char signed char int unsigned int signed int short int unsigned short int signed short int long int signed long int unsigned long int float double long double

-128 a +127 0 a +255 -128 a + 127 -28s-1 a +28s-1 0 a (28s - 1 ) -28s-1 a +28s-1 -32.768 a +32.767 0 a 65.535 0 a 65.535 -2.147.483.648 a +2.147.483.647 -2.147.483.648 a +2.147.483.647 0 a + 4.294.967.295 3,4E-38 a + 3,4E+38 1,7E-308 a 1,7E+308 3,4E-4932 a 3,4E+4932

%c %c %c %d %d %d %hd %hu %hd %ld %lu %lu %f %lf %lf

Cdigo fonte code/cap1/tamando_dos_tipos.c Programa para demonstrar os tamanhos dos tipos


#include <stdio.h> #include <stdlib.h> int main(void) { printf ("sizeof (unsigned int) = %d\n", sizeof (unsigned int)); printf ("sizeof (signed int) = %d\n", sizeof (signed int)); printf ("sizeof (short int) = %d\n", sizeof (short int)); system ("pause"); return 0; }
2 Para

uso nos comandos printf e scanf.

5 / 72

Linguagem de Programao I Sada da execuo do programa sizeof (unsigned int) = 4 sizeof (signed int) = 4 sizeof (short int) = 2

1.3.2

Estruturas de controle sequenciais e de deciso

As estruturas sequenciais so as mais simples e se caracterizam por serem sequncias ordenadas de comandos que so executados da maneira como aparecem e sem desvios de execuo, a no ser que exista algum comando especco que cause um desvio de execuo. O Quadro 1.1 Sintaxe geral da estrutura de controle sequencial [6] ilustra a sintaxe geral de estruturas sequenciais. Dependendo do problema em anlise, talvez seja preciso seguir caminhos diferentes dependendo do teste de uma condio. As estruturas de seleo ou deciso permitem que um grupo de comandos seja executado de acordo com a aceitao ou no de certas condies. Uma condio lgica (boolena) testada e, dependendo do resultado (verdadeiro ou falso), um determinado caminho seguido dentro do programa. Pode-se ter dois tipos de estrutura de deciso, a saber, deciso simples e deciso mltipla. O Quadro 1.2 Sintaxe geral da estrutura de controle de seleo simples [6] apresenta a sintaxe geral da estrutura de controle de seleo simples. Na opo 1, tem-se o teste da condio e, caso seja verdadeira, o bloco de comando 1 executado. Caso seja falsa, sero executados os comandos aps o fechamento da chave. Na opo 2, tem-se o teste da condio e, caso seja verdadeira, o bloco de comando 1 executado, caso contrrio, o bloco de comando 2 executado. Note que os blocos de comandos so separados por chaves. Sintaxe geral da estrutura de controle sequencial Comando1; Comando2; Comando3; ... Sintaxe geral da estrutura de controle de seleo simples Opo 1:
if (condio){ // bloco de comandos 1; }

Opo 2:
if (condio){ // bloco de comandos 1; } else { // bloco de comandos 2; }

H problemas em que preciso testar vrias condies (como pode ser visto em Sintaxe geral da estrutura de seleo composta [7]). O funcionamento da estrutura composta simular ao da seleo
6 / 72

Linguagem de Programao I simples. Caso a condio 1 seja verdadeira, executa-se o bloco de comandos 1; seno (else) a condio 2 testada e, se for verdadeira, executa-se o bloco de comandos 2; e assim por diante, at ser testada a ltima condio.
Importante Sempre que voc precisar executar um bloco de instrues, utilize as chaves para delimitar o incio e o m deste bloco.

Sintaxe geral da estrutura de seleo composta


if (condio1) { // bloco de comandos 1; } else if (condio2) { // bloco de comandos 2; } else if (condio3) { // bloco de comandos 3; } // ... else if (condioN) { // bloco de comandos N; } else { // bloco de comando default; }

Importante O bloco de comandos default pode ser utilizado para dar uma mensagem de alerta ao usurio dizendo que todas as condies foram testadas e nenhuma delas foi verdadeira.

1.3.3

Estruturas de repetio

Uma estrutura de repetio utilizada quando se deseja repetir um trecho do programa ou at mesmo o programa inteiro. O nmero de repeties pode ser um nmero xo ou estar relacionado a uma condio denida pelo programador. Dessa maneira, h trs tipos de estruturas de repetio que podem ser utilizadas para cada situao.
1.3.3.1 Estrutura de repetio para um nmero denido de repeties (estrutura for )

utilizada quando se sabe o nmero de vezes que um trecho do programa deve ser repetido. Esta estrutura chamada em linguagem C de for. A sintaxe geral do comando for pode ser vista a seguir: Sintaxe geral da estrutura de repetio for
7 / 72

Linguagem de Programao I

for(i=valor inicial; condio de parada; incremento/decremento de i){ // bloco de comandos }

A primeira parte atribui um valor inicial varivel i, que chamada de contador e tem a funo de controlar o nmero necessrio de repeties. A condio de parada utilizada como critrio para se saber quando deve-se parar o comando de repetio. Quando essa condio assumir o valor falso, o comando for ser encerrado. A terceira parte o incremento ou decremento do contador i e tem a funo de alterar o valor do contador i at que a condio de parada assuma valor falso. Exemplo do comando for
for (j=0; j<10; j++){ // bloco de comandos; }

Nesse exemplo inicialmente atribudo o valor 0 ao contador, varivel j, e depois vai sendo incrementado em uma unidade. A cada valor de j, o bloco de comandos executado. Este processo se repete at que o valor do contador j se torne maior ou igual a 10, fazendo com que a condio j<10 assuma o valor falso. Perceba que nesse exemplo o bloco de comandos ser executado 10 vezes.
1.3.3.2 Estrutura de repetio para um nmero indenido de repeties (estrutura while )

A estrutura de repetio while utilizada principalmente quando o nmero de repeties no conhecido pelo programador. O Quadro 1.3 Sintaxe geral da estrutura de repetio while [8] mostra a sua sintaxe geral. Nessa estrutura, o bloco de comando repetido enquanto a condio for verdadeira e a condio de parada testada logo no incio do comando while, assim, caso ela seja falsa, o bloco de comandos no executado. O while pode tambm ser utilizado em situaes em que se conhece o nmero de repeties. Sintaxe geral da estrutura de repetio while
while(condio){ // bloco de comandos; }

Cdigo fonte code/cap1/while_exemplo.c Uso do while


int z=0; while (z<=3) { printf("Continuo repetindo o comando.\n"); z++; }

Importante Note que o incremento do contador (z++) do exemplo anterior ltimo comando do while.

8 / 72

Linguagem de Programao I
1.3.3.3 Estrutura de repetio para um nmero indenido de repeties e teste no nal da estrutura (estrutura do-while )

Assim como a estrutura while, a estrutura do-while utilizada principalmente quando o nmero de repeties no conhecido pelo programador, a diferena que a condio de parada testada no nal da estrutura, portanto, o bloco de comandos 3 no Quadro 1.4 Sintaxe geral da estrutura de repetio do-while [9] executado pelo menos uma vez. Assim, o menu exibido na tela a primeira vez e, caso o usurio digite uma opo diferente de 1, 2 ou 3, o comando repetido. Perceba que nesse caso o do-while terminar somente quando o usurio escolher uma das opes 1, 2 ou 3. Sintaxe geral da estrutura de repetio do-while
do { // bloco de comandos } while (condio);

Cdigo fonte code/cap1/do_while_exemplo.c Exemplo do do-while


do{ printf ("\n Escolha a fruta pelo numero: \n"); printf ("\t(1)...Mamao\n"); printf ("\t(2)...Abacaxi\n"); printf ("\t(3)...Laranja\n"); scanf("%d", &i); } while ((i<1) || (i>3));

1.3.4

Arrays em C

Um array em C pode ser entendido como uma estrutura de dados composta homognea, ou seja, capaz de armazenar um conjunto de dados do mesmo tipo (inteiros ou reais), que possuem o mesmo identicador (nome) e so alocados de forma contnua na memria. Podem ser de dois tipos, unidimensionais (tambm chamados de vetores) ou multidimensionais (tambm chamados de matrizes de n-dimenses).
1.3.4.1 Arrays unidimensionais ou vetores

Para se declarar um vetor em C, usa-se colchetes logo aps o nome dado ao vetor e, dentro dos colchetes, a quantidade de posies do vetor. A Figura 1.1 [10] mostra um exemplo de denio de vetor. Note que preciso tambm denir o tipo de dado que o vetor ir armazenar (float, double, int, etc.). Neste exemplo foi denido um vetor de float com nome vet e com tamanho de oito posies, dado tambm um exemplo de preenchimento do vetor. Sero ento alocados na memria RAM um espao com 8*sizeof(float) bytes para armazenamento deste vetor.

9 / 72

Linguagem de Programao I

Figura 1.1: Exemplo de denio de um vetor As operaes bsicas que se pode fazer com vetores so: atribuir valores a posies dos vetores, preencher por completo o vetor e mostrar ou imprimir os valores armazenados no vetor. Para atribuir um valor a uma posio do vetor basta fazer:
vet[0]= 3.4; // atribui o valor 3.4 a primeira posio do vetor vet vet[6]= 0.0; // atribui o valor 0.0 a stima posio do vetor vet soma[4]= 28.9; // atribui o valor 28.9 a quinta posio do vetor soma

O preenchimento ou impresso completa de um vetor sempre feito usando-se um comando de repetio para acess-lo. Em geral, usa-se o comando for j que se conhece o tamanho do vetor e, portanto, quantas vezes os comandos sero repetidos. O preenchimento de um vetor como o da Figura 1.1 [10] pode ser feito com um cdigo como:
for(i=0; i<7; i++){ printf("Digite o valor a ser preenchido em vet[%d]. \n", i+1); scanf("%f", &vet[i]); // grava o valor digitado na i-sima posio }

A impresso dos valores armazenados pode ser feita com um cdigo como:
printf("Os valores armazenados no vetor vet so: \n"); for(i=0; i<7; i++){ printf("%0.2f ", vet[i]); }

possvel tambm denir e preencher vetores diretamente da seguinte forma:


float notas[6] = {1.3, 4.5, 2.7, 4.1, 0.0, 100.1};

1.3.4.2

Arrays bidimensionais ou multidimensionais

Um array multidimensional pode ser denido de maneira similar a um vetor, a diferena que deve-se utilizar um ndice para cada dimenso. No caso de vetores foi utilizado apenas um ndice por que o vetor possui apenas uma dimenso. A sintaxe geral ento:
tipo-de-dado nome_do_array [dimenso1][dimenso2]...[dimensoD];

em que: tipo-de-dado corresponde ao tipo de dado (int, float, double, . . . ) a ser armazenado na matriz;

10 / 72

Linguagem de Programao I nome_do_array o identicador ou nome dado matriz; [dimenso1] o tamanho da primeira dimenso da matriz; [dimenso2] o tamanho da segunda dimenso da matriz; [dimensoD] o tamanho da D-sima dimenso da matriz; Em geral usam-se matrizes com duas dimenses, as quais recebem os nomes de linhas e colunas da matriz. A Figura 1.2 [11] mostra um exemplo de como denir uma matriz com 3 linhas e 4 colunas para armazenar nmeros do tipo double.

Figura 1.2: Exemplo de denio de um array bidimensional ou matriz As operaes bsicas que se pode fazer com matrizes so: atribuir valores a posies das matrizes, preencher por completo a matriz e mostrar ou imprimir os valores armazenados na matriz. Para atribuir um valor a uma posio da matriz basta fazer:
// atribui o valor 0.5 a primeira posio de matriz matriz[0][0]= 0.5; // atribui o valor 104 a posio linha 2, coluna 3 de matriz matriz[2][3]= 104;

O preenchimento ou impresso completa de um array sempre feito usando-se comandos de repetio para acessar as dimenses do array. Para cada dimenso usa-se um comando de repetio que, em geral, o comando for. O preenchimento de uma matriz de duas dimenses como a da Figura 1.2 [11] pode ser feito com um cdigo como:
for(i=0; i<3; i++){ for(j=0; j<4; i++){ printf("Digite o valor a ser preenchido em matriz[%d,%d].\n",i,j); scanf("%lf", &matriz[i,j]); // grava na linha i coluna j } }
11 / 72

Linguagem de Programao I A impresso dos valores armazenados pode ser feita com um cdigo como:
printf("Os valores armazenados em matriz so: \n"); for (i=0;i<3;i++){ for (j=0;j<4;j++){ printf (" %lf",matriz[i][j]); } printf ("\n\n"); }

Observe que nos cdigos do preenchimento e impresso da matriz matriz foram utilizados dois comandos de repetio, j que ela bidimensional.

Nota Registros ou estruturas em C e arquivos sero abordados no Captulo 2 [17].

1.4

Estrutura geral de um programa em C

Um programa em C pode ter uma estrutura geral como aparece a seguir:


1 2 3 4 5 6 7 8 9

/* Comentrios gerais explicando o que o programa faz . */ Diretivas de pr-compilao (include, define, uso de < > e " ") Declaraes globais Definio de prottipo de funes ou sub-rotinas usadas no programa int main() { comandos contidos na funo main; // comentrios return 0; } // fim da funo main

A linha 2 representa a incluso das bibliotecas da linguagem, como stdio.h, stdlib.h, math.h, dentre outras, ou bibliotecas criadas pelo prprio programador. A linha 3 representa a denio de declaraes globais, como por exemplo, variveis globais do programa. Em seguida, podem ser includos os prottipos das funes ou sub-rotinas criadas pelo programador e que sero utilizadas no programa. A linha 6 representa o incio da funo main do programa C com os seus comandos delimitados pelas chaves { ... }. Finalmente, aps a funo main, so includos os cdigos das funes ou sub-rotinas denidas na linha 4 e utilizadas no programa. Embora seja simples, essa estrutura geral de um programa em C pode ser utilizada pelo estudante ou programador iniciante para no esquecer partes fundamentais que um programa em C deve conter. Pode-se acrescentar ainda no incio do programa (linha 1) um comentrio geral explicando o que ele faz, qual seu objetivo, que tipo de entrada precisa, que tipo de sada ir gerar, etc.

1.5

Atividades

1. Faa um programa em C que receba o ano de nascimento de uma pessoa e o ano atual, calcule e mostre: (a) a idade da pessoa; e (b) quantos anos ela ter em 2045. O programa deve ser capaz de receber somente valores positivos e maiores do que zero para a idade da pessoa.
12 / 72

Linguagem de Programao I 2. Um supermercado deseja reajustar os preos de seus produtos usando o seguinte critrio: o produto poder ter seu preo aumentado ou diminudo. Para o preo ser alterado (ou seja, ser aumentado ou diminudo), o produto deve atender PELO MENOS uma das linhas da tabela a seguir: Venda mdia mensal (unidades vendidas) Menor que 500 Entre 500 (inclusive) e 1200 Igual ou maior que 1200 Preo atual (R$) < R$ 30,00 > = R$ 30,00 e < R$ 80,00 > = R$ 80,00 % de aumento 10 % 15 % % de diminuio 20 %

Faa um programa em C que receba o preo atual e a venda mdia mensal do produto, calcule e mostre o novo preo. 3. Faa um algoritmo que receba um nmero positivo e maior que zero, calcule e mostre: o nmero digitado ao quadrado, o nmero digitado ao cubo e a raiz quadrada do nmero digitado. 4. Joo Papo-de-Pescador est organizando uma corrida de automveis e precisa de um mtodo para computar os tempos das voltas no circuito. Faa um programa em C que tenha como entrada: i) o nmero de pilotos que disputaro a corrida; ii) os seus respectivos nomes; iii) o nmero de voltas da corrida; iv) e o tempo de todas as voltas para cada piloto. O programa deve imprimir no nal o tempo mdio da volta para cada piloto e o tempo da volta mais rpida da corrida (ou seja, a volta que foi feita no menor tempo) e qual foi o piloto que a fez. 5. Em uma competio de ginstica olmpica, a nota determinada por um painel de seis juzes. Cada um dos juzes atribui uma nota entre zero e dez para o desempenho do atleta. Para calcular a nota nal, a nota mais alta e a nota mais baixa so descartadas e calculada a mdia das quatro notas restantes. Escreva um programa que leia seis notas que devem estar entre zero e dez e, em seguida, calcule a mdia aps o descarte da maior e da menor nota. Faa duas verses desse programa em C: i) usando somente estruturas de seleo e de repetio e sem o uso de vetores; ii) com o uso de vetores e estruturas de seleo e repetio. 6. Analise o algoritmo abaixo e explique o que ele faz. Quais so os valores de LUCROMAX, PREOMAX e INGRESSOSMAX que sero impressos no nal da execuo do algoritmo?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Algoritmo declare PREO, //preo do ingresso em Reais INGRESSOS, //nmero provvel de ingressos vendidos DESPESAS, //despesas com o espetculo LUCRO, //lucro provvel LUCROMAX, //lucro mximo provvel PREOMAX, //preo mximo INGRESSOSMAX: numrico; //nmero mximo de ingressos vendidos LUCROMAX 0; PREO 5; INGRESSOS 120; DESPESAS 200; Enquanto (PREO > 1) { LUCRO INGRESSOS*PREO - DESPESAS; imprima LUCRO, PREO; se (LUCRO LUCROMAX) {

13 / 72

Linguagem de Programao I
LUCROMAX LUCRO; PREOMAX PREO; INGRESSOSMAX INGRESSOS; } INGRESSOS INGRESSOS + 26; PREO PREO - 0,5; } imprima LUCROMAX, PREOMAX, INGRESSOSMAX; fim algoritmo

17 18 19 20 21 22 23 24 25

7. Uma empresa decidiu dar uma graticao de Natal a seus funcionrios baseada no nmero de horas extras e no nmero de horas que o funcionrio faltou ao trabalho. Faa um programa em C que calcule o valor da graticao de Natal. O valor do prmio obtido pela consulta tabela que se segue, na qual a varivel SH calculada da seguinte forma: SH = nmero de horas extras 0,5*(nmero de horas faltadas). SH (em minutos) Maior ou igual a 2200 Entre 1700 (inclusive) e 2200 Entre 1000 (inclusive) e 1700 Entre 500 (inclusive) e 1000 Menor que 500 Graticao (em R$) 600,00 500,00 400,00 300,00 200,00

8. Analise o cdigo abaixo e diga qual o valor que a varivel E ter ao nal da execuo do programa.
#include <stdio.h> #include <stdlib.h> int main(void) { double fat, E; int i, j, n; n = 4; for(i=1; i<=n; i++){ fat=1; for(j=1; j<=n; j++){ fat=fat*j; } E=E+(1/fat); } printf ("O valor da varivel E %lf ", E); return 0; }

9. Faa um programa em C que receba o salrio de um funcionrio e, usando a tabela a seguir, calcule e mostre o seu novo salrio. O programa deve aceitar somente valores positivos e maiores do que zero para o salrio do funcionrio. Faixa Salarial At R$ 500,00 Entre R$ 500,00 e 700,00 (inclusive)
14 / 72

% de aumento 55 % 45 %

Linguagem de Programao I Faixa Salarial Entre R$ 700,00 e 900,00 (inclusive) Entre R$ 900,00 e 1100,00 (inclusive) Entre R$ 1100,00 e 1300,00 (inclusive) Acima de R$ 1300,00 % de aumento 35 % 25 % 15% 5%

10. Analise o cdigo abaixo e diga qual o valor que a varivel S ter ao nal da execuo do algoritmo.
Algoritmo declare fim, i, j, x, exp, num_ter, den, D, fat, S: numrico; num_ter = 3; x = 3; S = 0; D = 1; para (i=1; i<= num_ter; i=i+1) { fim = D; fat = 1; para (j=1; j<= fim; j=j+1) { fat = fat*j; } exp = i+1; se (RESTO(exp/2) == 0){ S = S-(x^(exp))/fat; } seno{ S = S + (x^(exp))/fat; } se (D == 4){ den = -1; } se (D==1){ den = 1; } se (den == 1){ D = D +1; } seno{ D = D - 1; } } imprima S; fim algoritmo

11. Uma agncia bancria possui vrios clientes que podem fazer investimentos com rendimentos mensais conforme a tabela a seguir: Cdigo do tipo de investimento 1 2 3 Nome Poupana Poupana plus Fundos de renda xa
15 / 72

Rendimento mensal % 0,6 % 1,1 % 1,8 %

Linguagem de Programao I Cdigo do tipo de investimento 4 Nome Fundos de renda varivel Rendimento mensal % 2,5 %

Faa um programa em C que tenha como dados de entrada o cdigo do cliente, o cdigo do tipo de investimento e o valor investido. O algoritmo deve calcular e imprimir o rendimento mensal de acordo com o tipo de investimento do cliente. No nal, o algoritmo dever imprimir o total investido por todos os clientes consultados e o somatrio do rendimento mensal pago a todos os clientes consultados. A leitura de clientes pelo algoritmo terminar quando o cdigo do cliente digitado for menor ou igual a 0 (zero).

16 / 72

Linguagem de Programao I

Captulo 2 Registros
O BJETIVOS DO CAPTULO Ao nal deste captulo voc dever ser capaz de: Criar registros em C Analisar problemas e reconhecer os campos necessrios para utilizar nos registros Reconhecer campos identicadores de registros Criar e manipular listas de registros Neste captulos ns iremos estudar sobre Registros. Vamos conhecer a sua utilidade e como declarlos em C. Depois vamos analisar diversas situaes para aprender como o processo de criao de um registro. Sero apresentados alguns programas demonstrando a utilizao dos registros e por m, vamos aprender como compor registros a partir de outros registros. Mas, o que so Registros?

2.1

Denio de registro

Denio de Registro Um Registro um tipo de dado criado pelo usurio, atravs da composio de outros tipos de dados. Ns utilizamos registros quando desejamos criar um tipo de dado para reunir informaes sobre o que desejamos representar. No registro, as informaes so organizadas em campos. Uma analogia de registro pode ser vista quando preenchemos um formulrio. Na Tabela 2.1 [18] ns temos um exemplo de formulrio para cadastrar Clientes. Os campos do formulrio so preenchidos com os dados do cliente que nos interessa registrar. Sabendo as informaes que desejamos registrar sobre um Cliente, ns podemos esquematizar um registro, informando os tipos de dado de cada campo, conforme descrito na Tabela 2.2 [18].

17 / 72

Linguagem de Programao I Tabela 2.1: Formulrio para cadastro de Cliente Nome: Data de Nascimento: CPF:

Telefone para contato: RG:

Tabela 2.2: Representao de um registro Cliente Novo tipo Campo Nome Data de Nascimento Telefone para contato CPF # RG Tipo do campo Textual Numrico Textual Numrico Numrico

Cliente

Relembrando Em nossos programas ns utilizamos varivies para manter as informaes que desejamos manipular. No momento da criao de uma varivel precisamos especicar o tipo de dado que desejamos que ela mantenha, atravs da declarao da varivel. Vamos relembrar como declaramos variveis:

Em pseudocdigo
DECLARE nome_da_variavel: TEXTUAL DECLARE var1,var2,var3: NUMRICO

Em C
char[] nome_da_variavel; double var1,var2,var3;
Quando especicamos mais de uma varivel separadas por vrgula, assumimos que todas elas possuem o mesmo tipo.

Na prxima seo, veremos como a sintaxe para criao de registros, em pseudocdigo e em C.


Importante Embora, na prtica, o uso de registro geralmente esteja associado a persistncia de dados, sempre que mencionarmos cadastrar neste captulo, estamos nos referindo a manter os dados em memria para consulta posterior. Em um sistema real, geralmente existe alguma forma de persistncia dos dados atravs de arquivos ou banco de dados caso contrrio, os dados seriam perdidos.

18 / 72

Linguagem de Programao I

2.2

Sintaxe para criao de registros

Agora que temos o entendimento que um registro um tipo de dado, vamos conhecer a sintaxe para especic-lo: Sintaxe em pseudocdigo para criar registro
REGISTRO nome_do_registro // Declaraes dos campos REGISTRO_FIM

Sintaxe em C para criar registro


typedef struct { // Declaraes dos campos } nome_do_registro;

Quando criamos um novo tipo de dado precisamos nome-lo, para podermos referenci-lo mais tarde. Nestas notaes, nome_do_registro o nome do tipo de dado registro que ser criado. As Declaraes dos campos denem os campos que compem o registro. Esta composio car evidente nas prximas sees, onde iremos criar e manipular vrios registros. Aps a denio do novo tipo de dado registro, uma declarao de varivel com este tipo realizada da forma usual: Declarao de varivel do tipo criado em pseudocdigo
DECLARE variavel_nome: nome_do_registro

Declarao de varivel do tipo criado em C


nome_do_registro variavel_nome;

2.3

Identicadores de registros

Antes de comearmos a especicar os registros, vamos primeiro entender a necessidade de identicar unicamente um registro.
Importante A palavra registro pode ser empregada em dois contextos diferentes.

Tipo de dado
o tipo de dado, conforme apresentado na denio de Registro.

Instncia do registro
Utilizando a analogia do formulrio, equivaleria s chas dos clientes. Cada cha preenchida equivale a uma instncia ou um registro daquele tipo. Por convenincia, sempre que utilizarmos a palavra registro para indicar instncia do tipo, ela ser grafada em itlico.

19 / 72

Linguagem de Programao I Identicadores de registros so campos nos registros que os identicam e diferenciam um registro de qualquer outro. No registro indicado na tabela Tabela 2.2 [18], como podemos diferenciar um cliente cadastrado de outro? Qual campo identica um cliente? Seria o nome? Data de Nascimento? Telefone? CPF ou RG? Neste caso, preferimos utilizar o CPF, pois sabemos que duas pessoas diferentes no podem possuir o mesmo nmero de CPF. Em nosso livro, os campos identicadores esto marcados com #.
Nota Os identicadores costumam ser do tipo inteiro, pois a comparao de inteiros mais rpida do que a comparao textual.

Na prxima seo, faremos anlises em algumas situaes, caso voc no tenha compreendido o que so campos identicadores ter outra oportunidade.

2.4

Anlise para criao de Registros

Nesta seo mostramos o processo de criao de um Registro em diversas situaes diferentes. Em cada situao apresentada faremos a seguinte anlise: Determinar o tipo de registro que vamos criar; Especicar quais sero os campos do registro, com os seus respectivos tipos; Indicar qual o campo identicador (#), caso exista; Apresentar o cdigo de criao do Registro em Pseudocdigo e em C.

2.4.1

Situao do clculo das notas de um aluno

Em uma disciplina onde os alunos possuem duas notas, e precisamos registrar e calcular as mdias de todos eles, como seria um registro para representar esta situao? Nome do Registro Aluno Campos Obviamente vamos precisar guardar duas notas para cada aluno. Vamos precisar guardar a mdia tambm? No, uma vez que temos as duas notas registradas, sempre que desejarmos consultar a mdia poderemos calcul-las. O nome do aluno seria uma informao til? Sem dvidas! Ser importante registrar o nome do aluno pois poderamos imprimir uma lista com os nomes, notas e mdias de cada aluno. A matrcula do aluno importante tambm? Ns poderamos suprimir a matrcula do aluno, mas qual seria a consequncia disso? Por exemplo, na lista de notas poderia conter apenas os nomes, notas e mdias. Mas o que aconteceria se tivssemos dois alunos com o mesmo nome? Ns precisamos de um informao extra para identicar e diferenciar um aluno do outro. Com este intuito, vamos optar por registrar a matrcula tambm. O nome da disciplina importante? Neste caso no, pois estamos nos limitando aos alunos e suas notas.

20 / 72

Linguagem de Programao I Novo tipo Aluno Campo matricula # nome nota1 nota2 Tipo do campo Numrico Textual Numrico Numrico

Registro em Pseudocdigo
REGISTRO Aluno matricula: NUMRICO nome: TEXTO nota1, nota2: NUMRICO FIM_REGISTRO

Cdigo fonte code/cap2/reg_aluno.c Registro de Aluno em C


typedef struct { int matricula; char nome[100]; float nota1; float nota2; } Aluno;

Nota At agora voc teve diculdade para entender esta anlise? Voc compreendeu a necessidade da utilizao de matrcula como campo identicador? Concordou com os tipos de dados utilizados para cada varivel?

2.4.2

Situao do clculo e consulta do IMC de uma pessoa

Nesta situao desejamos criar um sistema para cadastrar pessoas e em seguida consultar o IMC delas. Nome do Registro Pessoa Campos Para o clculo do IMC so necessrias duas informaes: a altura e o peso. Novamente, o nome da pessoa uma informao relevante, pois vamos imprimir o IMC calculado junto com o nome. Mas como realizar a consulta? Aps o cadastro realizado de algumas pessoas, qual o parmetro de busca que iremos utilizar para encontrar a pessoa certa? Poderamos utilizar o nome completo da pessoa para encontr-la. Mas digitar o nome todo enfadonho. Poderamos utilizar apenas o primeiro nome para busca, mas ento teramos que apresentar um lista com todas as pessoas com aquele primeiro nome e selecionar a pessoa correta entre elas.1 Se cadastrarmos o CPF da pessoa poderamos consult-la mais tarde informando apenas ele, simplicando a busca. Por ltimo, como algumas tabelas do IMC apresentam os dados categorizados por sexo, vamos registr-lo tambm.
1A

opo de utilizar o primeiro nome iria complicar o algortmo da busca.

21 / 72

Linguagem de Programao I Novo tipo Campo nome peso altura cpf # sexo Tipo do campo Textual Numrico Numrico Numrico Textual

Pessoa

Registro em Pseudocdigo
REGISTRO Pessoa nome, sexo: TEXTO peso, altura, cpf: NUMRICO FIM_REGISTRO

Cdigo fonte code/cap2/reg_pessoa.c Registro de Pessoa em C


typedef struct{ char nome[100]; char sexo; // m: masculino, f: femino float peso; float altura; long long cpf; } Pessoa;

Nota Mais uma vez, embora nosso problema no tenha indicado os campos que necessita, fomos capazes de deduzir alguns. Aqui no h certo ou errado, cada um pode realizar sua anlise e chegar a resultados diferentes. Voc concorda com os tipos de dados apresentados aqui? No achou estranho cpf ser do tipo long long? Voc declararia sexo com outro tipo, diferente de char?

cpf
Declaramos ele como long long pois os tipos long e int no armazenam nmeros na ordem de 11 dgitos.

sexo
Optamos por utilizar o tipo char para simplicar comparaes, caso sejam necessrias. Poderamos declar-lo do tipo int, fazendo uma correspondncia de valores: 1=Feminino e 2=Masculino. Ou ainda poderamos utilizar char[] e registrar o texto completo: Feminino ou Masculino.

2.4.3

Situao sobre manipulao de pontos no plano cartesiano

Nesta situao desejamos criar um sistema matemtico para manipular pontos no plano cartesiano. Nome do Registro Ponto
22 / 72

Linguagem de Programao I Campos Quais as informaes que precisamos para registrar um ponto no plano cartesiano? Apenas suas coordenadas (x,y). Existe mais alguma informao que desejamos registrar? O ponto possui um lugar associado a ele, como um regio geogrca? No! Os pontos sero plotados com coloraes especcas? No!. Para identicar os campos identicadores nos perguntamos: se dois pontos possuem as mesmas coordenadas eles so os mesmos? Sim! Conclumos que, neste caso, as duas coordenadas juntas identicam o ponto. Novo tipo Ponto Campo x# y# Tipo do campo Numrico Numrico

Registro em Pseudocdigo
REGISTRO Ponto x, y: NUMRICO FIM_REGISTRO

Cdigo fonte code/cap2/reg_ponto.c Registro de Ponto em C


typedef struct{ int x; int y; } Ponto;

Nota Neste registro ns temos uma novidade: estamos utilizando dois campos como identicadores simultaneamente. As vezes um nico campo no suciente para identicar um registro. Neste caso, ca evidente que dois pontos so iguais se, e somente se, eles possurem os mesmo valores para o par (x,y). E em relao aos tipos de dados das coordenadas? Voc teria utilizado outro tipo, diferente de int, como float ou double? Mais uma vez, aqui no h certo ou errado, ns optamos por int apenas por ser mais simples fornecer coordenadas em inteiro.

2.4.4

Situao sobre cadastro de produtos no supermercado

Nesta situao desejamos criar um sistema, para um supermercado, que cadastre produtos e seus preos. Nome do Registro Produto Campos Para registrar um produto vamos precisar do seu nome e o seu preo. Mas como identicar um produto cadastrado? Quando vamos no supermercado e compramos alguma mercadoria
23 / 72

Linguagem de Programao I no peso, o caixa do supermercado precisa fornecer um cdigo para cadastrar o produto pesado. Geralmente ele utiliza uma tabela, onde h o nome do produto e o seu cdigo. Para a nossa aplicao vamos utilizar este mesmo cdigo para identicar unicamente cada produto. Novo tipo Produto Campo nome preco codigo # Tipo do campo Textual Numrico Numrico

Registro em Pseudocdigo
REGISTRO Produto codigo: NUMRICO nome: TEXTUAL preco: NUMRICO FIM_REGISTRO

Cdigo fonte code/cap2/reg_protudo.c Registro de Produto em C


typedef struct { long codigo; char nome[100]; float preco; } Produto;

Nota Neste registro tivemos contato com um provvel campo identicador universal, o codigo. Geralmente, quando nos deparamos com um campo cdigo, ele ser utilizado como o identicador.a
aA

no ser quando o cdigo for utilizado para designar uma senha.

2.4.5

Situao sobre gerenciamento de contas bancrias

Nesta situao desejamos criar um sistema bancrio para gerenciar clientes e suas contas bancrias. Nomes dos Registros Cliente e Conta. Campos O nome do cliente uma informao relevante. O CPF poder ser utilizado para diferenciar clientes com o mesmo nome. Como identicar a conta do cliente? Cada conta poderia ter um nmero de conta nico, que serviria para identicar a conta do cliente. Cada conta ter um saldo, que ser gerenciada pelo sistema. Como cada cliente pode possuir mais de uma conta bancria, junto com a conta deveremos registrar qual cliente o dono dela. Vamos utilizar o CPF do cliente na conta para identicar o seu dono.

24 / 72

Linguagem de Programao I Novo tipo Conta Campo numero_da_conta # saldo cpf_do_cliente Tipo do campo Numrico Numrico Numrico

Registro em Pseudocdigo
REGISTRO Conta numero_da_conta, cpf_do_cliente, saldo: NUMRICO FIM_REGISTRO

Cdigo fonte code/cap2/reg_conta.c Registro de Conta em C


typedef struct { long numero_da_conta; long cpf_do_cliente; double saldo; } Conta;

Novo tipo Cliente

Campo nome cpf #

Tipo do campo Textual Numrico

Registro em Pseudocdigo
REGISTRO Cliente cpf: NUMRICO nome: TEXTUAL FIM_REGISTRO

Cdigo fonte code/cap2/reg_cliente.c Registro de Cliente em C


typedef struct { char nome[256]; long long cpf; } Cliente;

Nota Nesta situao temos outras novidades: a criao de dois Registros e utilizao de um campo para registrar o relacionamento entre os dois registros.a Percebam que cpf o campo identicador de Cliente. Para identicar que uma conta de um determinado cliente, utilizamos o campo identicador de cliente na conta. Esta uma estratgia muito importante para especicar relacionamento entre registros, certique-se que compreendeu-a antes de prosseguir.
entre registros um assunto que est fora do escopo de uma disciplina de Introduo Programao, voc estudar este tpico numa disciplina de Banco de Dados.
a Relacionamento

25 / 72

Linguagem de Programao I

2.5

Exemplos de utilizao dos Registros

Nesta seo veremos alguns exemplos que demonstram a utilizao de registros. Nestes exemplos voc ir aprender: 1. Como atribuir e acessar valores aos campos do registro; 2. Como atribuir valores de texto aos campos do registro; 3. Como ler valores da entrada e atribui-los aos campos; 4. Como declarar um arranjo de registros; 5. Como acessar um campo num arranjo de registros.

2.5.1

Aluno

Exemplo de utilizao do registro Aluno. Cdigo fonte code/cap2/reg_aluno_exemplo.c Exemplo de utilizao do registro Aluno
#include <stdio.h> #include <string.h> typedef struct { int matricula; char nome[100]; float nota1; float nota2; } Aluno;

int main(){ Aluno aluno; aluno.matricula = 201328; // 1x strncpy(aluno.nome, "Maria Bonita", sizeof(aluno.nome)); // 2x aluno.nota1 = 8.0; // 3x aluno.nota2 = 9.0; // 4x printf("\n%d %s %1.2f %1.2f", aluno.matricula, aluno.nome, // 5x aluno.nota1, aluno.nota2); // 6x getchar(); return 0; }
x , 1x , 3x , 4x Como

atribuir valores aos campos do registro. Voc j estudou a funo strcpy antes.

x , 2x Como atribuir valores de texto aos campos do registro. x , 6x Como

acessar valores atribudos aos campos do registro.


26 / 72

Linguagem de Programao I Resultado ao simular a execuo do programa


201328 Maria Bonita 8.00 9.00

2.5.2

Produto

Exemplo de utilizao do registro Produto. Cdigo fonte code/cap2/reg_produto_exemplo.c Exemplo de utilizao do registro Produto em C
#include <stdio.h> typedef struct { long codigo; char nome[100]; float preco; } Produto; int main(){ Produto p; scanf("%ld %s %f", &p.codigo, p.nome, &p.preco); // 1x if (p.preco < 4) printf("\nProduto em promocao: %s R$ %1.2f", p.nome, p.preco); else printf("\nProduto cadastrado."); getchar(); return 0; }
x

Como ler da entrada os valores e atribu-los aos campos. Consulte a documentao de scanf (ou fscanf) para conhecer a sintaxe de leitura e converso dos dados. Percebam a ausncia de & antes do campo nome.

Resultado ao simular a execuo do programa


Produto em promocao: banana R$ 3.99

Ateno Percebam que quando atribumos um valor de texto aos campos do tipo char[], ns suprimimos o &. Isto correu com o campo aluno.nome em strncpy e p.nome no scanf.

2.5.3

Pontos

Exemplo de utilizao do registro Ponto com Arranjo. Cdigo fonte code/cap2/reg_ponto_exemplo.c Exemplo de utilizao do Registro Ponto
27 / 72

Linguagem de Programao I

#include <stdio.h> #include <string.h> typedef struct{ int x; int y; } Ponto; #define QUANTIDADE_DE_PONTOS 3 // 1x int main(){ Ponto pontos[QUANTIDADE_DE_PONTOS]; // 2x pontos[0].x = -4; pontos[0].y = 7;// 3x pontos[1].x = 2; pontos[1].y = -9;// 4x pontos[2].x = 5; pontos[2].y = 3;// 5x for (int i = 0; i < QUANTIDADE_DE_PONTOS ; i++){ if(pontos[i].y > 0) printf("\nPonto acima da reta: (%d,%d)", pontos[i].x, pontos[i].y); } getchar(); return 0; }

x x

Declarao de constante que denir o tamanho do arranjo. Como declarar um arranjo de registros do tipo Ponto, com o tamanho denido pela constante QUANTIDADE_DE_PONTOS. acessar um campo em arranjo de registros. Cada posio, do arranjo contm um registro. Voc pode acessar as posies do arranjo com a mesma sintaxe: [ndice].

x , 4x , 5x Como

Resultado ao simular a execuo do programa


Ponto acima da reta: (-4,7) Ponto acima da reta: (5,3)

2.6

Exerccios resolvidos

Nesta seo teremos a especicao de diversos problemas. Para cada um deles iremos escrever um pseudocdigo que resolva o problema descrito, utilizando o recurso de Registros. Em seguida, iremos implementar um programa em C.

28 / 72

Linguagem de Programao I

2.6.1

Programa do clculo de mdias de alunos

Escrever um programa que cadastre o nome, a matrcula e duas notas de vrios alunos. Em seguida imprima a matrcula, o nome e a mdia de cada um deles. Pseudocdigo do programa
REGISTRO Aluno matricula: NUMRICO nome: TEXTO nota1, nota2: NUMRICO FIM_REGISTRO QUANTIDADE_DE_ALUNOS = 3 DECLARA alunos: Aluno[QUANTIDADE_DE_ALUNOS] PARA i=0 AT QUANTIDADE_DE_ALUNOS FAA LEIA alunos[i].nome LEIA alunos[i].matricula LEIA alunos[i].nota1 LEIA alunos[i].nota2 FIM_PARA PARA i=0 AT QUANTIDADE_DE_ALUNOS FAA ESCREVA alunos[i].matricula ESCREVA alunos[i].nome ESCREVA (alunos[i].nota1 + alunos[i].nota2)/2 1x FIM_PARA

Imprime a mdia calculada.

Cdigo fonte code/cap2/calculo_das_medias.c Programa em C


#include <stdio.h> typedef struct { int matricula; char nome[100]; float nota1; float nota2; } Aluno;

#define QUANTIDADE_DE_ALUNOS 3 int main(){ Aluno alunos[QUANTIDADE_DE_ALUNOS]; printf("Dados: nome(sem espacos), matricula, nota1, nota2\n"); for(int i=0; (i < QUANTIDADE_DE_ALUNOS); i++){ printf("\nInforme os dados do aluno(%i): ",i+1);
29 / 72

Linguagem de Programao I
scanf("%s %i %f %f",alunos[i].nome, &alunos[i].matricula, &alunos[i].nota1, &alunos[i].nota2); } printf("\nMatricula\tNome\tMedia\n"); for(int i=0; (i < QUANTIDADE_DE_ALUNOS); i++){ printf("%i\t%s\t%1.2f\n",alunos[i].matricula,alunos[i].nome, (alunos[i].nota1 + alunos[i].nota2)/2); } getchar(); return 0; }

Resultado ao simular a execuo do programa


Dados do aluno: nome(sem espacos), matricula, nota1, nota2 Informe os dados do aluno(1): Jesuno 2887399 6.0 7.5 Informe os dados do aluno(2): Maria 2887398 7.0 9.0 Informe os dados do aluno(3): Virgulino 2887400 10.0 8.0 Matricula Nome Media 2887399 Jesuno 6.75 2887398 Maria 8.00 2887400 Virgulino 9.00

2.6.2

Problema do clculo e consulta do IMC de uma pessoa

Escrever um programa que cadastre o nome, a altura, o peso, o cpf e sexo de algumas pessoas. Com os dados cadastrados, em seguida localizar uma pessoa atravs do seu CPF e imprimir o seu IMC. Pseudocdigo do programa
REGISTRO Pessoa nome, sexo: TEXTO peso, altura, cpf: NUMRICO FIM_REGISTRO QUANTIDADE_DE_PESSOAS = 3 PARA i=0 AT QUANTIDADE_DE_PESSOAS FAA LEIA pessoas[i].nome LEIA pessoas[i].altura LEIA pessoas[i].peso LEIA pessoas[i].cpf LEIA pessoas[i].sexo FIM-PARA DECLARA cpf_localizador: NUMRICO LEIA cpf_localizador 1x
x 2 PARA i=0 AT QUANTIDADE_DE_PESSOAS FAA SE pessoas[i].cpf == cpf_localizador ENTO 3x

30 / 72

Linguagem de Programao I
ESCREVE pessoas[i].nome ESCREVE pessoas[i].sexo // IMC = peso / (altura * altura) ESCREVE pessoas[i].peso / (pessoas[i].altura * pessoas[i].altura) FIM-PARA
1

O ler o campo identicador de Pessoa (CPF). pelo registro Pessoa identicado pelo CPF lido.

x , 3x Pesquisa

Cdigo fonte code/cap2/imc_calculo.c Programa em C


#include <stdio.h> typedef struct{ char nome[100]; char sexo; // m: masculino, f: femino float peso; float altura; long long cpf; } Pessoa; #define QUANTIDADE_DE_PESSOAS 3 int main(){ Pessoa pessoas[QUANTIDADE_DE_PESSOAS]; printf("Campos: nome, altura, peso, cpf, sexo\n"); for(int i=0; (i < QUANTIDADE_DE_PESSOAS); i++){ printf("\nInforme os dados da pessoa(%i): ",i+1); scanf("%s %f %f %Lu %c",pessoas[i].nome, &pessoas[i].altura, &pessoas[i].peso, &pessoas[i].cpf, &pessoas[i].sexo); } printf("\nInforme o CPF da pessoa: "); long long cpf_localizador; scanf("%Lu",&cpf_localizador); // 1x printf("\nSexo\tNome\tIMC"); for(int i=0; (i < QUANTIDADE_DE_PESSOAS); i++){ // 2x if (cpf_localizador == pessoas[i].cpf){ // 3x float imc = pessoas[i].peso / (pessoas[i].altura * pessoas[i].altura); printf("\n%c\t%s\t%1.2f\n",pessoas[i].sexo, pessoas[i].nome, imc); break; } } getchar(); return 0; }
31 / 72

Linguagem de Programao I
1

O ler o campo identicador de Pessoa (cpf). pelo registro Pessoa identicado pelo CPF lido.

x , 3x Pesquisa

Resultado ao simular a execuo do programa


Campos: nome, altura, peso, cpf, sexo Informe os dados da pessoa(1): Jesuno 1.82 79 48755891748 m Informe os dados da pessoa(2): Maria 1.66 52 72779162201 f Informe os dados da pessoa(3): Virgulino 1.75 80 71443626406 m Informe o CPF da pessoa: 72779162201 Sexo Nome IMC f Maria 18.87

2.6.3

Problema de pontos no plano cartesiano

Escrever um programa que leia 5 pontos. Em seguida imprima qual o ponto mais prximo do primeiro ponto lido. Pseudocdigo do programa
REGISTRO Ponto x, y: NUMRICO FIM_REGISTRO QUANTIDADE_DE_PONTOS = 5 PARA i=0 AT QUANTIDADE_DE_PONTOS FAA LEIA p[i].x LEIA p[i].y FIM_PARA menor_distancia_ao_quadrado = MAIOR_INTEIRO 1x ponto_mais_proximo = 1 2x PARA i=1 AT QUANTIDADE_DE_PONTOS FAA distancia_ao_quadrado = (pontos[i].x-pontos[0].x)* (pontos[i].x-pontos[0].x)+(pontos[i].y-pontos[0].y)* (pontos[i].y-pontos[0].y) 3x SE distancia_ao_quadrado < menor_distancia_ao_quadrado ENTO 4x ponto_mais_proximo = i 5x menor_distancia_ao_quadrado = distancia_ao_quadrado 6x FIM_PARA ESCREVA p[ponto_mais_proximo].x,p[ponto_mais_proximo].y

x ,

x ,

x MAIOR_INTEIRO

numa varivel. menor valor.

representa o maior nmero inteiro que podemos armazenar Geralmente atribumos o maior inteiro quando procuramos por um No cdigo, comparamos menor_distancia_ao_quadrado com

32 / 72

Linguagem de Programao I distancia_ao_quadrado e salvamos o menor deles. Se executarmos isso sucessivamente, ao nal, menor_distancia_ao_quadrado conter o menor valor comparado.2
2

x , 5x Esta x

varivel ir guardar a posio do ponto mais prximo. Ela atualizada, sempre que encontramos outro ponto com menor distncia.

Calculo para encontrar a distncia entre dois pontos. Na realizadade, a distncia entre os dois pontos seria a raiz de distancia_ao_quadrado. Mas no h diferena em comparar a distncia ao quadrado. Sabemos, por exemplo, que a raiz de x menor do que a raiz de y se x for menor do que y.

Cdigo fonte code/cap2/ponto_proximo.c Programa em C


#include <stdio.h> #include <limits.h> // contm definio de INT_MAX typedef struct{ int x; int y; } Ponto; #define QUANTIDADE_DE_PONTOS 5 int main(){ Ponto pontos[QUANTIDADE_DE_PONTOS]; printf("Campos: x, y\n"); for(int i=0; (i < QUANTIDADE_DE_PONTOS); i++){ printf("\nInforme as coordenadas do ponto(%i): ",i+1); scanf("%d %d",&pontos[i].x,&pontos[i].y); } int menor_distancia_ao_quadrado = INT_MAX; // maior inteiro int ponto_mais_proximo = 1; for(int i=1; (i < QUANTIDADE_DE_PONTOS); i++){ int distancia_ao_quadrado = (pontos[i].x-pontos[0].x)* (pontos[i].x-pontos[0].x)+(pontos[i].y-pontos[0].y)* (pontos[i].y-pontos[0].y); if(distancia_ao_quadrado < menor_distancia_ao_quadrado){ ponto_mais_proximo = i; menor_distancia_ao_quadrado = distancia_ao_quadrado; } } printf("\nPonto mais proximo: (%d,%d)\n", pontos[ponto_mais_proximo].x, pontos[ponto_mais_proximo].y); getchar();
tivssemos inicializado a varivel menor_distancia_ao_quadrado com 0, ao compar-lo com outro nmero, ele seria o menor, impossibilitando encontrar a menor distncia.
2 Caso

33 / 72

Linguagem de Programao I
return 0; }

Resultado ao simular a execuo do programa


Campos: x, y Informe as Informe as Informe as Informe as Informe as Ponto mais coordenadas do coordenadas do coordenadas do coordenadas do coordenadas do proximo: (5,3) ponto(1): ponto(2): ponto(3): ponto(4): ponto(5): 0 4 6 5 7 0 6 1 3 2

2.6.4

Problema sobre cadastro de produtos no supermercado

Escrever um programa que cadastre vrios produtos. Em seguida, imprima uma lista com o cdigo e nome da cada produto. Por ltimo, consulte o preo de um produto atravs de seu cdigo. Pseudocdigo do programa
REGISTRO Produto codigo: NUMRICO nome: TEXTUAL preco: NUMRICO FIM_REGISTRO QUANTIDADE_DE_PRODUTOS = 5 DECLARA produtos: Produto[QUANTIDADE_DE_PRODUTOS] PARA i=0 AT QUANTIDADE_DE_PRODUTOS FAA LEIA produtos[i].codigo LEIA produtos[i].nome LEIA produtos[i].preco FIM_PARA PARA i=0 AT QUANTIDADE_DE_PRODUTOS FAA ESCREVA produtos[i].codigo ESCREVA produtos[i].nome FIM_PARA DECLARA codigo_digitado: NUMRICO LEIA codigo_digitado PARA i=0 AT QUANTIDADE_DE_PRODUTOS FAA SE produtos[i].codigo == codigo_digitado ENTO ESCREVA produtos[i].preco FIM_PARA

Cdigo fonte code/cap2/supermercado.c Programa em C

34 / 72

Linguagem de Programao I

#include <stdio.h> typedef struct { long codigo; char nome[100]; float preco; } Produto; #define QUANTIDADE_DE_PRODUTOS 5 int main(){ Produto produtos[QUANTIDADE_DE_PRODUTOS]; printf("Campos: codigo-do-produto nome preco\n"); for(int i=0; (i < QUANTIDADE_DE_PRODUTOS); i++){ printf("\nInforme os dados do produto(%i): ",i+1); scanf("%ld %s %f",&produtos[i].codigo,produtos[i].nome, &produtos[i].preco); } for(int i=0; (i < QUANTIDADE_DE_PRODUTOS); i++){ printf("\n%ld\t%s R$ %1.2f", produtos[i].codigo, produtos[i].nome,produtos[i].preco); } long codigo_digitado; printf("\nInforme o codigo do produto: "); scanf("%ld", &codigo_digitado); for(int i=1; (i < QUANTIDADE_DE_PRODUTOS); i++){ if (produtos[i].codigo == codigo_digitado) { printf("\nPreo: R$ %1.2f\n", produtos[i].preco); } } getchar(); return 0; }

Resultado ao simular a execuo do programa


Campos: codigo-do-produto nome preco Informe os dados do produto(1): Informe os dados do produto(2): Informe os dados do produto(3): Informe os dados do produto(4): Informe os dados do produto(5): 1 laranja R$ 1.40 2 rosquinha R$ 3.00 3 leite-moca R$ 4.50 4 farinha-de-trigo R$ 2.70 5 coxinha R$ 1.50 1 2 3 4 5 laranja 1.4 rosquinha 3 leite-moca 4.5 farinha-de-trigo 2.7 coxinha 1.5

35 / 72

Linguagem de Programao I
Informe o codigo do produto: 4 Preo: R$ 2.70

2.6.5

Problema sobre gerenciamento de contas bancrias

Escreva um programa que simule contas bancrias, com as seguintes especicaes: Ao iniciar o programa vamos criar contas bancrias para trs clientes. Cada conta ter o nome e o CPF do cliente associado a ela. No ato da criao da conta o cliente precisar fazer um depsito inicial. Aps as contas serem criadas, o sistema dever possibilitar realizaes de saques ou depsitos nas contas. Sempre que uma operao de saque ou depsito seja realizada, o sistema dever imprimir o nome do titular e o saldo nal da conta. Pseudocdigo do programa
REGISTRO Conta numero_da_conta, cpf_do_cliente, saldo: NUMRICO FIM_REGISTRO REGISTRO Cliente cpf: NUMRICO nome: TEXTUAL FIM_REGISTRO QUANTIDADE_DE_CLIENTES = 3 DECLARA clientes: Cliente[QUANTIDADE_DE_CLIENTES] DECLARA contas: Conta[QUANTIDADE_DE_CLIENTES] PARA i=0 AT QUANTIDADE_DE_CLIENTES FAA LEIA clientes[i].cpf LEIA clientes[i].nome LEIA contas[i].saldo // depsito inicial clientes[i].codigo = i contas[i].numero_da_conta = i contas[i].codigo_do_cliente = clientes[i].codigo FIM_PARA DECLARA operacao: TEXTUAL DECLARA num_conta, valor, sair=0: NUMRICO ENQUANTO sair == 0 FAA LEIA operacao SE operacao == "saque" OU operacao == "deposito" ENTO LEIA num_conta, valor
36 / 72

Linguagem de Programao I
PARA i=0 AT QUANTIDADE_DE_CLIENTES FAA SE contas[i].numero_da_conta == num_conta ENTO SE operacao == "saque" ENTO contas[i].saldo = contas[i].saldo - valor SE operacao == "deposito" ENTO contas[i].saldo = contas[i].saldo + valor PARA j=0 AT QUANTIDADE_DE_CLIENTES FAA SE clientes[j].codigo == contas[i].codigo_do_cliente ENTO ESCREVE clientes[j].nome, contas[i].saldo FIM_PARA FIM_PARA SENO operacao == "sair" ENTO sair = 1 FIM_ENQUANTO

Cdigo fonte code/cap2/conta_bancaria.c Programa em C


#include <stdio.h> typedef struct { char nome[256]; long long cpf; } Cliente; typedef struct { long numero_da_conta; long cpf_do_cliente; double saldo; } Conta; #define QUANTIDADE_DE_CLIENTES 3 #define OPERACAO_SAQUE 1 #define OPERACAO_DEPOSITO 2 int main(){ Cliente clientes[QUANTIDADE_DE_CLIENTES]; Conta contas[QUANTIDADE_DE_CLIENTES]; printf("Campos: cpf nome deposito-inicial\n"); for(long i=0; (i < QUANTIDADE_DE_CLIENTES); i++){ printf("\nDados para abertura da conta(%ld): ",i+1); scanf("%Ld %s %lf",&clientes[i].cpf,clientes[i].nome, &contas[i].saldo); contas[i].numero_da_conta = i; contas[i].cpf_do_cliente = clientes[i].cpf; printf("\nCliente: %s Conta: %ld Saldo inicial: %1.2lf\n", clientes[i].nome, contas[i].numero_da_conta, contas[i].saldo); } int operacao; // como ainda no aprendemos a comparar strings,
37 / 72

Linguagem de Programao I
// vamos usar operao como numrico. long num_conta; double valor; int sair=0; // FALSE while (!sair){ printf("\nInforme a operao: 1-Saque 2-Deposito 3-Sair: "); scanf("%d", &operacao); if (operacao == OPERACAO_SAQUE || operacao == OPERACAO_DEPOSITO){ printf("\nInforme numero-da-conta e valor: "); scanf("%ld %lf", &num_conta, &valor); for(int i=0; (i < QUANTIDADE_DE_CLIENTES); i++){ if (contas[i].numero_da_conta == num_conta) { if (operacao == OPERACAO_SAQUE){ contas[i].saldo -= valor; printf("\nSAQUE: %1.2lf", valor); } if (operacao == OPERACAO_DEPOSITO){ contas[i].saldo += valor; printf("\nDEPOSITO: %1.2lf", valor); } for(int j=0; j < QUANTIDADE_DE_CLIENTES; j++){ if (clientes[j].cpf == contas[i].cpf_do_cliente) printf("\nCliente: %s Saldo atual: %1.2lf", clientes[j].nome, contas[i].saldo); } } } }else{ sair = 1; // TRUE } } getchar(); return 0; }

Resultado ao simular a execuo do programa


Campos: cpf nome deposito-inicial Dados para abertura da conta(1): 48755891748 Jesuno 1500 Cliente: Jesuno Conta: 0 Saldo inicial: 1500.00 Dados para abertura da conta(2): 72779162201 Maria 200 Cliente: Maria Conta: 1 Saldo inicial: 200.00 Dados para abertura da conta(3): 71443626406 Virgulino 600 Cliente: Virgulino Conta: 2 Saldo inicial: 600.00 Informe a operao: 1-Saque 2-Deposito 3-Sair: 1 Informe numero-da-conta e valor: 0 300
38 / 72

Linguagem de Programao I
SAQUE: 300.00 Cliente: Jesuno Saldo atual: 1200.00 Informe a operao: 1-Saque 2-Deposito 3-Sair: 2 Informe numero-da-conta e valor: 2 400 DEPOSITO: 400.00 Cliente: Virgulino Saldo atual: 1000.00 Informe a operao: 1-Saque 2-Deposito 3-Sair: 3

Aps todos estes programas, agora vamos ver uma tcnica que no utilizada ainda, a inicializao de registro com valores pr-denidos.

2.7

Inicializando registros

Quando declaramos uma varivel do tipo registro, tambm podemos realizar uma atribuio aos valores dos seus campos. O programa a seguir ilustra esta atribuio.
Ateno Para a atribuio poder ocorrer, os campos precisam ser inseridos na ordem que foram declarados no tipo do registro.

Cdigo fonte code/cap2/reg_atribuicao.c Programa em C


#include <stdio.h> typedef struct { int matricula; // char nome[100];// float nota1; // float nota2; // } Aluno;
x x 2 x 3 x 4
1

typedef struct { char nome[256];// 5x long long cpf; // 6x } Cliente; int main() { Aluno a = {15, "Virgulino da Silva", 9.0f, 10.0f}; // 7x Cliente c = {"Maria Bonita", 72779162201}; // 8x printf("Aluno: %s Mat.: %d Nota1: %1.2f Nota2: %1.2f\n", a.nome, a.matricula, a.nota1, a.nota2); printf("Cliente: %s CPF: %1Ld\n", c.nome,c.cpf); return 0; }

39 / 72

Linguagem de Programao I
1

x , 2x , 3x , 4x , 7x Seguindo

a ordem da declarao do registro, matricula recebe 15, nome recebe Virgulino da Silva, nota1 recebe 9 e nota2 recebe 10. a ordem da declarao do registro, nome recebe Maria Bonita e cpf recebe 72779162201.

x , 6x , 8x Seguindo

Resultado ao simular a execuo do programa


Aluno: Virgulino da Silva Mat.: 15 Nota1: 9.00 Nota2: 10.00 Cliente: Maria Bonita CPF: 72779162201

Nota O Registro um tipo de dado composto por campos com outros tipos. Mas ser que possvel declarar um campo do tipo Registro? Veremos a resposta na prxima seo.

2.8

Composio de Registros

Na denio de registros (Seo 2.1 [17]), vimos que um Registro criado pela composio de outros tipos de dado. Agora veremos que podemos compor um Registro utilizando outros Registros previamente denidos.
Cuidado Ao realizar composio de registros, a denio do registro que ser utilizado na composio precisa aparecer antes (no cdigo fonte) da denio do novo registro. Caso contrrio, voc poder ter erros de compilao.

2.8.1

Tringulo

Nesta seo vamos denir um Registro tringulo que contm 3 campos do tipo Ponto. Composio de registro em Pseudocdigo
REGISTRO Ponto x, y: NUMRICO FIM_REGISTRO REGISTRO Triangulo p1, p2, p3: Ponto FIM_REGISTRO

Cdigo fonte code/cap2/reg_triangulo.c Composio de registro em C - Tringulo


#include <stdio.h> typedef struct int x; {

40 / 72

Linguagem de Programao I
int y; } Ponto ; typedef struct { Ponto p1; Ponto p2; Ponto p3; } Triangulo ; int main() { Triangulo t; t.p1.x= 1; t.p1.y=0; t.p2.x=-1; t.p2.y=0; t.p3.x= 0; t.p3.y=1; printf("Triangulo: (%d, %d), (%d, %d), (%d, %d).\n", t.p1.x, t.p1.y, t.p2.x, t.p2.y, t.p3.x, t.p3.y); return 0; }

Nota Neste exemplo, o registro do tipo Tringulo foi criado com campos do tipo Ponto, os trs campos foram: p1, p2 e p3. Para acessar a coordenada x do primeiro ponto do Tringulo t, chamamos: t.p1.x. Foram dispostas duas atribuies de coordenadas numa mesma linha apenas para car melhor visualmente, no h necessidade de serem assim.

2.8.2

Informao Pessoal

Nesta seo vamos denir um Registro InformacaoPessoal e utiliz-lo no Registro Aluno e Cliente. Composio de registro em Pseudocdigo
REGISTRO InformacaoPessoal cep: NUMRICO estado_civil: TEXTO FIM_REGISTRO REGISTRO Aluno matricula: NUMRICO nome: TEXTO nota1, nota2: NUMRICO info_pessoal: InformacaoPessoal FIM_REGISTRO REGISTRO Cliente cpf: NUMRICO nome: TEXTUAL
41 / 72

Linguagem de Programao I
info_pessoal: InformacaoPessoal FIM_REGISTRO

Cdigo fonte code/cap2/reg_infopessoal.c Composio de registro em C - Informao Pessoal


#include <stdio.h> typedef struct { long long cep; int estado_civil; // 1:Solteiro 2:Casado 3:Viuvo 4:Divorciado } InformacaoPessoal; typedef struct { int matricula; char nome[100]; float nota1; float nota2; InformacaoPessoal info_pessoal; } Aluno; typedef struct { char nome[256]; long long cpf; InformacaoPessoal info_pessoal; } Cliente; int main() { Aluno a = {15, "Virgulino da Silva", 9.0f, 10.0f, {58051400, 1}}; Cliente c = {"Maria Bonita", 72779162201, {58051400, 2}}; printf("Aluno: %s %1Ld %d.\n", a.nome, a.info_pessoal.cep, a.matricula); printf("Cliente: %s %1Ld %1Ld.\n", c.nome, c.info_pessoal.cep, c.cpf); return 0; }

Nota A composio de Registro utiliza a sintaxe usual de declarao de campos. Uma vez que denimos um novo tipo, basta utilizar o tipo na declarao normal do campo. O acesso aos campos internos do registro passam pelo campo denido no registro externo, por exemplo, para acessar o interno cep, primeiro precisamos referenciar o campo externo info_pessoal, portanto o acesso ca: a.info_pessoal.cep.

Para nalizar nossos estudos sobre Registro, na seo seguinte vamos compar-lo com Arranjo.

42 / 72

Linguagem de Programao I

2.9

Comparao entre Arranjo e Registro

A tabela a seguir mostra uma comparao entre Arranjos e Registros. Arranjo (ou array) Estrutura de dados homognea Arranjo de variveis referenciadas por um mesmo nome e indexada por um inteiro. Ex: notas[i]. Armazena vrios valores, mas todos do mesmo tipo. Registro Estrutura de dados heterognea Coleo de variveis referencias por um mesmo nome Armazena vrios valores, e podem ser de diferentes tipos Cada valor armazenado num campo com um tipo prprio

2.10

Recapitulando

Iniciamos este captulo conhecendo a denio de Registro e sua utilidade. Em seguida aprendemos a sua sintaxe de criao. Vimos o que um campo identicador, e como ele utilizado para diferenciar um registro de outro. Realizamos anlises em 5 situaes demonstrando como criamos registros em cada uma delas. Na Seo 2.6 [28] vimos como implementamos diversos programas em pseudocdigo e em C. Por m, aprendemos como um registro pode ser inicializado (Seo 2.7 [39]), comparamos os registros com os arranjos (Seo 2.9 [43]) e aprendemos como criar um registro atravs da composio de outro (Seo 2.8 [40]).

2.11

Atividades
Dica Na sala de aula, nos fruns e mensagens recomendamos a utilizao do site https://gist.github.com para compartilhar cdigos e tirar dvidas sobre eles.

1. Entendo a necessidade dos registros. Ns poderamos escrever os programas sem utilizar registros. Qual a utilidade de se utilizar registros nos programas? 2. O que um campo identicador? D exemplos no contidos neste captulo. 3. Na Seo 2.4 [20] analisamos diversas situaes buscando os campos necessrios para criao de Registros. Agora chegou a sua vez de fazer o mesmo. Para cada situao a seguir:

43 / 72

Linguagem de Programao I Dena o(s) nome(s) do tipo de registro que voc criar Especique os campos com seus respectivos tipos Indique quais so os campos identicadores, caso exista Escreva as declaraes do(s) Registro(s) em C a. Um programa para registrar os animais e os clientes de um Petshop. b. Um programa para registrar e consultar lmes. c. Um programa para uma biblioteca registrar os seus livros. d. Um programa para agendar e consultar compromissos. 4. Pratique o uso de registros. Utilizando os registros denidos no captulo, faa pequenos programas e teste com as entradas indicadas.3 a. Utilizando o Registro de Aluno em C [21], faa um programa que indique a situao de cada Aluno: Aprovado, se mdia das notas for maior ou igual 5; Reprovado se a mdia for inferior a 5; Aprovado com meno de honra se mdia for superior ou igual a 9. Entrada: nome matrcula nota1 nota2
Maria 12887398 7.0 9.0 Jesuno 12887399 3.5 6.0 Virgulino 12887400 10.0 8.0

b. Utilizando o Registro de Pessoa em C [22], escreva um programa que imprima o IMC das mulheres, depois o dos homens. Quando imprimir o IMC, exiba uma mensagem indicando a condio em que a pessoa se encontra, de acordo com a tabela a seguir. IMC abaixo de 18,5 entre 18,6 e 24,9 entre 25,0 e 29,9 entre 30,0 e 34,9 entre 35,0 e 39,9 acima de 40 Classicao Subnutrido ou abaixo do peso Peso ideal (parabns) Levemente acima do peso Primeiro grau de obesidade Segundo grau de obesidade Obesidade mrbida

Entrada: nome altura peso cpf sexo


Jesuno 1.82 79 48755891748 m Maria 1.66 52 72779162201 f Virgulino 1.75 80 71443626406 m

c. Utilizando o Registro de Ponto em C [23], escreva um programa que leia alguns pontos, indicando em qual quadrante eles esto no plano cartesiano. Entrada: p1.x p1.y p2.x p2.y p3.x p3.y
1 3 -2 4 -3 -3 2 -5
3 Testar com valores pr-denidos facilita o desenvolvimento dos programas, faa disso um hbito. Veremos mais adiante como redirecionar a entrada do programa, facilitando ainda mais os testes.

44 / 72

Linguagem de Programao I
4 0

d. Utilizando o Registro de Produto em C [24], escreva um programa que cadastra uma lista de produtos. Em seguida imprima os produtos ordenadamente pelo menor preo. Entrada: codigo nome valor
11 12 13 14 15 laranja 1.4 rosquinha 3 leite-moca 4.5 farinha-de-trigo 2.7 coxinha 1.5

5. Criando novos Registros. Agora que voc j praticou a utilizao de Registro est no momento de criar os seus prprios Registros.
Importante As questes a seguir no especicam os programas minuciosamente, elas foram elaboradas assim para permitir que voc expresse a sua criatividade. No entanto, voc deve: Resolver as questes utilizando os conhecimentos adquiridos neste captulo Utilizar composio de registros quando for apropriado Preparar valores de entradas xos para o seu programa, de forma a test-lo ecientemente.

a. Faa um programa para um Petshop, para cadastrar os clientes da loja e seus animais. O programa deve possibilitar pesquisa pelo cliente ou pelo seu animal. b. Faa um programa para gerenciar os gastos pessoais. O programa deve poder registrar os gastos por categoria e emitir um relatrio para proporcionar um controle nanceiro. c. Faa um programa para registrar os lmes que voc assistiu ou quer assistir. Os lmes devem ser cadastrados por categorias. O programa deve emitir listas de lmes com base em dois critrios sua escolha. d. Faa um programa para auxiliar a Policia Federal acompanhar as exploses de caixas eletrnicos ao longo do tempo. Aps cadastrar as exploses, o sistema deve informar as regies crticas. e. Faa um programa para simular um dicionrio. Ele deve cadastrar algumas palavras e possibilitar alguma forma de navegao. Consulte um dicionrio real para vericar que alm do signicado da palavra, outras informaes diferentes tambm so cadastradas.

45 / 72

Linguagem de Programao I

Captulo 3 Ponteiros e Alocao Dinmica de Memria


O BJETIVOS DO CAPTULO Ao nal deste captulo voc dever ser capaz de: Entender o conceito de ponteiros e utiliz-los em funes, vetores, registros ou estruturas, dentre outras; Aprofundar o conhecimento sobre armazenamento e manipulao de dados no computador; No incio do capitulo anterior, foi discutido que o conhecimento de linguagens de programao especcas, por si s, no habilita ou no suciente para programadores, imprescindvel saber us-las de maneira eciente. Foi visto tambm que o projeto de um algoritmo ou programa engloba, entre outras, a fase da modelagem computacional de um problema, a qual por sua vez possui uma etapa de identicao das propriedades dos dados (ou informaes contidas no problema) e suas caractersticas funcionais. Dessa forma, uma representao adequada dos dados ou informaes do problema, em vista das funcionalidades que devem ser atendidas, constitui uma etapa fundamental para a obteno de programas ecientes. Neste captulo sero abordados os conceitos de ponteiros e a sua aplicao para alocao dinmica de memria. Ser visto o uso de ponteiros em funes ou sub-rotinas, vetores, registros ou estruturas, vetores de registros, dentre outros.

3.1

Armazenamento de dados no computador

Para armazenar dados no computador um programa gerencia fundamentalmente trs parmetros, a saber, onde a informao est armazenada, que tipo de informao armazenada e que valor mantido l. O primeiro refere-se ao endereo de memria onde os dados so gravados. O segundo refere-se ao tipo de dado, ou seja, qual o tipo de estrutura (varivel, array, registros, dentre outras) e qual a natureza da informao armazenada (real, inteiro, caracteres, nmero sem sinal, dentre outras), essas informaes so importantes para se calcular o espao de memria que ser necessrio para o armazenamento desses dados. O ltimo parmetro refere-se aos valores que so atribudos pelo usurio ou calculados no prprio programa e que sero armazenados nas estruturas de dados. O exemplo mais simples para ilustrar o que foi colocado, o processo de declarao de uma varivel num programa.

46 / 72

Linguagem de Programao I Como ilustrado na Figura 3.1 [47], nesse caso, so realizados basicamente dois passos, a declarao da varivel em si e a atribuio de um valor a essa varivel. Note na Figura 3.1 [47] que no momento em que a varivel soma declarada, alocado na memria RAM do computador um espao de memria para a essa varivel (posies 0xCB22 e 0xCB23). Esse espao de memria preenchido quando um valor atribudo a varivel, como por exemplo, o valor 3126.

int soma; soma=3126; // equivale a 0x0C36 Declarao


0xCB20 0xCB21

Atribuio

0x0C
0xCB23

int

???

0x36

Figura 3.1: Ilustrao de uso da memria por uma varivel em um programa em C. Um cuidado importante que todo programador deve ter inicializar as variveis antes do seu uso. Veja no cdigo a seguir que, quando no se inicializa uma varivel, o valor que ela assume aleatrio e depende do lixo no espao de memria onde foi criada. No momento em que esse cdigo foi criado, compilado e executado o valor de conta foi 624.756.000,00! Ou seja, um valor totalmente aleatrio e que muda a cada vez que a memria RAM do computador inicializada. Voc iria trabalhar a vida inteira para pagar essa conta de luz! O correto inicializar a varivel antes de utiliz-la. Como exerccio, compile e execute o cdigo a seguir com e sem o comentrio indicado. Certamente, com a linha comentada, o valor impresso na tela ser diferente em cada computador em que esse cdigo for executado. Cdigo fonte code/cap3/variavel_nao_inicializada.c Programa para demonstrar valor de varivel no inicializada
#include <stdio.h> #include <stdlib.h> int main() { float conta; // representa o valor da conta de luz da sua casa //conta=65.90; // 1x Descomente este linha printf("O valor da conta esse ms %0.2f. \n", conta); //system ("pause"); return 0; }

Dessa forma, todo nome de varivel est associado a um endereo na memria. O operador de endereo & pode ser usado para obter a localizao de uma varivel na memria, ou seja, o endereo de memria. O cdigo a seguir mostra como esse operador pode ser utilizado para se obter o endereo

47 / 72

???

0xCB22=&soma

3126

Linguagem de Programao I de memria onde uma varivel foi criada. Note que no printf, o %p foi utilizado como formato para endereo de memria. Cdigo fonte code/cap3/operador_de_endereco.c Programa para demonstrar uso do Operador de Endereo
#include <stdio.h> #include <stdlib.h> int main() { int pg=120; double livro=145.60; printf("Valor de pg = %d. \n", pg); printf("Endereo de pg = %p. \n", &pg); printf("Valor de livro = %lf. \n", livro); printf("Endereo de livro = %p. \n", &livro); //system ("pause"); return 0; }

Sada da execuo do programa Valor de Endereo Valor de Endereo pg = 120. de pg = 0xbfda0dac. livro = 145.600000. de livro = 0xbfda0da0.

3.2

Denio de ponteiros

Outra estratgia para armazenar e manipular dados no computador : Alocar memria manualmente; Guardar o endereo de memria em um ponteiro; Usar o ponteiro para acessar e modicar os dados. Ou seja, necessrio denir e utilizar ponteiros no programa. Um ponteiro um tipo especial (varivel especial) que guarda valores que so endereos de memria. Em outras palavras, um ponteiro uma varivel que utilizada para se armazenar endereos de memria. Em geral, um ponteiro associado a uma varivel, ou seja, o ponteiro contm um endereo de uma varivel que contm um valor especco. A referncia de um valor por meio de um ponteiro chamada de indireo. A declarao de um ponteiro segue o seguinte padro: float *ptr; // L-se "ptr um ponteiro para um float" Em que float especica o tipo de elemento apontado pelo ponteiro, ptr o nome que est sendo dado ao ponteiro, o *operador de indireo e usado para se denir um ponteiro. Como o ponteiro contm um endereo de memria, diz-se que ele aponta para aquela posio de memria. A Figura 3.2 [49] ilustra a denio de um ponteiro com nome ptr, que utilizado para
48 / 72

Linguagem de Programao I apontar para a varivel float soma. Note que na linha 4 ptr declarado. At esse momento no existe nenhuma relao entre o ponteiro ptr e a varivel soma. No nal, ptr associado a varivel soma por meio do comando ptr = &soma, ou seja, prt recebe o endereo de memria da varivel soma usando o operador de endereo &. A partir desse comando, o programador pode utilizar o ponteiro ptr para manipular o contedo armazenado na varivel soma. A seguir ser visto como isso feito.

Memria
0xFC00 0xFC02 0xFC04 0xFC06 0xFC08

230.8 1340 5.8 0xF 00

soma N md ptr

float int N float float ... ptr =

soma = 230.8; = 1340; md = 5.8; *ptr; &soma;

Figura 3.2: Ilustrao de declarao e inicializao de um ponteiro na memria O nome de um ponteiro representa uma localizao na memria. Outra funo do operador de indireo * ser usado para se obter o valor armazenado na memria. Ou seja, a partir do operador * que o programador pode manipular o contedo da varivel para qual o ponteiro est apontando.
Importante Sempre inicialize um ponteiro que voc declarou em um programa. Um ponteiro s ter utilidade em um programa quando for inicializado, ou seja, for associado a algum elemento.

Um ponteiro pode ser inicializado com NULL, 0 (zero) ou um endereo de uma varivel usando o operador de endereo &. Um ponteiro com valor NULL no aponta para nada. NULL uma constante simblica denida na biblioteca <stddef.h> e tambm em <stdio.h>. A inicializao do ponteiro com o valor 0 (zero) equivalente a inicializar com NULL, todavia em geral usa-se a inicializao com NULL.

Nota Outras linguagens de programao utilizam nil, ou null com o mesmo signicado.

Outra maneira de se inicializar ponteiros associando-o diretamente a uma varivel. Para isso o operador de endereo & deve ser utilizado. A Figura 3.3 [50](a) ilustra que, ao declarar um ponteiro, o computador no aloca automaticamente memria para guardar o valor apontado e, nesse caso, o comando *pt = 230.8 no faz sentido. preciso inicializar o ponteiro como mostrado na Figura 3.3 [50](b), ou seja, o ponteiro pt declarado e associado a varivel N1. Em seguida, pode-se utilizar o ponteiro para armazenar o valor 230.8 na varivel N1.

49 / 72

Linguagem de Programao I
float *ptr; ... *ptr = 230; float soma = 0; float *ptr = &soma; ... *ptr = 230;

0xFC00 0xFC02 0xFC04 0xFC06 0xFC08

0xFC00

230

soma

0xFC02 0xFC04

????

ptr

0xFC06 0xFC08

0xFC00

ptr

(a)
Figura 3.3: Utilizao de ponteiro.

(b)

Ateno Na Figura 3.3 [50](a) demonstrada uma forma errada da utilizao de ponteiro, ao atribuir um valor a um ponteiro no inicializado. Em b) apresentada a forma correta, com atribuio de valor aps ponteiro inicializado.

Nota Na declarao de um ponteiro o uso de espaos ao redor do * opcional.

int *pt; // enfatiza que *pt um int int* pt; // enfatiza que pt um ponteiro para int int * pt; // estilo neutro

Cuidado Cuidado com declaraes mltiplas.

char *p1, p2;

// p1 um ponteiro para char, // p2 uma varivel do tipo char // p1 e p2 so ponteiros para char

char *p1, *p2;

Com o intuito de sedimentar o conceito de ponteiros, o cdigo a seguir mostra um exemplo de como um ponteiro usado para manipular o contedo da varivel para qual est apontando. Execute esse programa no seu computador e faa modicaes vontade para voc melhor absorver o conceito de ponteiros. Cdigo fonte code/cap3/usando_ponteiro.c Usado ponteiro para alterar varivel

50 / 72

Linguagem de Programao I

#include <stdio.h> #include <stdlib.h> int main() { int total = 18; int *pt; // 1x pt = &total; // 2x printf("Valor de printf("Endereo printf("Valor de printf("Valor de total = %d\n", total); // 3x de total = %p\n", &total);// 4x pt = %p\n", pt);// 5x x *pt = %d\n", *pt);// 6

x *pt = *pt + 12; // 7

printf("Apos soma usando ponteiro: total=%d\n", total);// 8x //system ("pause"); return 0; }


x , 1x o x

ponteiro pt criado

pt inicializado com o endereo de total do valor de total e seu endereo

x , 4x Impresso x x

Impresso do endereo apontado por pt Impresso do valor endereado por pt operador de indireo * utilizado para alterar o valor da varivel total por meio do ponteiro Impresso do valor da varivel total, que teve seu valor alterado pela utilizao de ponteiro.

Resultado da execuo Valor de total = 18 Endereo de total = 0xbfd286a8 Valor de pt = 0xbfd286a8 Valor de *pt = 18 Apos soma usando ponteiro: total=30 Finalmente, recapitulando, note que h dois operadores que so utilizados para a manipulao e/ou denio de ponteiros, a saber, o operador &, conhecido como operador de endereo, e o operador *, normalmente chamado de operador de indireo. O operador de endereo utilizado para se obter o endereo de seu operando ou varivel a que aplicado. O operador de indireo pode ser utilizado de duas formas, a primeira para denio de um ponteiro; j a segunda funo retornar o valor ou contedo da varivel para a qual um ponteiro est apontando.
51 / 72

Linguagem de Programao I

3.3
3.3.1

Ponteiros em funes ou sub-rotinas


Contextualizao

Para entendermos a utilidade do uso de ponteiros em funes preciso antes analisar aspectos da execuo de uma funo em um programa em C, como, por exemplo, a pilha de execuo de uma funo e transferncia de dados para o programa principal (funo main). As funes em um programa em C so independentes entre si. Como consequncia, as variveis locais denidas dentro do escopo de uma funo, inclusive os parmetros de entrada da funo, no existem fora dela. Isso signica que cada vez que uma funo executada, as suas variveis locais so criadas, e aps a sua execuo, essas variveis locais deixam de existir. Outra caracterstica bsica no conceito de funes que a transferncia de dados entre funes feita com o uso de parmetros e do valor de retorno da funo chamada. Ou seja, uma funo pode retornar um valor para a funo que a chamou por meio do comando return. Para entendermos melhor a transferncia de dados entre funes e o uxo de dados dentre do escopo de uma funo, um exemplo detalhado dado e sua execuo analisada usando o esquema ilustrado na Figura 3.4 [52]. Essa gura esboa o conceito de pilha de execuo na memria RAM do computador, na qual os nomes das variveis e/ou das funes so mostrados direita de cada clula/linha, o valor/contedo que uma varivel assume no momento da execuo da funo mostrado em cada clula/linha da coluna e, nalmente, o endereo de memria onde cada varivel est gravada mostrado esquerda de cada clula/linha. images/cap3/pilha_de_execucao.eps Figura 3.4: Ilustrao da pilha de execuo na memria RAM do computador. Considere agora o cdigo mostrado a seguir. Esse exemplo mostra um programa que calcula a soma dos nmeros pares entre 0 e 200. A etapa de clculo da soma feita na funo f_soma, a qual chamada na linha 11 dentro da funo principal (funo main ou funo chamadora). Como dito anteriormente, quando uma funo executada, as suas variveis locais so criadas, e aps a sua execuo, essas variveis locais deixam de existir. Note no cdigo exemplo que, aps a execuo da funo f_soma, a varivel PAR dentro da funo f_soma ter valor 0 (zero). Ou seja, diferente do valor 200 que PAR possui aps a execuo da funo main, j que seu valor no foi alterado dentro da funo principal. O que acontece que PAR (parmetro da funo f_soma) uma varivel local inicializada com o valor passado na chamada da funo. Sendo assim, PAR dentro da funo f_soma no representa a PAR dentro da funo main; o fato delas terem o mesmo nome indiferente. Cdigo fonte code/cap3/f_soma.c
#include <stdio.h> #include <stdlib.h> float f_soma(int); // prottipo da funo f_soma int main() { float soma; // declara uma varivel do tipo float int PAR; // declara uma varivel do tipo int soma=0; // inicializa a varivel soma em 0 (zero) PAR = 200; // inicializa a varivel PAR em 200 soma = f_soma(PAR);
52 / 72

Linguagem de Programao I
printf ("A soma dos nmeros pares em 0 e 200 %0.1f ", soma); system("pause"); return 0; } // Corpo da funo f_soma. Soma os nmeros pares entre 200 e zero float f_soma(int PAR){ float s=0; // declara e inicializa em 0 uma varivel do tipo float while (PAR!=0){ s = s + PAR; PAR= PAR - 2; } return s; }

Dica Como exerccio para casa e para visualizar o que foi dito, inclua, usando o comando printf, a impresso da varivel PAR dentro da funo main e aps o while dentro da funo f_soma. Veja que dentro da funo main ser impresso o valor 200 e aps o while da funo f_soma ser impresso o valor 0 (zero).

Continuando o debate, ser mostrada agora a pilha de execuo na memria do programa em questo. Ser utilizada a notao descrita na Fig. 3.4. Resumidamente, a pilha de execuo funciona da seguinte forma. Cada varivel local de uma funo de uma funo colocada na pilha de execuo. As chamar uma funo, os parmetros da funo so copiados para a pilha e tratados como se fossem variveis locais da funo chamada. Quando a execuo da funo concluda, a parte da pilha correspondente quela funo liberada. Por isso, no se pode acessar as variveis locais de fora da funo em que foram denidas. Perceba na Fig. 3.5a que quando o programa inicia, a funo main inicia com a pilha vazia. Seguindo na execuo do programa (linhas 7 a 10 do programa), a Fig. 3.5b mostra a denio e inicializao das variveis soma e PAR na pilha. Com a chamada da funo (linha 11), a Fig. 3.5c apresenta a varivel PAR da funo f_soma na pilha de execuo (observe que PAR inicia com valor 200). A Fig. 3.5d ilustra a criao/inicializao da varivel local s dentro da funo f_soma. A Fig. 3.5e mostra a situao da pilha aps o lao while (linha 22), note que agora PAR possui valor 0 (zero) e s 10100.0 (que a soma dos nmeros pares entre 0 e 200). Nesse caso, veja que a varivel PAR dentro da funo main continua com seu valor inicial, ou seja, 200. A Fig. 3.5f mostra a situao aps o retorno da funo (linha 23), ou seja, o valor retornado pela funo f_soma armazenado na varivel soma dentro da funo main (linha 11). Fig. 3.5: Ilustrao da pilha de execuo na memria RAM de um programa em execuo.

3.3.2

3.3.2 Passagem de parmetros em funes: passagem por valor vs passagem por referncia

Na subseo anterior foi vista a pilha de execuo de um programa com funes em C e concluiu-se que no se pode modicar valores das variveis locais pertencentes a uma funo fora do escopo de tal funo. Esse tipo de passagem de parmetros que foi vista anteriormente chamada passagem por valor. Nesse caso, uma cpia dos parmetros da funo feita e passada para a funo chamada e, portanto, as mudanas nessa cpia no afetam o valor original da varivel chamadora.

53 / 72

Linguagem de Programao I

Dica A chamada por valor dever ser usada sempre que no se desejar/precisar modicar o valor da varivel original que foi chamada.

Importante Todas as chamadas em C so feitas por valor. Cabe ao programador identicar as situaes em que se deseja empregar a passagem por referncia.

Todavia, muitas funes exigem a necessidade de modicar uma ou mais variveis na funo chamadora ou passar um ponteiro para um objeto com grande quantidade de dados (por exemplo, um array), para evitar a sobrecarga de passar o objeto inteiro por valor, ou seja, isso implicaria na sobrecarga de ter de fazer uma cpia do objeto inteiro na pilha de execuo. Uma outra limitao do uso de passagem por parmetro que nesse tipo de implementao a funo s pode retornar um nico valor para a funo chamadora. Quando se deseja retornar mais de um valor, o esquema de passagem por valor no poder ser utilizado. Para resolver esses problemas, usa-se em C1 a passagem de parmetros por referncia para as funes e necessrio o uso de ponteiros para esse m. Para melhor entender esse debate, a seguir dado um exemplo simples de um programa para se calcular a soma e subtrao de dois nmeros inteiros. Vamos iniciar com um programa que usa uma funo para calcular a subtrao de dois nmeros inteiros. Cdigo fonte code/cap3/codigo-c.c
/* programa que usa uma funo para calcular a subtrao de dois nmeros inteiros*/ #include <stdio.h> #include <stdlib.h> int calculadora(int, int); // prottipo da funo calculadora int main() { int sub=0; // declara/inicializa uma varivel do tipo int sub = calculadora(10, 7); printf ("A subtrao entre 10 e 7 %d.\n, sub); system("pause"); return 0; } // Corpo da funo calculadora int calculadora(int x, int y){ return (x - y); }

Nesse exemplo no h um problema explcito, pois o resultado da subtrao retornado pela funo calculadora explicitamente (linha 15) e armazenado na varivel sub (linha 8). Um dos problemas da ((passagem de parmetros por valor)) acontece quando se deseja retornar em uma funo
1 Outras linguagens com Lua e Ruby permitem funes retornar vrios valores, que podem ser atribudos a mais de uma varivel.

54 / 72

Linguagem de Programao I mais de um valor para a funo chamadora. Vamos supor que agora se deseje retornar o valor da soma e subtrao de dois nmeros inteiros. Usando a ideia da passagem de parmetros por valor uma forma incorreta de se implementar esse programa mostrada a seguir. Cdigo fonte code/cap3/codigo-d.c Titulo do cdigo

Como se sabe e j foi alertado no texto, esse cdigo no funciona. Sero impressos na tela valores incorretos e que dependem da execuo em cada computador, os valores das variveis sub e soma calculados na funo calculadora no possuem relao com as variveis sub e soma impressos na funo chamadora (nesse caso a funo main) na linha 10. Para resolver esse problema preciso usar a ((passagem de valores por referncia)), ou seja, passar ponteiros para a funo. Como j se sabe, com o uso de ponteiros possvel alterar indiretamente valores de variveis. Dessa forma, se for passado para uma funo os valores dos endereos de memria em que suas variveis esto armazenadas (i.e., os ponteiros que apontam para essas variveis), essa funo pode alterar indiretamente os valores das variveis na funo chamadora. Usando-se essa estratgia, possvel resolver o problema do ltimo exemplo. Isso feito no cdigo a seguir. Cdigo fonte code/cap3/codigo-e.c

A diferena entre esse exemplo (forma correta) e o anterior (forma incorreta) est nas linhas 4, 8, 14, 15 e 16. Na linha 4, o prottipo da funo calculadora denido com duas variveis do tipo inteiro e dois ponteiros para inteiros como parmetros de entrada. Compare com a linha 5 do exemplo anterior (forma incorreta). Na linha 8, a funo calculadora continua sendo uma funo sem retorno. Entretanto, so tambm passados como parmetros de entrada os endereos de memria das variveis sub e soma (i.e., &sub e &soma). Compare esse trecho do cdigo com a linha 10 do exemplo anterior (forma incorreta). Na linha 14, o cdigo da funo calculadora comea a ser denido e com os dois ponteiros para inteiros como parmetros de entrada (i.e., ptr1 e ptr2), conforme foi denido no prottipo da funo na linha 4. Nesse cenrio, quando a funo calculadora chamada na linha 8, os endereos de memria das variveis sub e soma (i.e., &sub e &soma) so armazenados nos ponteiros ptr1 e ptr2. A partir desse momento, possvel modicar o contedo das variveis sub e soma usando ptr1 e ptr2. Isso feito nas linhas 15 e 16 para se calcular a subtrao e soma, respectivamente, usando a funcionalidade do operador de indireo * discutida na Seo 3.2. Execute esse cdigo no seu computador e veja que agora os valores da subtrao e soma so calculados e exibidos corretamente. Fig. 3.6: Ilustrao da execuo do programa para o clculo da subtrao e soma de dois nmeros inteiros. A Fig. 3.6 ilustra a pilha de execuo da forma correta do programa usando ponteiros. Note que na Fig. 3.6c que os ponteiros ptr1 e ptr2 recebem os endereos de memria das variveis sub e soma, respectivamente. Com isso, agora possvel alterar o contedo de sub e soma usando esses ponteiros, mesmo dentro de uma funo em que sub e soma no so denidas. Isso mostrado na Fig. 3.6d, observe que os ponteiros so utilizados para se computar a subtrao e soma. A Fig. 3.7e apresenta a situao da pilha aps a funo calculadora ser executada. Veja que as variveis locais x, y, *ptr1 e *ptr2 so desempilhadas.
55 / 72

Linguagem de Programao I

3.4

Atividades

1. Dena ponteiros e explique usando exemplos a funo dos operadores de indireo * e de endereo &. 2. Considere o cdigo a seguir. Quais valores sero impressos na tela?
#include <stdio.h> #include <stdlib.h> int main() { int tot = 20; int *ptr; ptr = &tot; printf(" %d.", tot); printf(" %d, *ptr); *ptr = *ptr + tot; printf(" %d, tot); *ptr = tot + 16; printf(" %d, tot); system ("pause"); return 0; }

3. Escreva os comandos em linguagem C que realizam as tarefas dadas nos itens (b), (c), (d) e (e). Considere que a varivel V1 do tipo double. O item (a) est resolvido para que o aluno melhor entenda o que se pede na questo. a. Dena um ponteiro para double; b. Atribua o endereo da varivel V1 ao ponteiro para double denido na letra (a); c. Imprima o endereo de memria da varivel V1; d. Imprima o endereo de memria armazenado no ponteiro da letra (b); e. Inicialize a varivel V1 em 12,5 e depois modique o seu valor para 30,4 usando o ponteiro da letra (b). (a) Soluo: double *ptr; 4. Faa um programa em C para calcular a rea de um retngulo. O programa deve solicitar ao usurio os dois lados do retngulo. Voc deve fazer duas verses desse programa: a. usando uma funo com passagem por valor para calcular a rea do retngulo; b. usando uma funo com passagem por referncia para calcular a rea do retngulo. Para cada caso faa/desenhe a pilha de execuo do programa. 5. Elabore um programa em C que receba trs valores (obrigatoriamente maiores do que zero), representando as medidas dos trs lados de um tringulo. Alm da funo main, o programa deve conter outra funo para: i) determinar se esses lados formam um tringulo; ii) determinar e mostrar o tipo de tringulo (equiltero, issceles ou escaleno), caso as medidas formem um tringulo. Na soluo deve-se usar passagem de parmetros por referncia.
56 / 72

Linguagem de Programao I

Dica Sabe-se que para ser tringulo, a medida de um lado qualquer deve ser inferior ou igual soma das medidas dos outros dois lados. Tringulo equiltero possui todos os lados iguais; tringulo issceles possui pelo menos dois lados de medidas iguais; tringulo escaleno possui as medidas dos trs lados diferentes.

6. Considere uma equao de movimento para calcular a posio (s) e velocidade (v) de uma partcula em um determinado instante t, dado sua acelerao a, posio s0 e velocidade v0. O programa abaixo ilustra o uso dessa equao, imprimindo os valores 55.5 e 25.0, que representam a posio e velocidade calculadas para os valores utilizados pelo programa.
#include <stdio.h> #include <stdlib.h> int main(){ float s0=3.0, v0=10.0, a = 5.0, t = 3.0; float s, v; movimento(s0, v0, a, t, &s, &v); printf (%f %f\n, s, v); system ("pause"); return 0; }

Implemente a funo movimento de tal forma que o exemplo acima funcione adequadamente. A soluo deve funcionar para quaisquer valores de t, a, s0 e v0, no podendo ser particularizada para o programa acima. Para o clculo da velocidade (v) use a equao v= v0 + a.t e da posio (s) use s= s0 + v0.t + (a.t2)/2. 7. Considere o programa abaixo que possui uma funo calculadora que serve para calcular soma (s) e o produto (p) de dois nmeros reais (c e d). O programa abaixo ilustra o uso dessa funo para quando os valores 2.5 e 3.9 so utilizados pelo programa. Implemente a funo calculadora de tal forma que o cdigo abaixo funcione adequadamente. A soluo deve funcionar para quaisquer valores de c e d, no podendo ser particularizada para os valores usados no programa abaixo, i.e., c= 2.5 e d=3.9. Aps montar o cdigo, faa/desenhe a pilha de execuo do programa para o caso quando c= 2.5 e d=3.9.
#include <stdio.h> #include <stdlib.h> int main(){ float c=2.5, d=3.9, s, p; calculadora(c, d, &s, &p); printf (%f %f\n, s, p); system ("pause"); return 0; }

8. Implemente uma funo chamada calc_esfera, que calcule o volume e a rea da superfcie de uma esfera de raio r. Essa funo deve obedecer ao prottipo: void calc_esfera(float r, float *area, float *volume). Em seguida, monte um programa que pea o raio da esfera ao usurio e calcule os valores da rea e volume da esfera. Dica: a rea e volume da esfera so calculados como area=4. .r2, volume=(4. .r3)/3.
57 / 72

Linguagem de Programao I

Captulo 4 Alocao Dinmica de Memria


O BJETIVOS DO CAPTULO Ao nal deste captulo voc dever ser capaz de: Fazer alocao dinmica de memria em programas em linguagem C e entender as suas vantagens com relao alocao esttica de memria. At agora foi visto que ponteiros podem ser usados para guardar endereos de variveis j existentes em um programa em C. As variveis podem ser entendidas como um espao de memria que rotulado durante o processo de compilao do programa em C. Ou seja, alocado um espao de memria esttico para as variveis. Nesse caso, foi visto que os ponteiros fornecem apenas uma segunda forma de acesso s variveis, pois recebem os endereos de memria onde essas variveis foram criadas. Um ponto importante a ser notado que durante a execuo do programa em C, uma vez criadas, essas variveis no podem ser mais apagadas da memria. Ou seja, os espaos de memria utilizados pelas variveis, no podem ser liberados para uso por outras variveis ou tipos de dados durante a execuo desse programa. Esse tipo de alocao de memria chamada alocao esttica. Ou seja, esse espao de memria alocado estaticamente ca reservado para a varivel (ou outro tipo/estrutura de dados, como arrays, estruturas ou registros, dentre outros. . . ) durante todo o tempo de execuo do programa. Outro ponto importante que na alocao esttica o programador deve saber a quantidade de memria que preciso ser denida no programa. Todavia, h casos em que o programador no sabe, no momento em que est montando o programa, a quantidade de memria (ou de tipo/estrutura de dados) que o programa ir precisar. Ou seja, h casos em que a quantidade de memria necessria varia de acordo com a execuo do prprio programa. Um exemplo um programa que permite mltiplos documentos abertos ao mesmo tempo, como muitos processadores de texto. Nesse caso, o programa no estima quantos documentos o usurio ir abrir nem qual o tamanho de cada documento aberto. Faz-se ento necessrio estudar um mecanismo que permita a alocao de memria de acordo com a necessidade e durante a execuo do prprio programa. Isso o que se chama de alocao dinmica de memria. Nesse cenrio, os ponteiros so nossos aliados e o seu verdadeiro poder est em apontar para memria no rotulada ou dinmica, alocada durante a execuo do programa, i.e., alocada dinamicamente. Para melhor entender o conceito de alocao dinmica, discutida trs formas para reservar espao de memria para o armazenamento de informaes em um programa em C:

58 / 72

Linguagem de Programao I Uso de variveis globais e estticas sabe-se que o espao reservado de memria para a varivel global existe enquanto o programa estiver em execuo e s pode ser utilizado pela prpria varivel. Uso de variveis locais em funes como j foi visto, o espao de memria reservado para a varivel s existe enquanto a funo que declarou a varivel est sendo executada. Quando a execuo da funo for concluda, esse espao de memria est liberado para outros usos e, portanto, as informaes armazenadas na varivel so perdidas e no podem ser mais recuperadas no escopo do programa. Uso de alocao dinmina A terceira opo requisitar ao sistema, durante a execuo do programa, um espao de memria de um determinado tamanho. Esse espao alocado dinamicamente permanece reservado at que seja liberado pelo programa usando um comando especco que ser visto adiante. Com isso, pode-se alocar dinamicamente um espao de memria em uma funo e acess-lo em outra. Quando o espao de memria liberado, ele ca liberado para outros usos dentro de programa e no se pode mais acess-lo. Como j foi discutida, uma vantagem dessa abordagem que, em problemas nos quais o programador no sabe a dimenso ou espao necessrio dos tipos de dados que ir utilizar no programa, pode-se usar a alocao dinmica de memria para alocar e liberar memria ao longo da execuo de um programa. A Fig. 3.7 ilustra um esquema didtico do uso da memria RAM do computador pelo sistema operacional durante a execuo de um programa. Quando um programa executado, o seu cdigo em linguagem de mquina carregado na memria RAM. H espaos reservados para gravao de variveis globais e estticas que possam existir nesse programa. O restante da memria livre pode ser utilizado pelas variveis locais e pelas variveis alocadas dinamicamente. Toda vez quem uma funo for chamada, reservado um espao na pilha de execuo para o armazenamento das variveis locais da funo. Lembre-se que, conforme debatido anteriormente, esse espao liberado quando a funo acaba a sua execuo. A parte da memria no utilizada pela pilha de execuo pode ser usada para alocar memria dinamicamente. Caso a pilha de execuo cresa alm do espao de memria livre ou a quantidade de memria a ser alocada dinamicamente seja maior que a memria livre, o programa para de funcionar. Mais adiante, ser visto como se deve fazer para abordar o programa na situao de alocao de memria alm do espao disponvel. Fig. 3.7: Ilustrao do uso da memria RAM do computador durante a execuo de um programa.

4.1

3.4.2 Alocao dinmica de memria

A alocao dinmica de memria feita usando-se funes da biblioteca padro stdlib.h. As funes bsicas para alocar e liberar memria so a malloc e free, respectivamente. Como ser visto adiante, possvel fazer tambm realocao dinmica de memria usando o realloc, ou seja, dado que existe um espao de memria alocado dinamicamente possvel realocar esse espao de memria liberando parte do espao de memria que no vai se utilizar no programa. A funo malloc recebe como parmetro de entrada o nmero de bytes que se deseja alocar e retorna o endereo de memria onde inicia o bloco de memria alocada dinamicamente. O leitor j deve ter percebido que para se armazenar o endereo de memria retornado pela funo malloc deve-se usar uma varivel do tipo ponteiro. Dessa forma, o esquema de alocao de memria em C uma relao entre o uso da funo malloc e de ponteiros, alm da funo free como ser visto adiante. Como exemplo, considere o caso que deseja alocar dinamicamente um vetor com 20 elementos reais do tipo float. Nesse caso, os comandos em linguagem C seriam
59 / 72

Linguagem de Programao I

float *ptr; ptr = (float*) malloc (20*sizeof(float)); Em que ptr um ponteiro que ir armazenar o valor retornado pela funo malloc, note que um ponteiro para um tipo float j que se trata de alocao de um vetor de tipos float. Conforme foi visto no Captulo 1, o comando sizeof utilizado para se computar a quantidade de bytes que um tipo de dado necessita para ser gravado na memria. Nesse caso, ser alocado dinamicamente um espao de memria equivalente a 20 variveis do tipo float. Um ltimo detalhe que a parte (float*) necessria porque a funo malloc retorna ou no um ponteiro genrico para um tipo qualquer, sendo representado por void*. O (float*) usado para transforma o ponteiro em ponteiro para float, visto que est se alocando memria para um tipo float. Algumas bibliotecas mais recentes de C no necessitam desse comando, fazendo a converso do ponteiro automaticamente. A Fig. 3.8 ilustra como que ocorre na memria a execuo desse trecho de cdigo. Observe na Fig. 3.8a que aps a execuo do comando que cria o ponteiro, um espao alocado na pilha de execuo para ptr. Na Fig. 3.8b, considerando que um float ocupa 8 bytes, ilustrada a situao da memria aps o comando ptr = (float*) malloc (20*sizeof(float)). Perceba tambm que 160 bytes so alocados dinamicamente na memria e que ptr recebe o endereo de memria onde inicia o bloco de 160 bytes recm alocados, ou seja, *ptr=0x36FC07. Fig. 3.8: Ilustrao de alocao dinmica de um vetor com 20 elementos do tipo oat. Pode acontecer a situao que no haja espao suciente de memria para a alocao que se deseja fazer. Nesse caso, a funo malloc retorna um endereo nulo para o ponteiro, ou seja, retornado NULL. Um cdigo simples pode ser adicionado no programa para vericar se essa situao ocorre e abortar a execuo do programa. Veja no exemplo a seguir que a funo exit, a qual pertence biblioteca stdlib.h, utilizada para abortar o programa.
... float *ptr; ptr = (float*) malloc(20*sizeof(float)); if(ptr==NULL){ printf ("No h memria suficiente para alocao. O programa ser encerrado."); exit(1); // aborta o programa e retorna 1 para o sistema operacional } ...

Para liberar o espao de memria alocado dinamicamente a funo free utilizada. Essa funo recebe como parmetro de entrada o ponteiro que indica o incio do bloco de memria a ser liberada. No exemplo em questo, seria o ponteiro prt. Dessa forma, para liberar o espao de memria do vetor de 20 elementos float usa-se o comando: free(ptr); Vale a pena mencionar que o espao de memria que foi liberado, no pode ser mais acessado pelo programa. Porm, pode ser reutilizado para armazenar outras informaes, inclusive para se fazer uma nova alocao dinmica de memria. Outro ponto importante que o sistema operacional do computador quem faz o trabalho de alocao e gerenciamento de memria. O programador apenas informa por meio dos comandos no programa que deseja fazer uma alocao de memria.

60 / 72

Linguagem de Programao I

Dica A funo free() no destri o ponteiro que recebe como entrada. Portanto, esse ponteiro pode ser reaproveitado dentro do escopo do mesmo programa. A funo free() apenas libera o espao de memria que foi alocado dinamicamente no programa para que possa ser utilizado para armazenar outros dados.

Ateno No se pode liberar o mesmo bloco de memria duas vezes. Ou seja, basta utiliza uma vez a funo free() para cada bloco de memria.

float *ptr; ptr = (float* ) malloc (20*sizeof(float)); . . . free(ptr); free(ptr); // comando incorreto

Cuidado No se pode usar free() para liberar memria criada com a declarao de variveis.

int soma; soma=80; . . . free(soma); // comando incorreto

O cdigo a seguir mostra que um ponteiro pode ser utilizado vrias vezes para se alocar memria dinamicamente. O cuidado que o programador deve ter liberar o espao de memria alocado dinamicamente antes de fazer uma nova alocao usando o mesmo ponteiro. Outra observao importante que quando esse cdigo foi executado no computador do autor, o mesmo endereo de memria foi impresso nas 15 e 22. Ou seja, aps a liberao do espao de memria alocado dinamicamente (linha 17), o sistema operacional pode reutiliz-lo para outros ns, que nesse caso foi uma nova alocao dinmica de memria (linha 18). Por m, possvel fazer uma realocao de um espao de memria que foi alocado dinamicamente. Isso feito usando a funo realloc(). O prottipo da funo : void *realloc (void *ptr, tamanho do espao a ser realocado); No exemplo a seguir feita uma realocao em que o espao alocado passa de 20 para 25 tipos float. E depois de 25 para 12 tipos floats.
float *ptr = (float* ) malloc (20*sizeof(float)); // ... (sequncia de comandos) ptr = (float* ) realloc (ptr, 25*sizeof(float)); // ... (sequncia de comandos) ptr = (float* ) realloc (ptr, 12*sizeof(float)); /* programa que usa o mesmo ponteiro para alocar memria dinamicamente em duas situaes diferentes*/
61 / 72

Linguagem de Programao I
#include <stdio.h> #include <stdlib.h> int main(){ int *ptr; // declara um ponteiro para um inteiro ptr = (int*) malloc(sizeof(int)); // aloca memria para um inteiro if(ptr==NULL){ printf ("No h memria suficiente para alocao. O programa ser encerrado."); exit(1); /* aborta o programa e retorna 1 para o sistema operacional */ } *ptr=69; // coloca um valor l printf("Valor inteiro = %d \n", *ptr); // imprimi valor printf("Localizao na memria= %p \n\n", ptr); // imprimi endereo // de memria free(ptr); // o espao de memria liberado ptr = (int*) malloc(sizeof(int)); // usa o mesmo ponteiro para alocar // memria para outro inteiro *ptr=45; printf("Valor inteiro = %d \n", *ptr); // imprimi valor printf("Localizao na memoria= %p \n\n", ptr); // imprimi endereo de // memria free(ptr); // o espao de memria liberado novamente system("pause"); return 0; }

4.2
4.2.1

3.4.3 Arrays dinmicos


3.4.3.1 Vetores dinmicos

Na maioria das vezes reserva-se o uso de alocao dinmica para os casos em que a dimenso do vetor desconhecida. Quando se sabe a sua dimenso, prefervel usar vetores alocados estaticamente, visto que do ponto de vista de tempo de execuo do programa, esse tipo de alocao de vetores mais rpida. Um ponto importante que caso o vetor seja denido dentro do escopo de uma funo, ento ele existir quando essa funo estiver sendo executada. Portanto, o programador deve atentar para a utilizao de vetores dentro de funes. Para alocar dinamicamente um vetor, pode-se usar o seguinte comando: float *ptr; ptr = (float*) malloc(n*sizeof(float)); Em que ptr um ponteiro que ir armazenar o valor retornado pela funo malloc, note que ptr um ponteiro para um tipo float j que se trata de alocao de um vetor de tipos float. n representa a dimenso do vetor. A seguir dado um exemplo de como se utilizar um vetor dinmico em um programa em C que calcula a soma de dois vetores.
/* programa que soma dois vetores usando alocao dinmica*/ #include <stdio.h> #include <stdlib.h>
62 / 72

Linguagem de Programao I
int* soma_vet(int[], int[]); int main(){ int i, *ptr1; // declara um inteiro e um ponteiro para inteiro int va[8], vb[8]; // declara dois vetores de inteiros com 8 posies for(i=0; i<8;i++){ // preenchendo os vetores va e vb va[i]=i; vb[i]=i+1; } ptr1=soma_vet(va, vb); // chamando a funo soma_vet for(i=0; i<8; i++){ // imprimindo o vetor va printf(" %d ", va[i]); } printf("\n\n"); for(i=0; i<8; i++){ // imprimindo o vetor vb printf(" %d ", vb[i]); } printf("\n\n"); for(i=0; i<8; i++){ // imprimindo o vetor soma printf(" %d ", ptr1[i]); } printf("\n\n"); system("pause"); return 0; } int* soma_vet(int va[8], int vb[8]){ int *ptr2; ptr2 = (int*) malloc(8*sizeof(int)); if(ptr2==NULL) { printf ("No h memria suficiente. O programa ser encerrado. "); exit(1); } // aborta o programa e retorna 1 para o sist. o peracional for(int j=0; j<8; j++){ ptr2[j]= va[j] + vb[j]; } return ptr2; }

Note que h outras maneiras de se resolver o problema da soma de dois vetores. Esse exemplo foi dado somente para ilustra o uso de alocao de um vetor dinamicamente. Veja que a alocao dinmica de memria ocorreu no escopo da funo soma_vet (linha 27). Como o vetor de oito posies, foi alocado um espao para oito nmeros inteiros no comando da linha 27. O ponteiro ptr2 foi utilizado como marcador inicial do vetor para guardar a soma dos vetores va e vb. Um ltimo detalhe que o comando free(ptr2) no necessitou ser dado, j que aps o comando de return na linha 33 o bloco de memria alocado ser liberado automaticamente j que a funo foi encerrada.

4.2.2

3.4.3.2 Matrizes dinmicas

Para se denir matrizes dinmicas na linguagem C enfrenta-se a limitao de que na linguagem C s permitida fazer alocao dinmica de memria de estruturas unidimensionais, como o caso de vetores. Como uma matriz uma estrutura com duas dimenses (linhas e colunas), para fazer uma alocao dinmica de uma matriz preciso utilizar artifcios de programao utilizando vetores. Por exemplo, partindo da ideia de que para se alocar uma matriz na memria preciso ter espao suciente para seus elementos, pode-se utilizar um vetor para tal m. O tamanho do vetor alocado dinamicamente seria determinado de acordo com as dimenses da matriz que se deseja alocar. A ideia, portanto, transformar, do ponto de vista conceitual, a matriz em um vetor unidimensional. A seguir apresentada uma maneira de fazer tal transformao.
63 / 72

Linguagem de Programao I Considere uma matriz com l linhas e c colunas, a qual pode ser representada na linguagem C como mtr[l][c]. possvel criar um vetor com l*c elementos, aqui chamado de vet[l*c], que representar a matriz mtr[l][c]. Para a correspondncia entra a matriz e o vetor seja atendida, um elemento aij da matriz mapeado no elemento k=i*c+ j, em que c o nmero de colunas da matriz, como foi denido no incio desse pargrafo. Essa relao utilizada para se encontra um elemento k do vetor vet[l*c], ou seja, o elemento vet[i*c+ j]. A Fig. 3.9 mostra uma ilustrao desse mapeamento de matriz em vetor. O ponto negativo dessa estratgia que preciso usar a notao vet[i*c + j] para acessar os elementos da matriz no vetor. Fig. 3.9: Ilustrao do mapeamento de uma matriz em um vetor. Usando esse mapeamento, a alocao dinmica de uma matriz recai no problema de alocao dinmica de um vetor. De forma geral, se quisermos fazer a alocao dinmica de uma matriz com l linha e c colunas para armazenar nmeros reais, basta fazer como abaixo // ponteiro para guardar o endereo onde inicia a alocao float *mtr; // note que foram alocados l*c elementos mtr = (float*) malloc(l*c*sizeof(float)); O exemplo a seguir mostra o uso dessa estratgia para uma matriz com 4 linhas e 3 colunas.
/* programa que usa um vetor para alocar dinamicamente uma matriz */ #include <stdio.h> #include <stdlib.h> int main(){ int i, *ptr1; // declara um inteiro e um ponteiro para inteiro int va[8], vb[8]; // declara dois vetores de inteiros com 8 posies int l=4, c=3; // declara dois inteiros, i.e., as linhas e colunas da matriz int i, j; // declara dois inteiros para serem os ndices dos for float *mtr; // declara dois floats e um ponteiro para float mtr = (float*) malloc(c*l*sizeof(float)); // alocao dinmica de memria if(mtr==NULL){ printf("Memoria insuficiente para alocar os c*l elementos. "); return 1; } // preenchendo o vetor (diretamente) e a matriz (indiretamente) for(i=0; i<l;i++){ for(j=0; j<c; j++){ mtr[i*c + j]= (9*i+j)/4.0; } } // imprimindo a matriz for (i=0;i<l;i++){ for (j=0;j<c;j++){ printf (" %0.1f", mtr[i*c + j]); } printf (" \n\n"); } printf("\n\n"); free(mtr); // libera do espao de memria alocado d inamicamente
64 / 72

Linguagem de Programao I
system("pause"); return 0; }

Como comentrio nal, existem outras maneiras de se alocar dinamicamente uma matriz, todavia, em geral, preciso utilizar um vetor como estrutura auxiliar para representar a matriz.

4.2.3

3.4.4 Registros (estruturas) dinmicas

possvel tambm alocar dinamicamente um registro ou estrutura na linguagem C. Considere um registro denido como a seguir: struct jogador { char nome[40]; float salario; unsigned gols; }; A alocao de registro dinamicamente segue a mesma lgica que j foi vista. Ou seja, deve-se inicialmente denir um ponteiro para o tipo de estrutura/tipo que se deseja alocar e em seguida usa-se a funo malloc para fazer a alocao. Seguindo esse raciocnio, tem-se para o caso de um registro jogador struct jogador *ptr; ptr = (struct jogador*) malloc(sizeof(struct jogador)); Nesses dois comandos alocado dinamicamente um registro do tipo jogador que capaz de armazenar o nome do jogador com at 40 caracteres, o salrio e o nmeros de gols. O espao de memria reservado igual soma do espao dos campos pertencentes ao registro jogador. O comando sizeof(struct jogador), por sua vez, automaticamente passa para a funo malloc a quantidade de memria necessria para alocar a estrutura jogador. Note que o programador no precisa se preocupar em computar a quantidade de memria necessria, como foi dito, isso feito automaticamente pelo comando sizeof(struct jogador). Um ponto importante a ser observado que o operador para acessar os campos de um registro alocado dinamicamente o -> e no o operador ponto .. O cdigo a seguir ilustra a alocao dinmica de registro e o preenchimento de seus campos. Perceba na linhas 12 e 13 que a alocao dinmica do registro feita, o preenchimento de seus campos feitos nas linhas 16 a 18 e nas linhas 20 e 21 os valores gravados so impressos. Note que o operador -> foi utilizado para acessar os campos do registro, tanto no preenchimento quanto na impresso. Na linha 22 a memria alocada liberada usando o comando free(ptr).
/* programa que aloca dinamicamente um registro */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct jogador { char nome[40]; float salario; unsigned gols; }; int main(){
65 / 72

Linguagem de Programao I
struct jogador *ptr;// define um ponteiro para o registro jogador ptr = (struct jogador*) malloc(sizeof(struct jogador)); // aloca dinamicamente // um registro do tipo jogador // preenchendo o registro strcpy(ptr->nome, "Tulipa Goleador "); ptr->salario = 3000; ptr->gols=2; // imprimindo o registro printf("Contratacao de %s com salario R$ %.1f e %u gols na temporada. \n\n", ptr->nome, ptr->salario, ptr->gols); free(ptr); system("pause"); return 0; }

possvel tambm denir vetores de registros, i.e., vetores cujos elementos so registros. Em outras palavras, em cada posio desse vetor gravado um registro inteiro. A Fig. 3.10 mostra um vetor de registro para o caso da estrutura jogador denida no incio dessa seo. Note que, como destacado na gura, em cada posio do vetor tem-se armazenado os campos denidos na estrutura jogador, ou seja, os campos nome, salario e gols. Fig. 3.10: Ilustrao de um vetor de estruturas. Primeiramente, ser mostrado como denir um vetor de estruturas para, se seguida apresentar como feita a alocao dinmica de um vetor de estruturas. Considerando a estrutura jogador, denida no incio da seo, um vetor de estruturas pode ser denido da seguinte forma: struct jogador Treze[22]; em que, struct a palavra obrigatria na sintaxe do comando para especicar que trata-se de um registro ou estrutura, jogador o tipo de registro que se pretende criar o vetor e Treze o nome do vetor que acabou de ser criado. Observe que foi criado um vetor de estruturas com 22 posies. O exemplo a seguir mostra um cdigo para preenchimento de um de vetor de estruturas com 22 posies ilustrando o cadastramento de uma equipe de futebol com 22 jogadores. Note nas linhas 15 a 17 e 21 e 22 que o operador ponto . utilizado para acessar os campos do registro.
/* programa que preenche um vetor de registros */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct jogador { char nome[40]; float salario; unsigned gols; }; int main(){ int i; struct jogador Treze[22]; for (i=0;i<22;i++) { printf("Digite o nome, salario e gols do jogador %d do Treze : \n", i +1); scanf("%s", &Treze[i].nome); scanf("%f", &Treze[i].salario);
66 / 72

Linguagem de Programao I
scanf("%u", &Treze[i].gols); } printf("Time do Treze: \n"); for(i=0;i<22;i++){ printf("%s \n", Treze[i].nome); printf("Com salario %0.1f \n", Treze[i].salario); } system("pause"); return 0; }

A alocao de um vetor de registros dinamicamente segue a mesma lgica que j foi vista para um vetor de outros tipos (int, float, double, etc.). Ou seja, deve-se inicialmente denir um ponteiro para o tipo de estrutura/tipo que se deseja alocar e em seguida usa-se a funo malloc para fazer a alocao dos espaos necessrios que iram formar o vetor de registros. Seguindo esse raciocnio, tem-se para o caso de um registro jogador: struct jogador *Treze; Treze = (struct jogador*) malloc(22*sizeof(struct jogador)); O exemplo a seguir o mesmo cdigo do exemplo anterior s que nesse caso o vetor de registros foi alocado dinamicamente. Note que na linha 25 o ponteiro Treze liberado. Um detalhe de implementao que o operador ponto . foi utilizado para acessar os campos do vetor de registros pois a notao Treze[i] a notao de vetor. Se a notao de ponteiro tivesse sido utilizada, ou seja (Treze + i), os campos seriam acessados usando-se o operador deveria ser usado. Assim, os campos seriam acessados por (Treze + i) ->nome, (Treze + i) ->salario e (Treze + i)->gols.
/* programa que aloca dinamicamente e preenche um vetor de registros */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct jogador { char nome[40]; float salario; unsigned gols; }; int main(){ int i; struct jogador Treze[22]; for (i=0;i<22;i++){ printf("Digite o nome, salario e gols do jogador %d do Treze : \n", i+1); scanf("%s", &Treze[i].nome); scanf("%f", &Treze[i].salario); scanf("%u", &Treze[i].gols); } printf("Time do Treze: \n"); for(i=0;i<22;i++){ printf("%s \n", Treze[i].nome); printf("Com salario %0.1f \n", Treze[i].salario); }
67 / 72

Linguagem de Programao I
free(Treze); system("pause"); return 0; }

4.3

Atividades

1. Explique a diferena entre alocao esttica e dinmica de memria, citando vantagens e dando exemplo de uso. D pelos menos cinco situaes nas quais alocao dinmica de memria se faz necessria. Na sua resposta, use as Figs. 3.7 e 3.8 para ilustrar a utilizao da memria do computador em cada um dos esquemas de alocao. 2. Explique dando exemplos de como funciona as funes malloc(), realloc() e free(). Faa uma pesquisa em livros, internet, etc. . . , e explique como funciona o comando calloc(), o qual no foi apresentado no texto desse captulo. 3. Um professor de uma disciplina deseja montar um programa em linguagem C que seja capaz de receber as mdias dos alunos de uma turma. O programa deve gravar as mdias em um vetor que alocado dinamicamente e ao nal liberado. Para dar uma ajuda ao professor, faa um programa que atenda o que foi dito. O programa deve conter uma funo ou subrotina que receba o vetor com as mdias, o qual foi alocado dinamicamente no programa, e calcular e retornar: i) a mdia da turma; ii) quantos alunos foram aprovados por mdia; iii) quantos alunos esto na prova nal. Dica: Considere que o aluno aprovado por mdia se media>=7,0. Se 3,5<media<7,0, o aluno estar na prova nal. 4. Considerando a estrutura struct Ponto { int x; int y; }; Para representar um ponto em uma grade 2D. Implemente um programa em C que contenha uma funo ou sub-rotina que indique se um ponto p est localizado dentro ou fora de um retngulo. O retngulo denido por seus vrtices inferior esquerdo v1 e superior direito v2. A funo deve retornar 1 caso o ponto esteja localizado dentro do retngulo e 0 caso contrrio. Use alocao dinmica de memria para alocar dinamicamente a estrutura Ponto. Essa funo deve obedecer ao prottipo: int dentroRet (struct Ponto* v1, struct Ponto* v2, struct Ponto* p).

5. Considerando a estrutura Jogador denida na Seo 3.4.4, implemente um programa em C que preencha e imprima na tela todos os jogadores de todos os times de futebol do Campeonato Brasileiro da Srie A. Considere que cada time possui 11 jogadores. Use alocao dinmica de memria na sua soluo.

68 / 72

Linguagem de Programao I

Dica Crie uma funo ou sub-rotina no programa, algo como Cadastra_equipe, para cadastrar uma equipe de futebol. Voc poder utilizar essa funo para cadastrar as 20 equipes de futebol do Campeonato Brasileiro da Srie A. Faa o mesmo para a parte da impresso na tela.

6. Discuta o conceito de registros dinmicos, matrizes dinmicas e vetores dinmicos dando exemplos e fazendo comparaes. Usando o mtodo da Seo 3.4.3.2 para representar matrizes de duas dimenses, possvel representar matrizes com trs dimenses? Justique a sua resposta.

69 / 72

Linguagem de Programao I

Captulo 5 Respostas das atividades


Nesta captulo apresentamos as respostas de algumas atividades.

Nota Voc pode contribuir para elaborao desta seo enviando suas respostas.

Dica Na sala de aula, nos fruns e mensagens recomendamos a utilizao do site https://gist.github.com para compartilhar cdigos e tirar dvidas sobre eles.

5.1

Captulo 1

Sem respostas.

5.2

Captulo 2

3d. No existe resposta nica. Nesta resposta optamos por criar dois registros, um para organizar o Agendamento e outro para agrupar os campos do Horrio. As tabelas a seguir mostram o resultado da anlise. Novo tipo codigo # titulo local horario detalhes Campo Tipo do campo Numrico Textual Textual Horario Textual

Compromisso

Exemplos de outros campos que poderiam existir so: tipo do compromisso, recorrencia do compromisso, participantes, horario de termino etc.
70 / 72

Linguagem de Programao I No tipo de registro Compromisso, nossa primeira tentativa de denir um campo identicador foi de utilizar titulo, mas percebemos que poderia haver mais de um compromisso com o mesmo ttulo. Outro possvel campo seria o horario, no entanto possvel existir dois compromissos com o mesmo horrio. Portanto criamos um campo codigo para identicar os registros. Novo tipo ano # mes # dia # hora # minuto # Campo Tipo do campo Numrico Numrico Numrico Numrico Numrico

Horario

No tipo Horario percebemos que todos os campos juntos identicam um registro. Caso dois registros possuam os mesmos valores ento eles representam um mesmo Horario. Cdigo fonte code/respostas/reg_compromisso.c Tipos dos registros Compromisso e Horario.
typedef struct { short ano; short mes; short dia; short hora; short minuto; } Horario; typedef struct { int codigo; char titulo[100]; char local[100]; char detalhes[255]; Horario horario; } Compromisso;

71 / 72

Linguagem de Programao I

Captulo 6 ndice Remissivo


A Algoritmos, 2 algoritmos, 2 Alocao dinmica, 59 alocao dinmica, 58 alocao esttica, 58 C Campo Identicador, 19 E escopo de uma funo, 52 esttico, 58 estruturas de dados, 4 F free, 59 funo, 52 I indireo, 48 M malloc, 59 memria dinmica, 58 O operador de endereo, 47, 49, 51 operador de indireo, 48, 49, 51 P parmetros por referncia, 54 passagem por parmetro, 54 passagem por valor, 53 persistncia, 18 pilha de execuo, 52, 53 Ponteiro, 48 indireo, 48 ponteiro, 51 ponteiros, 55
72 / 72

prottipo da funo, 55 R realloc, 59 Registro, 17 sintaxe, 19 relacionamento, 25 S sintaxe, 19 T Tipo de dado, 19 Tipos de dados, 4 V variveis, 4 variveis locais, 52 varivel local, 52