Вы находитесь на странице: 1из 104

Programação I

Sônia Virginia Alves França

Volume 3

Recife, 2009
Universidade Federal Rural de Pernambuco

Reitor: Prof. Valmar Corrêa de Andrade


Vice-Reitor: Prof. Reginaldo Barros
Pró-Reitor de Administração: Prof. Francisco Fernando Ramos Carvalho
Pró-Reitor de Extensão: Prof. Paulo Donizeti Siepierski
Pró-Reitor de Pesquisa e Pós-Graduação: Prof. Fernando José Freire
Pró-Reitor de Planejamento: Prof. Rinaldo Luiz Caraciolo Ferreira
Pró-Reitora de Ensino de Graduação: Profª. Maria José de Sena
Coordenação de Ensino a Distância: Profª Marizete Silva Santos

Produção Gráfica e Editorial


Capa e Editoração: Allyson Vila Nova, Rafael Lira e Italo Amorim
Revisão Ortográfica: Marcelo Melo
Ilustrações: Diego Almeida e Glaydson da Silva
Coordenação de Produção: Marizete Silva Santos
Sumário

Apresentação.........................................................................................5

Conhecendo o Volume 3.......................................................................6

Capítulo 1 – Armazenamento de Dados em Vetores..........................8

1.1 O que são vetores?.......................................................................8

1.2 Declaração de Vetores..................................................................9

1.3 Referência a elementos de vetor................................................. 11

1.4 Inicialização de vetores...............................................................13

1.5 Leitura de elementos para o vetor...............................................15

1.6 Impressão dos elementos de um vetor........................................22

1.7 Tamanho de um vetor e segmentação de memória....................27

1.8 Passando vetores como parâmetros de funções........................28

Capítulo 2 – Armazenamento de Dados em Registros.....................35

2.1 O que são registros?...................................................................35

2.2 Declaração de um Registro.........................................................36

2.3 Acessando os campos do registro...............................................39

2.4 Vetor de registro..........................................................................40

2.5 Acessando os campos do vetor de registro.................................42

2.6 Usando vetor de registro.............................................................43


Capítulo 3 – Armazenamento de Dados em Arquivos......................61

3.1 O que são arquivos?....................................................................61

3.2 Comandos para manipular arquivos binários..............................64

3.3 Implementação das operações básicas em um arquivo..............76

Considerações Finais........................................................................103

Conhecendo a Autora........................................................................104
Apresentação

Caro(a) cursista,

Seja bem-vindo (a) ao terceiro módulo da disciplina Programação I. Neste módulo,


vamos dar mais um passo no nosso aprendizado sobre a linguagem de programação
C.

Nos dois volumes anteriores, aprendemos os comandos básicos do C, a utilizar


as estruturas de controle (seleção e repetição) e a modularizar nossos programas em
módulos ou funções. Com estes assuntos, adquirimos a capacidade de desenvolver
programas mais elaborados.

Neste livro, nós vamos aprender novas formas de armazenar nossos dados. Com os
vetores e registros, poderemos manusear um volume maior de dados, de forma facilitada.
Outro assunto muito importante que será abordado neste volume é o armazenamento de
dados em arquivos. Atualmente, ao terminar a execução do programa, todos os dados
que foram digitados são perdidos. Com o armazenamento de dados em arquivos, isto
não acontece. Assim, iremos desenvolver programas com operações como: cadastro de
elementos, remoção, alteração, consultas, listagens, etc.

Continuem resolvendo as questões propostas no final de cada capítulo, além de


executar buscas na Internet, visando um maior aprofundamento de cada assunto. Ao final
deste módulo, teremos a capacidade de resolver questões com operações presentes
nos principais sistemas de controle do mercado, como por exemplo: sistema de controle
de estoque, sistema de controle de cliente, etc. Vamos começar mais uma nova etapa
no conhecimento da linguagem de programação C?

Bons estudos!

Professora Sônia Virginia Alves França


Programação I

Conhecendo o Volume 3

Neste terceiro volume, vocês irão encontrar o módulo 3 da


disciplina: Programação I. Este volume está estruturado em três
capítulos, que serão estudados ao longo de 15h/aula. Para facilitar
seus estudos, veja a organização deste volume.

Capítulo 1: Armazenamento de Dados em Vetores

Carga Horária do Capítulo 1: 5 h/aula

Objetivos do Capítulo 1: Apresentar o uso de vetores para o


armazenamento de dados.

Conteúdo Programático do Capítulo 1

» Definição de vetores;

» Declaração, leitura e escrita de dados em vetores;

» Passagem de vetores como parâmetros de funções;

Capítulo 2: Armazenamento de Dados em Registros

Carga Horária do Capítulo 2: 5 h/aula

Objetivos do Capítulo 2: Apresentar o uso de registros para o


armazenamento de dados.

Conteúdo Programático do Capítulo 2

» Definição de registros;

» Declaração, leitura e escrita de dados em registros;

» Vetor de registro;

Capítulo 3: Armazenamento de Dados em Arquivos

Carga Horária do Capítulo 3: 5 h/aula

Objetivos do Capítulo 3: Apresentar os principais comandos para


o armazenamento de dados em arquivos. Com os arquivos, os dados
manipulados no programa podem ser armazenados definitivamente.

Conteúdo Programático do Capítulo 3

» Definição de arquivos;

6
Programação I

» Ponteiros;

» Comandos para manipulação de dados em arquivos;

Ao final de cada capítulo vocês encontrarão:

» A seção “Atividades e Orientações de Estudo”: que contém


exercícios para a fixação do assunto estudado, além de
indicação de fóruns de discussão.

» A seção “Conheça Mais”: que contém dicas de sites e livros


que devem ser lidos para ampliar os seus conhecimentos.

» A seção “Vamos Revisar?”: que apresenta um resumo dos


principais tópicos abordados no capítulo.

7
Programação I

Capítulo 1 – Armazenamento de
Dados em Vetores

Vamos conversar sobre o assunto?

Neste terceiro volume, vamos aprender novas formas de armazenar


nossos dados. Começaremos aprendendo como armazenar os dados
em vetores. Com os vetores, nós podemos armazenar um grande
conjunto de dados, facilitando o acesso e manuseio dos mesmos. Os
dados são a “alma” de um programa. Assim, a manipulação dos dados
de forma mais adequada e facilitada trará ganhos para o programa e
para o programador. Vamos continuar a nossa caminhada?

1.1 O que são vetores?

Imaginem que um professor nos encomendou um programa, que


tenha que armazenar as médias dos 50 alunos de uma turma. Como
faríamos para armazenar essas médias? Até o ponto que estudamos
a linguagem C, teríamos que declarar 50 variáveis do tipo float, uma
por uma. Que trabalheira, não é mesmo? E se o professor tivesse 300
alunos? Passaríamos um tempão só declarando variáveis e, além
disso, teríamos muito trabalho para fazer o controle das mesmas.
Mas não se preocupem, com os vetores, o professor pode ter mais de
1000 alunos, que a declaração e manuseio dos dados será bem fácil.

Os vetores são usados quando precisamos armazenar um conjunto


Saiba Mais
de dados do mesmo tipo. Por exemplo: armazenar as 50 médias dos
alunos de uma turma (todas as médias são do tipo float). Os vetores
1
Em inglês, um
vetor é chamado são bem convenientes já que iremos colocar todas as informações
de array (que
significa cadeia). dentro de um mesmo conjunto e faremos referência de cada dado,
Assim, quando individualmente, através de um índice1. De maneira mais formal, os
temos um array,
temos uma cadeia vetores são chamados de estruturas de dados homogêneas (já
de inteiros, reais
ou caracteres. que armazenam dados do mesmo tipo). Os vetores são formados
por dados de mesmo tipo (homogêneo) e possuem número fixo de
elementos (estático).

Para entendermos melhor os vetores, vamos visualizar a sua


representação gráfica, na figura 1.1.

8
Programação I

media 3.0 7.5 5.8 9.5 8.2

0 1 2 3 4

Figura 1.1: Representação gráfica de um vetor

Na figura 1.1, temos um vetor chamado media, formado por 5


elementos. Vocês lembram quando tínhamos uma variável simples?
Representávamos com uma única caixa. Agora, com os vetores,
teremos um conjunto de dados, por isso ele é formado por várias
caixas. Em cada uma delas poderemos armazenar um valor. Todas as
caixas têm um único nome. Neste exemplo, o vetor se chama media.
Notem que, abaixo de cada caixa temos um número. Estes números
são chamados de índices. É através do índice, que iremos informar
qual das caixas do vetor é que estamos querendo acessar. Já que
todas as caixas têm um único nome (media), a forma de diferenciar
uma da outra é o índice. Entenderam?

Na linguagem C, o índice de um vetor, começa a partir de 0. Assim,


em um vetor com 5 elementos, os índices variam de 0 a 4 (como no
exemplo da figura 1.1). Por isso, o primeiro elemento do vetor media
está na posição de índice 0. Podemos dizer que a média do segundo
aluno está na posição de índice 1 do vetor media, e é igual a 7.5.

Esta não é a única maneira de estruturar um conjunto de dados.


Também podemos organizar dados sob forma de tabelas. Neste caso,
cada dado é referenciado por dois índices e dizemos que se trata de
um conjunto bidimensional (ou matriz).

Vamos aprender, nas próximas seções, como manusear os vetores


nos nossos programas.

1.2 Declaração de Vetores

Como já foi mencionado, um vetor é um conjunto de variáveis


do mesmo tipo, que possuem um nome identificador e um índice de
referência. A sintaxe para a declaração de um vetor é a seguinte:

Sintaxe

tipo identificador[tamanho];

9
Programação I

onde:

» tipo: é o tipo de dados que o vetor armazena: int, float, char,


etc.

» identificador: é o nome do vetor. As regras para nomear um


vetor são as mesmas usadas para nomear variáveis, constantes
e funções.

» tamanho: é o tamanho do vetor. Isto é, o número de elementos


que o vetor pode armazenar.

A seguir, são apresentados exemplos de declarações de vetores.


Os vetores são declarados na seção de declaração de variáveis do
programa. Se estivermos desenvolvendo um programa modularizado,
podemos declarar o vetor como uma variável local de um módulo.

Exemplo 1.1: declaração de vetores

1 int idade[100];

2 float nota[25];

3 char nome[80];

Atenção No primeiro exemplo, temos a declaração de um vetor chamado


idade, que pode armazenar até 100 números inteiros. No segundo
2
Nós já havíamos
utilizado vetor exemplo, temos um vetor chamado nota, com capacidade para
de caracteres,
uma vez que
armazenar até 25 números reais. E, finalmente, no terceiro exemplo,
trabalhamos temos um vetor chamado nome, com capacidade de armazenar até
com variáveis
que armazenam 80 caracteres2.
uma cadeia de
caracteres. No Ao declararmos um vetor, já temos que ter uma previsão de quantos
próximo volume,
teremos um elementos serão armazenados no mesmo. Com isso, o processador
capítulo dedicado
a este assunto.
saberá quanto de memória precisa ser reservada para armazenar os
dados do vetor, ao executar o programa. A quantidade de memória
(em bytes) usada para armazenar um vetor pode ser calculada como:

quantidade de memória = tamanho do tipo * tamanho do vetor

O tamanho do tipo indica quantos bytes são necessários para


armazenar um determinado tipo de variável (vimos este assunto no
Volume 1 – Capítulo 3). Ao compilar o programa, a quantidade de
memória necessária para armazenar o vetor é alocada. Os vetores
têm tamanhos fixos e não podemos armazenar mais elementos do que
a quantidade que foi solicitada no momento da declaração do vetor.

10
Programação I

Por isso, são chamados de estáticos. A quantidade de elementos não


pode aumentar em tempo de execução do programa.

Também é possível declarar um vetor com tamanho parametrizado:


usando uma constante. Declaramos uma constante com a diretiva
#define, no início do programa, e depois declaramos o vetor com
esta constante como tamanho do vetor. Deste modo, podemos alterar
o número de elementos do vetor antes de qualquer compilação do
programa. Esta é uma maneira simples de administrar o espaço de
memória usado pelo programa, e também testar os limites de um
vetor.

Exemplo 1.2:
Declaração de vetor usando uma constante no local do tamanho do vetor.

1 #define TAMANHO 30

2 int valor[TAMANHO];

No exemplo 1.2, o vetor valor terá capacidade de armazenar 30


elementos (este é o valor da constante TAMANHO).

1.3 Referência a elementos de vetor

Agora que já sabemos como criar os vetores, a partir da sua


declaração, vamos aprender como acessar um elemento do vetor.
Segue abaixo a sintaxe.

Sintaxe

identificador[indice]

onde:

» identificador: é o nome do vetor que queremos acessar.

» índice: é o índice do elemento do vetor que queremos acessar.

Cada elemento do vetor é referenciado pelo nome do vetor e,


entre colchetes, tem-se o índice, que é um número inteiro. O índice
irá indicar qual elemento do vetor estamos querendo referenciar. A
seguir, são apresentadas algumas atribuições a elementos de um
vetor chamado valor, que é composto por 10 elementos do tipo float.

11
Programação I

Exemplo 1.3: Acessando os elementos de um vetor

1 float valor[10]; //declaração do vetor

2 int x;

3 x = 3;

4 valor[1] = 6.6;

5 valor[x] = 9.9

6 valor[x+2] = 10.0;

Entre os colchetes, que indicam o índice do vetor que será


acessado, podemos ter: um valor (exemplo da linha 4), uma variável
(exemplo da linha 5) ou uma expressão (exemplo da linha 6).
Devemos ter cuidado quando usamos variáveis e expressões, pois
estas devem ser inteiras e devem ter um valor dentro da capacidade
de armazenamento do vetor. Ou seja, se o vetor foi declarado com
tamanho 10, não podemos tentar acessar o índice 18 do vetor.

Na linha 4, foi atribuído 6.6 ao elemento de índice 1 do vetor valor.


Na linha 5, como a variável x tem armazenado 3, então o valor[3],
receberá 9.9. Quando temos uma expressão, que é o caso da linha
6, a expressão é resolvida primeiro. Assim, como x = 3, e entre os
colchetes temos x+2, o resultado será 5. Dessa forma, valor[5]
receberá 10.0. A seguir, temos a situação final do vetor valor, após as
atribuições dos valores do exemplo.

Valor 6.6 9.9 10.0

0 1 2 3 4 5 6 7 8 9

Figura 1.2: Situação do vetor valor após atribuições

Viram como é fácil trabalhar com vetor? Em uma única linha, nós
criamos um conjunto de variáveis, do tamanho da nossa necessidade.
Posteriormente, acessamos cada uma destas variáveis utilizando o
nome do vetor e o índice da variável.

Na próxima seção, vamos ver como fazemos para inicializar os


elementos de um vetor, no momento da declaração.

12
Programação I

1.4 Inicialização de vetores

No momento da declaração de um vetor, também podemos


inicializar os seus elementos, fazendo a atribuição de valores aos
mesmos. A sintaxe para a inicialização dos elementos de um vetor é
a seguinte:

Sintaxe

tipo identificador[tamanho] = {lista de valores};

Onde:

» tipo: é o tipo dos elementos do vetor: int, float, char, etc.

» identificador: é o nome do vetor.

» tamanho: é o tamanho do vetor. Isto é, o número de elementos


que o vetor pode armazenar.

» lista de valores: é uma lista, separada por vírgulas, dos valores


de cada elemento do vetor. A lista de valores é colocada entre
chaves.

Vamos ver a seguir, exemplos de inicialização de vetores.

Exemplo 1.4: Inicialização de vetores

1 int idade[7] = {12, 30, 14, 7, 13, 15, 6};

2 char vogal[5] = {‘a’, ‘e’, ‘i’, ‘o’, ‘u’};

3 float nota[5] = {8.4, 6.9, 4.5};

4 float media[5] = {0};

No exemplo da linha 1, temos o vetor chamado idade e para cada


posição do vetor, foi atribuído um valor. Após esta atribuição, o vetor
idade ficará assim:

idade 12 30 14 7 13 15 6

0 1 2 3 4 5 6

Figura 1.3: Situação do vetor idade após inicialização

No segundo exemplo, temos um vetor de caracteres, chamado


vogal. Quando inicializamos um vetor deste tipo de variável, os valores

13
Programação I

devem ser colocados entre apóstrofo. Ao final desta atribuição, o vetor


vogal ficará como mostra a figura 1.4.

vogal a e i o u

0 1 2 3 4

Figura 1.4: Situação do vetor idade após inicialização

Na linha 3, temos a inicialização do vetor nota, que é composto


por cinco elementos. Notem que, entre as chaves, não temos cinco
valores. Temos apenas três. Quando não quisermos inicializar todo o
vetor, podemos colocar apenas os valores dos primeiros elementos, e
aos demais, será atribuído zero (automaticamente). Vejam na figura
1.5 como ficará o vetor nota, após a sua inicialização.

nota 8.4 6.9 4.5 0.0 0.0

0 1 2 3 4

Figura 1.5: Situação do vetor idade após inicialização

Seguindo o raciocínio do exemplo anterior, quando precisarmos


inicializar todos os elementos do vetor com zero, fazemos como
mostra o exemplo da linha 4. Colocamos apenas um zero entre as
chaves, o primeiro elemento será inicializado com zero, e os demais
também. Neste caso, o vetor media ficará como apresentado na figura
1.6.

media 0.0 0.0 0.0 0.0 0.0

0 1 2 3 4

Figura 1.6: Situação do vetor media após inicialização

Opcionalmente, podemos inicializar os elementos do vetor


enumerando-os um a um. No exemplo 1.5, a seguir, observem que
estas duas inicializações são possíveis:

14
Programação I

Exemplo 1.5: Inicialização de vetores

1 int valor[3] = {7,4,20};

2 ou

3 int valor[3];

4 valor[0] = 7;

5 valor[1] = 4;

6 valor[2] = 20;

Na próxima seção, vamos aprender a armazenar, em um vetor,


valores que são fornecidos via teclado.

1.5 Leitura de elementos para o vetor

Agora suponham que os valores que vão ser armazenados no


vetor sejam fornecidos pelo usuário, via teclado. O que devemos
fazer? Devemos utilizar uma estrutura de repetição, para controlar o
preenchimento dos dados no vetor, um por um. Assim, podem ocorrer
duas situações:

» Nós sabemos quantos elementos o usuário vai digitar;

» Nós não sabemos a quantidade de elementos que o usuário


vai digitar.

Vamos ver como tratar cada uma das situações? Quando nós
sabemos quantos elementos o usuário vai digitar, poderemos usar
uma estrutura de repetição como o for, que irá repetir a leitura dos
elementos, na quantidade definida. Vamos ver o Programa Completo
1.1 a seguir: o usuário precisa armazenar 5 elementos em um vetor
de inteiros, chamado valor.

15
Programação I

Programa Completo 1.1:


Ler 5 números inteiros, armazenando-os em um vetor

1 main()

2 {

3 int valor[5];

4 int i;

5 printf(“Cadastro dos elementos do vetor Valor


\n\n”);

6 for (i=0; i<5; i++)

7 { printf(“\n\nElemento %d: “,i+1);

8 scanf(“%d”,&valor[i]);

9 }

10 getche();

11 }

Comentários sobre o Programa Completo 1.1:

» Linha 3: declaração do vetor valor, que tem a capacidade de


armazenar 5 números inteiros.

» Linha 4: declaração da variável i, que irá controlar o for.

» Linha 5: printf para que o usuário saiba que será feito o cadastro
dos elementos no vetor.

» Linha 6: for que será repetido 5 vezes, fazendo a leitura dos


elementos do vetor. Notem que a variável de controle do for, o i,
é inicializado com 0. Isso acontece porque o primeiro índice do
vetor é 0.

» Linha 7: Abre chaves que inicia a sequência de comandos


do for (já que teremos mais de um comando). Nesta linha,
também temos o printf para que o usuário saiba qual elemento
do vetor está sendo cadastrado no momento. Vejam que neste
printf temos a expressão: i+1. O motivo de colocarmos esta
expressão no printf é que, como o i começa com zero e vai até
4, não ficaria muito interessante que saísse uma mensagem, na
tela, informando que o usuário estaria cadastrando o elemento
0. O correto é dizer que ele está cadastrando o elemento 1. Por

16
Programação I

isso, usamos a expressão i+1.

» Linha 8: scanf que lê o valor, armazenando no vetor. Notem


que estamos usando a variável i, no índice do vetor. Dessa
forma, o i vai variando a cada vez que o for é repetido, e assim,
os elementos são armazenados em índices diferentes do vetor.
Com isso, nenhum elemento irá sobrepor o outro.

» Linha 9: fecha chaves que indica o final da sequência de


comandos do for.

» Linha 10: comando getche que faz com que a tela de execução
do programa fique aberta, e assim podemos ver o resultado do
programa.

» Linha 11: fecha chaves, indicando o final do programa


principal.

A figura 1.7, apresenta a tela de execução do Programa Completo


1.1.

Figura 1.7: Tela de execução do Programa Completo 1.1

Para facilitar o entendimento, vamos fazer um acompanhamento


dos valores das variáveis do Programa Completo 1.1, ao longo da
sua execução. Vamos considerar que o usuário está cadastrando os
valores apresentados na figura 1.7. A figura 1.8 mostra os valores das
variáveis do programa, conforme o programa vai sendo executado.

17
Programação I

i i+1 valor

0 1 10

0 1 2 3 4

10 15
1 2

0 1 2 3 4

2 3 10 15 9

0 1 2 3 4

10 15 9 6
3 4

0 1 2 3 4

4 5 10 15 9 6 12

0 1 2 3 4

Figura 1.8: Acompanhamento das variáveis do Programa Completo 1.1

O que fazemos quando não sabemos quantos elementos serão


armazenados no vetor? Neste caso, como não sabemos quantas
vezes o for deve ser executado, poderemos fazer a leitura dos dados
que serão colocados no vetor, usando um do/while, como mostra o
Programa Completo 1.2, a seguir. Neste programa, iremos fazer
a leitura de uma quantidade indeterminada de números inteiros,
armazenando em um vetor.

18
Programação I

Programa Completo 1.2:


Ler um conjunto de números inteiros, armazenando-os em um vetor.

1 main()

2 { int valor[5];

3 int q, continuar;

4 q=0;

5 printf(“Cadastro dos elementos do vetor Valor


\n\n”);

6 do

7 { printf(“\n\nElemento %d: “,q+1);

8 scanf(“%d”,&valor[q]);

9 q++;

10 printf(“\n\nCadastrar outro elemento


(1-sim/2-nao)? “);

11 scanf(“%d”, &continuar);

12 } while ((continuar==1) && (q<5));

13 }

Neste caso, a leitura será finalizada quando o vetor ficar cheio,


com cinco elementos, ou quando o usuário decidir que não deseja
mais continuar a leitura. Neste último caso, saberemos quantos Atenção

elementos foram armazenados no vetor através da variável q. É esta 3


Quando não
variável que indica, também, em qual índice do vetor o elemento deve sabemos quantos
elementos serão
ser armazenado3. cadastrados,
temos que
Comentários sobre o Programa Completo 1.2: estipular um valor
para a quantidade
» Linha 2: declaração do vetor valor, que tem a capacidade de de elementos
que serão
armazenar 5 números inteiros. armazenados no
vetor. Isso se dá
porque temos que
» Linha 3: declaração das variáveis q (que controlam a
saber o tamanho
quantidade de elementos que já foram cadastrados no vetor) e do vetor no
momento da sua
continuar (que armazena a resposta do usuário informando se declaração.
quer cadastrar mais elementos ou não).

» Linha 4: inicialização da variável q com 0.

» Linha 5: printf para que o usuário saiba que será feito o cadastro

19
Programação I

dos elementos no vetor.

» Linha 6: do indicando o início da repetição.

» Linha 7: Abre chaves que inicia a sequência de comandos do


do/while (já que teremos mais de um comando). Nesta linha,
também temos o printf para que o usuário saiba qual elemento
do vetor está sendo cadastrado no momento.

» Linha 8: scanf que lê o valor que será armazenado no vetor.


Notem que estamos usando a variável q, no índice do vetor.

» Linha 9: incremento da variável q, indicando que mais um


elemento foi cadastrado no vetor. Através do valor de q,
saberemos se o vetor já está cheio ou não.

» Linha 10: prinft que pergunta ao usuário se deseja cadastrar


outro elemento no vetor. O usuário pode parar o cadastro dos
elemento do vetor, no momento que ele desejar. Nesse caso, o
vetor pode ficar com posições sem valores armazenados.

» Linha 11: scanf para ler a resposta do usuário.

» Linha 12: fecha chaves do do/while e while com a condição


que faz com que a repetição fique sendo executada. Como
a condição é formada por duas expressões relacionais, nós
colocamos cada expressão relacional entre parênteses e depois
colocamos toda a expressão entre parênteses. As expressões
estão conectadas pelo operador && (e). Com isso, quando uma
das expressões der falso, a repetição para. Vai parar porque
o vetor está cheio (q=5) ou porque o usuário desejou parar,
respondendo 2 a pergunta se deseja continuar.

» Linha 13: fecha chaves, indicando o final do programa


principal.

A figura 1.9, apresenta a tela de execução do Programa Completo


1.2.

20
Programação I

Figura 1.9: Tela de execução do Programa Completo 1.2

Vamos acompanhar o valor das variáveis do Programa Completo


1.2? A Figura 1.9 mostra o cadastramento de 3 elementos no vetor. O
usuário respondeu que não queria mais cadastrar após dar entrada
ao terceiro elemento. A figura 1.10 mostra os valores das variáveis do
programa, conforme o programa vai sendo executado.

q q+1 valor

12
0 1

0 1 2 3 4

12 15
1 2

0 1 2 3 4

2 3 12 15 18

0 1 2 3 4

Figura 1.10: Acompanhamento das variáveis do Programa Completo 1.2

Agora que já sabemos colocar informações em um vetor via


teclado, vamos ver como apresentar, na tela, os valores armazenados
em um vetor.

21
Programação I

1.6 Impressão dos elementos de um vetor

Quando desejarmos apresentar os elementos que estão


armazenados no vetor, devemos utilizar uma estrutura de repetição,
que fará com que cada uma das posições do vetor seja “visitada” e
seu conteúdo apresentado. Vale lembrar que, quando declaramos um
vetor, indicamos a sua capacidade de armazenamento. Mas durante a
execução do programa, pode ser que o usuário não armazene dados
suficiente para preencher todas as posições do vetor. Assim, quando
formos imprimir os dados de um vetor, precisamos saber quantos
elementos têm armazenado no momento da impressão. O Programa
Completo 1.3, mostra a leitura e a impressão dos dados armazenados
em um vetor.

Programa Completo 1.3: Ler e imprimir um conjunto de números inteiros,


armazenando-os em um vetor.

1 main()

2 { int valor[5];

3 int q, continuar, i;

4 q=0;

5 printf(“Cadastro dos elementos do vetor Valor


\n\n”);

6 do

7 { printf(“\n\nElemento %d: “,q+1);

8 scanf(“%d”,&valor[q]);

9 q++;

10 printf(“\n\nCadastrar outro elemento


(1-sim/2-nao)? “);

11 scanf(“%d”, &continuar);

12 } while ((continuar==1) && (q<5));

13 printf(“\n\nElementos do Vetor: “);

14 for (i=0; i<q; i++)

15 printf(“ %d “,valor[i]);

16 getche();

17 }

22
Programação I

Até a linha 12, o Programa Completo 1.3 é, praticamente, idêntico


ao Programa Completo 1.2. A única diferença é que temos, na linha
3, a declaração da variável i, que será usada no for que imprimirá os
elementos do vetor. Vamos ver o que está acontecendo nas demais
linhas?

» Linha 13: printf para informar que serão apresentados os


elementos do vetor. Notem que o texto entre aspas não termina
com \n. Isso se dá porque não queremos que o cursor vá para
a linha seguinte.

» Linha 14: for que será utilizado para percorrer o vetor,


acessando cada uma das posições do vetor. A variável que tem
a informação de quantos elementos foram armazenados no
vetor é q. Dessa forma, o i do for vai variar de 0 até q-1. Uma
vez que se q for 3, a última posição ocupada no vetor é 2.

» Linha 15: printf que apresenta o elemento do vetor, na posição


de índice i. Este printf também não tem o \n, porque queremos
que os elementos do vetor sejam impressos um ao lado do
outro. Este é o único comando do for, por isso não houve a
necessidade de delimitar com chaves.

» Linha 16: getche que evita o fechamento da janela de execução


do programa, e assim poderemos ver os elementos do vetor
impresso.

» Linha 17: fecha chaves, indicando o final do programa


principal.

A figura 1.11 apresenta a tela de execução do programa 1.3. Foram


cadastrados os mesmos valores do exemplo anterior.

23
Programação I

Figura 1.11: Tela de execução do Programa Completo 1.3

Neste caso, apesar do vetor ter sido declarado com 5 posições, só


foram preenchidas 3 posições. Vejam que, após o usuário responder
que não quer mais cadastrar, os elementos do vetor são apresentados
um ao lado do outro.

Vamos ver outro Programa Completo? Neste programa, iremos


ler as matrículas e notas dos alunos de uma turma e imprimir as
matrículas dos alunos de tiveram nota acima da média das notas da
turma.

Programa Completo 1.4

1 main()

2 { int mat[10];

3 float nota[10];

4 int q, i, continuar;

5 float soma, media;

6 soma = 0;

7 q=0;

8 do

9 { system(“cls”);

10 printf(“Universidade Aberta do Brasil -


UFRPE\n\n”);

24
Programação I

11 printf(“\n\nDados do Alunos %d\n\n”,


q+1);

12 printf(“\nMatricula: “);

13 scanf(“%d”,&mat[q]);

14 printf(“\nNota: “);

15 scanf(“%f”,&nota[q]);

16 soma = soma + nota[q];

17 q++;

18 printf(“\n\nCadastrar outro(1-sim/2-nao)?
“);

19 scanf(“%d”, &continuar);

20 } while ((continuar==1) && (q<10));

21 media = soma/q;

22 system(“cls”);

23 printf(“Universidade Aberta do Brasil - UFRPE


\n\n”);

24 printf(“Media da turma: %.2f\n\n\n”,media);

25 printf(“Alunos com nota acima da media da


turma\n\n”);

26 for (i=0; i<q; i++)

27 { if (nota[i]>media)

28 printf(“%d \n”,mat[i]);

29 }

30 printf(“\n\nDigite qualquer tecla para sair


“);

31 getche();

32 }

Comentários sobre o Programa Completo 1.4:

» Linhas 2 a 5: declaração das variáveis do programa. Vejam


que precisamos de um vetor para armazenar as matrículas e
um outro para armazenar as notas.

25
Programação I

» Linhas 6 e 7: inicialização das variáveis soma (que acumula as


notas de todos os alunos) e q (que conta quantos elementos
foram cadastrados no vetor).

» Linhas 8 a 20: do/while que faz a leitura das matrículas e das


notas de cada aluno, armazenando nos respectivos vetores.
Neste do/while, o usuário pode parar o cadastro no momento
que ele desejar. Para calcularmos a média da turma, temos que
somar as notas de todos os alunos e dividir pela quantidade
de alunos. Assim, enquanto estivermos no do/while, estamos
acumulando as notas de todos os alunos na variável soma.

» Linha 21: ao sair do do/while, a média da turma pode ser


calculada.

» Linha 22: usa o system(“cls”) para limpar a tela e dar início à


tela que irá apresentar os resultados.

» Linha 24: printf para apresentar a média da turma.

» Linhas 26 a 29: for para visitar cada posição do vetor que


armazena as notas dos alunos. Quando verifica que a nota do
aluno é maior que a média da turma (armazenada na variável
media), a matrícula do aluno é apresentada.

A figura 1.12 apresenta a tela de execução do Programa Completo


1.4, na fase do cadastramento dos dados dos alunos (matrícula e
nota).

Figura 1.12: Tela de Execução do Programa Completo 1.4 – Cadastro de Alunos

A figura 1.13 apresenta a tela de execução do programa completo


1.4, na fase do apresentação dos resultados.

26
Programação I

Figura 1.13: Tela de Execução do Programa Completo 1.4 – Apresentação dos Resultados

1.7 Tamanho de um vetor e segmentação de


memória

Na linguagem C, devemos ter cuidado com os limites de um vetor.


Embora na declaração tenhamos que definir o tamanho de um vetor,
o compilador C não faz nenhum teste de verificação de acesso a um
elemento dentro do vetor ou não.

Por exemplo, se declaramos um vetor como int valor[5],


teoricamente, só tem sentido usarmos os elementos valor[0], valor[1],
valor[2] , valor[3] e valor[4]. Porém, o compilador C não acusa erro se
usarmos valor[12] em algum lugar do programa. Estes testes de limite
devem ser feitos dentro do programa, pelo programador.

Este fato se deve à maneira como o C trata os vetores. A memória


do computador é um espaço (físico) particionado em porções de 1
byte. Se declararmos um vetor como int valor[3], estamos reservando
12 bytes (3 segmentos de 4 bytes – lembrando que cada int ocupa
4 bytes) de memória para armazenar os seus elementos. O primeiro
segmento será reservado para valor[0], o segundo segmento para
valor[1] e o terceiro segmento para valor[2]. O segmento inicial é
chamado de segmento base, de modo que valor[0] será localizado no
segmento base. Quando acessamos o elemento valor[i], o processador
acessa o segmento localizado em base+i. Se i for igual a 2, estamos
acessando o segmento base+2 ou valor[2] (o último segmento
reservado para o vetor). Porém, se i for igual a 7, estamos acessando
o segmento base+7 que não foi reservado para os elementos do vetor
e que provavelmente está sendo usado por uma outra variável ou
contém uma informação inesperada (lixo).

27
Programação I

Observem que o acesso a um segmento fora do espaço destinado


a um vetor pode destruir informações reservadas de outras variáveis.
Estes erros são difíceis de detectar, pois o compilador não gera
nenhuma mensagem de erro. Por isso, a solução mais adequada é
sempre avaliar os limites de um vetor antes de manipulá-lo. Como
feito no Programa Completo 1.2 que vai cadastrando os elementos no
vetor e para quando o vetor completa a sua capacidade.

A princípio, este fato poderia parecer um defeito da linguagem,


mas na verdade trata-se de um recurso muito poderoso do C. Poder
manipular, sem restrições, todos os segmentos de memória é uma
flexibilidade apreciada por programadores mais experientes.

1.8 Passando vetores como parâmetros de


funções

Os vetores, assim como as variáveis simples, podem ser usados


como argumentos de funções. Veremos como se declara uma função
que recebe um vetor como parâmetro e como se chama uma função
passando um vetor como parâmetro.

A sintaxe de uma função que recebe um vetor como parâmetro é a


seguinte:

Sintaxe

tipo_retorno nome_função(tipo_vetor nome_vetor[])

//corpo da função

Onde:

» tipo_retorno: é o tipo de retorno da função.

» nome_função: é o nome da função.

» tipo_vetor: é o tipo de dados dos elementos do vetor.

» nome_vetor: é o nome do vetor. Observe que depois do nome


do vetor temos o [ e o ], mas não colocamos nada entre eles.
Neste caso, não é necessário informar o tamanho do vetor.

Quando formos chamar uma função que recebe um vetor como

28
Programação I

parâmetro, usamos a seguinte sintaxe:

Sintaxe

nome_da_função(nome_do_vetor);

Onde:

» nome_da_função: é o nome da função que será chamada.

» nome_do_vetor: é o nome do vetor que queremos passar


como parâmetro. Neste caso, indicamos apenas o nome do
vetor, sem os colchetes.

O exemplo 1.6, a seguir, apresenta a declaração de uma função


que tem um vetor como parâmetro e a chamada da função.

Exemplo 1.6:
declaração e chamada de uma função que tem um vetor como parâmetro

1 float media(float vetor[],float N)

2 {

3 //corpo da função

4 }

6 main()

7 { float valor[30]; // declaração do vetor

8 float n;

9 ...

10 med = media(valor, n); // passagem do vetor


para a função

11 ...

12 }

Atenção: Ao contrário das variáveis comuns, o conteúdo de um


vetor pode ser modificado pela função chamada. Isto significa que
podemos passar um vetor para uma função e alterar os valores de
seus elementos. Isto ocorre porque a passagem de vetores para
funções é feita de modo especial dito passagem por endereço.
Portanto, devemos ter cuidado ao manipular os elementos de um

29
Programação I

vetor dentro de uma função para não modificá-los por descuido.

Atividades e Orientações de Estudos

Vamos fazer um conjunto de exercícios, usando o assunto que


acabamos de aprender? Segue abaixo uma lista de exercícios em
que os dados serão armazenados em vetores. Vamos começar?

1. Ler um conjunto de números e imprimi-los na ordem inversa da


leitura. A quantidade de números também será lida e será no
máximo 10.

2. Ler o tamanho e os elementos de dois vetores e, em seguida,


caso os vetores tenham o mesmo tamanho, gere e imprima o
vetor SOMA, onde seus elementos serão formados pela soma
dos elementos de mesmos índices dos dois vetores lidos.
Exemplo:

A 1 4 7 2 9

0 1 2 3 4

B 3 5 11 4 8

0 1 2 3 4

Soma 4 9 18 6 17

0 1 2 3 4

3. Ler um vetor de números e imprimir os valores armazenados


nas posições PARES e, em seguida, os valores armazenados
nas posições ÍMPARES. Exemplo:

V 1 4 7 2 9

0 1 2 3 4

Valores nas posições pares: 1 7 9

30
Programação I

Valores nas posições impares: 4 2

4. Ler dois vetores e caso tenham tamanhos iguais, armazene seus


elementos alternadamente em um terceiro vetor. Exemplo:

A 1 4 7 2 12

0 1 2 3 4

B 3 5 11 4 15

0 1 2 3 4

Resultante 1 3 4 5 7 11 2 4 12 15

0 1 2 3 4 5 6 7 8 9

5. Ler um vetor de números inteiros e imprimir as posições do


maior e do menor elemento do vetor. Assuma que não existem
elementos repetidos no vetor. Exemplo:

V 14 13 7 22 9

0 1 2 3 4

O menor elemento se encontra na posição 2

O maior elemento se encontra na posição 3

6. Ler um vetor de números e inverter a ordem dos elementos


desse vetor no próprio vetor. Exemplo:

Vetor antes de ser invertido:

V 14 13 7 22 9

0 1 2 3 4

Vetor depois de ser invertido:

31
Programação I

V 9 22 7 13 14

0 1 2 3 4

7. Ler dois vetores de números e gerar um terceiro vetor formado


pela INTERSECÇÃO dos dois vetores lidos. O resultado da
interseção de dois conjuntos é: os elementos que fazem parte
dos dois conjuntos. Exemplo:

A 1 4 7 2 12

0 1 2 3 4

B 3 4 2 14 25

0 1 2 3 4

interseccao 4 2

0 1 2 3 4

8. Ler dois vetores de números e gerar um terceiro vetor formado


pela DIFERENÇA dos dois vetores lidos. O resultado da
diferença de dois conjuntos é: os elementos do conjunto A que
não fazem parte do conjunto B. Exemplo:

A 1 4 7 2 12

0 1 2 3 4

B 3 4 2 14 25

0 1 2 3 4

Diferenca 1 7 12

0 1 2 3 4

32
Programação I

9. Ler dois vetores de números e gerar um terceiro vetor formado


pela UNIÃO dos dois vetores lidos. O resultado da união de dois
conjuntos é: todos os elementos que fazem parte dos conjuntos
A e B. Exemplo:

A 1 4 7 2 12

0 1 2 3 4

B 3 4 2 14 25

0 1 2 3 4

União 1 4 7 2 12 3 14 25

0 1 2 3 4 5 6 7 8 9

10. Ler um vetor de números e imprimir os números que se repetem


nesse vetor. Exemplo:

V 1 4 7 1 2 1 4 25 3 7

0 1 2 3 4 5 6 7 8 9

Os números que se repetem no vetor são: 1 4 7

Conheça Mais

Para ampliar nossos conhecimentos sobre os assuntos tratados


neste capítulo, leiam o capítulo que aborda armazenamento em
vetores, do livro:

SCHILDT, Herbert. C Completo e Total. São Paulo: Makron,


1996.

33
Programação I

Vamos Revisar?

Vamos lembrar rapidinho o que foi visto neste capítulo?


Leia o resumo a seguir, composto com os principais conceitos
apresentados.

Vetores: conhecidos como estruturas de dados homogêneas, os


vetores são um conjunto de variáveis que armazenam elementos
do mesmo tipo.

Índices: para acessar um elemento do vetor, precisamos indicar em


que posição do vetor está o elemento.

No momento da declaração dos vetores, precisamos indicar quantos


elementos serão armazenados no mesmo.

É de responsabilidade do programador o acesso aos elementos do


vetor. Se o programa tentar acessar uma posição que não existe no
vetor, o compilador não indicará o erro.

Quando passamos um vetor como parâmetro de uma função, seus


valores podem ser alterados

34
Programação I

Capítulo 2 – Armazenamento de
Dados em Registros

Vamos conversar sobre o assunto?

Neste capítulo, vamos aprender mais uma forma de armazenamento


de dados, que são os registros. Nos registros podemos agrupar dados
de tipos diferentes. Por conta disto, os registros são chamados de
estruturas de dados heterogêneas. Assim como os vetores, os registros
vão facilitar o gerenciamento dos dados dos nossos programas, que
estão cada vez maiores. Veremos, também, como unir os conceitos
de vetores e registros, trabalhando com vetor de registro. Leiam este
capítulo com calma e atenção, uma vez que iremos utilizar registros
em muitas situações nos nossos programas, certo?

2.1 O que são registros?

Nós já sabemos que um conjunto homogêneo de dados é composto


por variáveis do mesmo tipo (vetores). Mas, e se tivermos um conjunto
em que os elementos não são do mesmo tipo? Teremos, então, um
conjunto heterogêneo de dados, que são chamados de registros.
O registro é uma das principais formas de estruturar os dados no
programa. O conceito de registro visa facilitar o agrupamento de
variáveis de tipos diferentes, mas que possuem uma relação lógica.

Um registro é um conjunto de uma ou mais variáveis, que podem


ser de tipos diferentes, agrupadas sobre um único nome. O fato de
variáveis agrupadas em um registro poderem ser referenciadas por
um único nome, facilita a manipulação dos dados armazenados nestas
estruturas. Como exemplo de um registro, imaginem uma estrutura que
armazene as diversas informações do boletim de um aluno. O boletim
é formado por um conjunto de informações logicamente relacionadas,
porém de tipos diferentes, tais como: número de matrícula (inteiro),
nome do aluno (caractere), nome da disciplina (caractere), média (real)
e situação (caractere), que são subdivisões do registro (elementos
de conjunto), também chamadas de campos. Logo, um registro é
composto por campos que são partes que especificam cada uma das
informações. A figura 2.1 apresenta o boletim de notas de um aluno.

35
Programação I

Boletim de Notas

Matricula...: 12345

Nome........: Michel

Disciplina..: Matemática

Média........: 10.0

Situação....: Aprovado

Figura 2.1 Boletim de Notas

Notem que o boletim é composto por informações de diferentes


tipos. No entanto, todas as informações do boletim estão relacionadas
ao mesmo aluno. O agrupamento de informações de tipos diferentes,
que tem uma relação lógica, facilitará a manipulação de dados.

Nas próximas seções, vamos aprender a declarar e manipular


registros.

2.2 Declaração de um Registro

Para declarar uma variável, precisamos informar o seu tipo e dar


um nome à mesma. Mas um registro é formado por várias variáveis
de tipos diferentes. Como iremos declarar um registro? Para declarar
um registro, é necessário informar quais variáveis, e seus respectivos
tipos, fazem parte do registro. Dessa forma, precisamos declarar
cada campo do registro, agrupando-os em um novo tipo de dado.
A declaração de um registro passa por duas fases: definição de um
novo tipo de dado e declaração do registro propriamente dito. Vamos
entender melhor isso tudo?

Primeiramente, precisamos definir quais campos fazem parte


do registro e criar um novo tipo de dado para o nosso programa.
Precisamos criar um novo tipo de dado porque não conseguiríamos
representar o tipo de informação que o registro armazena, utilizando
os tipos primitivos disponíveis na linguagem: int, float, char, etc. Uma
vez que o registro agrupa variáveis de tipos de dados diferentes. Para
criar um novo tipo de dado, utilizamos a seguinte sintaxe:

36
Programação I

Sintaxe

typedef struct { declaração das variáveis;

} nome_do_tipo;

Onde:

» typedef: indica que um novo tipo de dado será definido.

» struct: indica que o tipo de dado que será definido é um


registro, ou seja, um agrupamento de variáveis de tipos de
dados diferentes.

» declaração das variáveis: são as variáveis que fazem parte do


registro. Neste local, precisamos especificar quais as variáveis
irão compor o registro, além do tipo das mesmas. As variáveis
são colocadas entre chaves.

» nome_do_tipo: é dado um nome ao novo tipo de dado que


está sendo criado. Só depois que o novo tipo de dado é criado,
é que o registro poderá ser declarado.

Na sequência, vamos ver a declaração de um registro. Assim como


toda variável, ao declarar uma variável que é um registro, precisamos
dizer que tipo de dado o registro armazena. Neste caso, iremos dizer
que o registro é do tipo de dado que acabamos de definir no typedef.
A sintaxe é a seguinte:

Sintaxe

nome_do_tipo nome_do_registro;

Onde:

» nome_do_tipo: é o nome do tipo de dado que definimos


no nosso programa, formado pelo agrupamento de várias
variáveis.

» nome_do_registro: é o nome da variável registro que está


sendo declarada. O nome de um registro segue as regras dos
identificadores.

O exemplo 2.1 apresenta a declaração do registro do boletim do


aluno:

37
Programação I

Exemplo 2.1: Definição de tipo e declaração de registro

1 typedef struct { int matricula;

2 char nome[20], disciplina[20],


situação[10];

3 float media;

4 } Tipo_Aluno;

5 Tipo_Aluno aluno;

Primeiramente, entre as linhas 1 e 4, foi definido o conjunto de


variáveis que fazem parte do registro. É nesta parte que está sendo
definido um novo tipo de dado.

» Linha 1: com o typedef estamos informando que será definido


um novo tipo de dado. O struct indica que este tipo é um
agrupamento de variáveis de tipos diferentes, ou seja, um
registro. Colocamos o abre chaves e começamos a declarar
as variáveis que irão compor o registro. Começamos com a
declaração da variável inteira matricula. Se houvesse mais
variáveis do tipo int, poderiam ser declaradas nesta mesma
linha.

» Linha 2: declaração das variáveis do tipo char: nome, disciplina


e situacao.

» Linha 3: declaração da variável media que é do tipo float.

» Linha 4: Após a declaração de todas as variáveis que compõe


o registro, podemos fechar a chaves e, em seguida, dar um
nome a esse tipo de agrupamento, que acabamos de definir.
Neste caso, o tipo foi chamado de Tipo_Aluno. Ao definirmos
um tipo de dado no nosso programa, significa que: podemos
declarar variáveis dos tipos de dados primitivos (int, float, char,
etc), além de variáveis do tipo de dado que nós definimos, neste
caso, Tipo_Aluno.

» Linha 5: declaração de uma variável chamada aluno, e o tipo


de dado que ela armazena é Tipo_Aluno, ou seja, armazena:
matricula, nome, disciplina, situacao e media.

A figura 2.2 mostra a representação gráfica da variável aluno, que


é do tipo Tipo_Aluno.

38
Programação I

matricula

nome

disciplina

situacao

media

aluno

Figura 2.2: Representação gráfica do registro aluno

Notem que, a variável aluno (que é um registro) é formada pelos


campos definidos no Tipo_Aluno.

Como uma variável registro é formada por vários campos,


precisamos utilizar uma forma diferenciada para informar qual campo
do registro nós estamos querendo acessar. Lembram dos vetores que
precisávamos dizer qual elemento do vetor seria acessado? Com os
registros vai acontecer algo parecido. Mas isto, nós vamos aprender
na próxima seção.

2.3 Acessando os campos do registro

De acordo com a figura 2.2, a variável aluno é um registro formado


por vários campos. Para acessar um campo de um registro, devemos
usar a seguinte sintaxe:

Sintaxe

nome_do_registro.campo

Onde:

» nome_do_registro: é o nome da variável registro que queremos


acessar.

Após o nome_do_registro devemos colocar um ponto, que


irá separar o nome do registro, do campo que vem logo em
seguida.

» campo: é o campo do registro que será acessado.

39
Programação I

Pensem da seguinte forma: suponham que queremos acessar


o registro aluno, do exemplo 2.1. Ao acessarmos esta variável, ela
possui vários campos. Precisamos dizer qual deles será acessado
no momento. A seguir, são apresentados exemplos de acesso aos
campos do registro aluno. Ao acessar um campo do registro, podemos
atribuir valores, como mostra o exemplo 2.2.

Exemplo 2.2: Acesso aos campos de um registro

1 aluno.matricula = 12345;

2 scanf(“%f”, &aluno.media);

3 gets(aluno.nome);

4 printf(“Situacao do aluno: %s”, aluno.situacao);

Na linha 1, estamos acessando o campo matricula do registro


Saiba Mais aluno. Assim, colocamos o nome do registro, o ponto e o campo que
queremos acessar. Com acesso ao campo, fizemos uma atribuição4.
4
O ponto que
aparece neste
comando, deve Na linha 2, estamos acessando o campo media do registro aluno.
ser lido como Neste caso, ao invés de atribuir um valor ao campo de registro, estamos
“campo”. Assim,
a leitura do fazendo uma leitura via teclado e armazenando o valor digitado no
comando da linha
1 seria: aluno no campo media. Como o campo media é do tipo float, colocamos o %f
campo matricula no scanf, indicando que será lido um número real.
recebe 12345.

Na linha 3, temos o comando de leitura gets, responsável por ler


variáveis do tipo char. Neste gets, estamos fazendo uma leitura via
teclado e armazenando o valor digitado no campo nome do registro
aluno.

Na linha 4, temos um printf que apresenta a situação do aluno.


Para isso, acessamos o campo situacao do registro aluno.

Notem que, se tivermos vários alunos em uma turma, precisaremos


de várias variáveis registro do tipo Tipo_Aluno, uma para cada
aluno. Para fazer isso de forma mais simplificada, devemos juntar os
conceitos de vetores e registros e criar um vetor de registro. Vamos
aprender como faz isto?

2.4 Vetor de registro

Os vetores são formados por um conjunto de dados do mesmo


tipo. No capítulo anterior, utilizamos vetores que armazenavam dados

40
Programação I

de tipos primitivos, ou seja, tipos disponíveis na linguagem – int,


float, char, etc. Veremos que podemos utilizar como elemento do vetor
não apenas um tipo primitivo, mas também os tipos construídos (tipos
definido pelo programador), neste caso, os registros. Imaginem que
queremos armazenar os boletins dos 50 alunos de uma turma. Para
isso, será necessário um registro diferente para cada aluno. Para
agrupar todos estes registros, iremos definir um vetor de registro.
Como possuímos 50 alunos, podemos criar um vetor no qual cada
posição armazena um Tipo_Aluno.

Para declarar um vetor de registro, precisamos antes definir os


elementos do registro, utilizando o typedef struct, e assim, definir um
novo tipo de dado que será utilizado no programa. Após definirmos o
novo tipo de dado, o vetor poderá ser declarado. Para declararmos
um vetor, precisamos informar o tipo de dado que o vetor armazena,
damos um nome ao vetor e informamos, entre colchetes, o tamanho
do vetor. O exemplo 2.3 apresenta a declaração do vetor de registro
alunos:

Exemplo 2.3: definição do registro e declaração do vetor de registro

1 typedef struct { int matricula;

2 char nome[20], disciplina[20],


situação[10];

3 float media;

4 }Tipo_Aluno;

5 Tipo_Aluno alunos[50];

Neste exemplo, cada uma das 50 posições do vetor alunos irá


armazenar todos os dados que compõe o Tipo_Aluno, ou seja:
matricula, nome, disciplina, situacao e media. A figura 2.3, a seguir,
representa o vetor de registro declarado no exemplo.

matricula matricula matricula matricula


nome nome nome nome
alunos disciplina disciplina disciplina disciplina
media media media media
situacao situacao situacao situacao

0 1 ... 48 49

Figura 2.3: Representação gráfica do vetor de registro aluno

41
Programação I

Se apenas com os vetores, já havíamos adquirido uma facilidade


na declaração e manipulação de um grande conjunto de variáveis,
com os vetores de registros, esta facilidade será aumentada.

Vamos aprender, na próxima seção, como acessamos um campo


de um vetor de registro.

2.5 Acessando os campos do vetor de


registro

Quando precisamos acessar um elemento do vetor, informamos,


entre colchetes, o índice do elemento do vetor que será acessado.
Quando queremos acessar um campo do registro, informamos o
nome da variável registro, colocamos um ponto e o nome do campo
que queremos acessar. Já no caso de um vetor de registro, temos
que usar a seguinte sintaxe:

Sintaxe

nome_do_vetor[indice].campo

Onde:

nome_do_vetor: nome do vetor que queremos acessar.

[índice]: índice do vetor que será acessado.

.campo: campo do registro que será acessado.

O exemplo 2.4 apresenta acessos a campos do vetor de registro


alunos.

Exemplo 2.4: Acesso aos elementos de um vetor de registro

1 alunos[2].media = 7.5;

2 alunos[3].matricula = 12345;

3 gets(alunos[0].nome);

4 scanf(“%d”,&alunos[2].matricula);

Na linha 1, acessamos o elemento de índice 2 do vetor alunos e


atribuímos 7.5 ao campo media. Na linha 2, acessamos o elemento
de índice 3 do vetor alunos e atribuímos 12345 ao campo matricula.

Nas linhas 3 e 4, temos acessos através de comandos de entrada

42
Programação I

de dados. Na linha 3, temos um gets, que obtém o nome do aluno, via


teclado, e armazena no índice 0 do vetor alunos, no campo nome. Na
linha 4, temos o scanf que lê a matrícula do aluno, armazenando no
índice 2 do vetor alunos, no campo matricula.

2.6 Usando vetor de registro

Vamos fazer um programa completo usando vetor de registro?


Este programa será um pouco maior do que os outros programas que
já fizemos, e apresentará uma gama de coisas novas. Além do uso
de vetor de registro, aprenderemos a mostrar os dados do vetor de
registro em forma de tabela. Vamos começar?

Primeiramente, vamos ler e entender o enunciado do Programa


Completo 2.1: faça um programa que cadastre e apresente os
dados dos alunos de uma escola. Os dados dos alunos devem
ser armazenados em um vetor de registro, com a capacidade de
armazenar até 20 alunos. A quantidade de alunos que será cadastrada
é desconhecida. No momento do cadastro serão informados os
seguintes dados para cada aluno: matrícula, nome, série(1-4) e se
tem irmão na escola (1-sim/0-nao). O programa irá calcular o valor
da mensalidade do aluno, que depende da série do aluno e se o
mesmo tem irmão na escola. Valor da Mensalidade: 1ª Serie: R$110,
2ª Serie: R$130, 3ª Serie: R$160, 4ª Serie: R$170. O aluno que tiver
irmão na escola, receberá 20% de desconto no valor da mensalidade.
Quando o usuário decidir que não deseja mais cadastrar, o programa
apresentará os dados de todos os alunos, em forma de tabela. Para
facilitar o entendimento deste enunciado, vejam os exemplos das telas
que são apresentadas durante a execução do programa:

Colégio Legal

Cadastro de Aluno

Matricula..:
Nome.......:
Serie(1-4):
Irmao na escola (1-sim/0-nao):

Cadastrar outro aluno (1-sim/0-nao)?

43
Programação I

Colégio Legal

Relatório Geral

Matricula Nome Serie Irmao Mensalidade

xx xxxxx x x xx.xx

xx xxxxx x x xx.xx

xx xxxxx x x xx.xx

xx xxxxx x x xx.xx

xx xxxxx x x xx.xx

Tecle enter para sair...

Figura 2.4:Exemplos de telas do programa completo 2.1

A primeira tela representa a operação de cadastramento dos


dados dos alunos. Nesta tela, é que serão fornecidos os dados para o
cadastramento dos alunos. Como a mensalidade é um dado calculado
pelo programa, o usuário não fornecerá este dado no momento do
cadastro.

A segunda tela representa a apresentação dos dados de todos


os alunos, em forma de tabela (listagem ou relatório). Cada linha da
tabela apresentará os dados de um aluno.

Como precisamos armazenar os vários dados de cada um dos


alunos da escola, se faz necessário o uso de um vetor de registro.
Segue o código do programa completo 2.1, que será comentado
posteriormente.

44
Programação I

Programa Completo 2.1

1 #include <stdio.h>

2 main()

3 { typedef struct{ int mat, serie, irmao;

4 char nome[20];

5 float mens;

6 } Tipo_Aluno;

7 Tipo_Aluno alunos[20];

8 int qa, i, resp;

9 qa =0;

10 do

11 { system(“cls”);

12 printf(“Colegio Legal\n”);

13 printf(“\n\nCadastro de Alunos\n\n”);

14 printf(“\nMatricula.: “);

15 scanf(“%d”,&alunos[qa].mat);

16 printf(“\nNome......: “);

17 fflush(stdin);

18 gets(alunos[qa].nome);

19 printf(“\nSerie(1-4): “);

20 scanf(“%d”,&alunos[qa].serie);

21 printf(“\nIrmao na escola(1-sim/0-nao):
“);

22 scanf(“%d”,&alunos[qa].irmao);

23 switch(alunos[qa].serie)
24 { case 1: alunos[qa].mens = 110; break;

25 case 2: alunos[qa].mens = 130; break;

26 case 3: alunos[qa].mens = 160; break;

27 case 4: alunos[qa].mens = 170; break;

28 }

45
Programação I

29 if (alunos[qa].irmao == 1)

30 alunos[qa].mens = alunos[qa].mens*0.8;

31 qa++;

32 printf(“\n\nDeseja cadastrar outro aluno(1-


sim/0-nao)? “);

33 scanf(“%d”,&resp);

34 }while ((resp == 1) && (qa <20));

35 system(“cls”);

36 printf(“Colegio Legal\n”);

37 printf(“\n\nRelatorio Geral\n”);

38 printf(“\n________________________________”);

39 printf(“\nMatricula Nome Serie Irmao


Mensalidade”);

40 printf(“\n________________________________”);

41 for(i = 0; i < qa; i++)

42 printf(“\n%9d %-20s %5d %5d %11.2f”,


alunos[i].mat, alunos[i].nome, alunos[i].serie,
alunos[i].irmao, alunos[i].mens);

43 printf(“\n_______________________________”);

44 printf(“\nTecle enter para sair...”);

45 getche();

46 }

Comentários sobre o Programa Completo 2.1

» Linha 1: inclusão da biblioteca stdio.h devido o uso do comando


fflush.

» Linha 2: início do programa principal.

» Linhas 3 a 6: definição de um novo tipo de dado, que será


chamado de Tipo_Aluno. O Tipo_Aluno é formado pelos dados
dos alunos: mat (matrícula), nome, serie, irmao (indica se tem
irmão na escola) e mens (mensalidade).

» Linha 7: declaração do vetor de registro alunos, com capacidade


de armazenar 20 elementos do Tipo_Aluno.

46
Programação I

» Linha 8: declaração das variáveis qa (que irá controlar a


quantidade de alunos cadastrados no vetor), i (utilizada como
variável de controle do for) e resp (utilizada para saber se o
usuário deseja continuar cadastrando novos alunos).

» Linha 9: inicialização da variável qa com 0;

» Linhas 10 a 34: repetição do tipo do/while que irá controlar


o cadastro dos dados dos alunos no vetor de registro. Este
do/while irá parar a sua execução se o vetor ficar cheio (20
elementos) ou se o usuário não quiser mais cadastrar.

» Linha 11: Cada vez que o do/while é executado, queremos que


a tela seja limpa. Para isso, usamos o system(“cls”). Esta linha
tem, também, o abre chaves que indica o início da sequência
de comandos do do/while.

» Linhas 12 e 13: printf para indicar o nome do colégio (Colégio


Legal) e para indicar o que está sendo feito nesta tela (Cadastro
de Alunos).

» Linhas 14 e 15: printf informando que o usuário deve digitar


a matrícula do aluno e scanf que obtêm a matrícula do aluno,
armazenado-a no vetor de registro alunos, na posição qa e no
campo mat. Notem que a variável qa iniciou com 0. Na primeira
vez que o do/while for executado, os dados dos alunos serão
armazenados na posição 0 do vetor. A cada vez que a repetição
é executada, a variável qa é incrementada de uma unidade.
Assim, os dados de cada aluno serão armazenados em uma
posição, diferente, no vetor de registro.

» Linhas 16 a 18: printf informando que o usuário deve digitar o


nome do aluno. fflush para limpar o buffer e, em seguida, o gets
responsável por ler o nome do aluno, armazenando no vetor de
registro alunos, na posição qa e no campo nome.

» Linhas 19 e 20: printf informando que o usuário deve digitar a


série do aluno (que pode ser de 1 a 4). scanf responsável por
ler a série do aluno, armazenando no vetor de registro alunos,
na posição qa e no campo serie.

» Linhas 21 e 22: printf informando que o usuário deve digitar se


o aluno tem irmão na escola (digitar 1 se tiver irmão e 0 se não
tiver irmão na escola). scanf responsável por ler se o aluno tem
irmão na escola, armazenando no vetor de registro alunos, na

47
Programação I

posição qa e no campo irmao.

» Linhas 23 a 28: depois de obter todos os dados de um aluno,


o programa vai calcular o valor da mensalidade do aluno,
verificando a série e se tem irmão na escola. Como cada uma
das séries da escola tem um valor diferente de mensalidade,
este switch serve para verificar em que série o aluno está
matriculado, para atribuir ao campo mens do registro do aluno,
o valor da mensalidade correspondente a sua série.

» Linhas 29 e 30: if para verificar se o aluno tem irmão na escola.


De acordo com o enunciado, os alunos que tem irmão na escola,
recebem uma desconto de 20% na sua mensalidade. Como o if
só tem um comando, não foi necessário o uso de chaves.

» Linha 31: neste momento, todo o registro do aluno já foi


preenchido. Com isso, fazemos o incremento da variável qa,
informando que mais um aluno acabou de ser cadastrado.

» Linhas 32 e 33: printf que pergunta se o usuário deseja


continuar cadastrando novos alunos. scanf para ler a resposta
do usuário (1 se ele deseja continuar cadastrando e 0 se deseja
parar).

» Linha 34: fechamento do do/while com a condição que faz a


repetição parar. Como mencionado anteriormente, este do/
while fica em execução enquanto tem posições disponíveis no
vetor ou enquanto o usuário desejar. Nesta linha, termina a fase
de cadastramento dos dados dos alunos no vetor de registro.

» Linhas 35 a 47: Esta sequência de comando serve para


apresentar os dados dos alunos que foram armazenados
no vetor de registro. Por uma questão de organização, estes
dados serão apresentados na forma de tabela. Assim, cada
linha da tabela corresponderá aos dados de um aluno, ou
seja, uma posição do vetor de registro. Para que a tabela fique
alinhada, precisamos saber que: a tela tem 80 colunas por 25
linhas. Dessa forma, temos que distribuir as informações de um
jeito que não extrapole as 80 colunas da tela. Para entender
melhor esta parte do programa, acompanhem os comandos,
observando a figura 2.9 (tela de execução do programa).

» Linha 35: limpa a tela para darmos início à apresentação dos


dados de todos os alunos.

48
Programação I

» Linhas 36 e 37: printf para informar o nome do colégio e para


informar o que esta tela faz (Relatório Geral).

» Linha 38: printf para passar uma linha na tela. Esta linha vai
delimitar o cabeçalho da tabela.

» Linha 39: printf que imprime os títulos de cada coluna da tabela.


A tabela será composta pelas seguintes colunas: Matricula,
Nome, Serie, Irmao e Mensalidade. Os títulos que devemos
dar as colunas da tabela são sempre indicados nos enunciados
das questões, certo? Sigam esta dica, porque vocês estão
começando a aprender a fazer tabelas agora. Este printf é cheio
de detalhes, mas vamos ver isso agora, observando a figura
2.5. O resultado deste printf é a linha que está indicada com a
seta horizontal.

Figura 2.5: Apresentação dos dados em forma de tabela

» Vamos ver quais são os passos para montar o printf da linha 39


(cabeçalhos/títulos das colunas da tabela).

» Para cada coluna da tabela, verifiquem quantas letras tem


no seu cabeçalho. Por exemplo, a palavra matrícula tem 9
letras. Vejam que, na figura 2.5, tem a indicação de quantas
letras tem em cada um dos cabeçalhos. A quantidade de
letras que tiver o cabeçalho será a largura da coluna.

» Agora, precisamos verificar se os dados dos alunos vão


extrapolar a largura de cada uma das colunas da tabela.
Vamos ver uma por uma:

√ Matricula: a coluna que será utilizada para apresentar


a matrícula tem uma largura de 9 espaços (quantidade
de letras da palavra matrícula). Vamos considerar que
nossas matrículas tem sempre menos que 9 dígitos.

49
Programação I

Assim, a largura de 9 espaços para esta coluna é


suficiente.

√ Nome: a palavra nome só tem 4 letras. Vejam que o


nome do aluno foi declarado com 20 letras. Assim, se
deixarmos a coluna Nome, com largura 4, não será
suficiente para apresentar os nomes dos alunos.
Quando a quantidade de letras do cabeçalho é menor
que o conteúdo que vem na coluna da tabela, devemos
completar a coluna com espaços em branco até fazer
com que a coluna tenha a largura que precisamos.

√ Série: tem 5 letras. A série do aluno varia entre 1 e 4,


dessa forma, a largura da coluna Serie (5 espaços)
será suficiente para apresentar o dado.

√ Irmão: também tem 5 letras. A variável que armazena


se o aluno tem ou não irmão na escola varia entre 0 e
1, dessa forma, a largura da coluna Irmao (5 espaços),
será suficiente para apresentar o dado.

√ Mensalidade: tem 11 letras. Esta largura é suficiente


para apresentar o valor da mensalidade do aluno.

» Agora que já sabemos que apenas a coluna Nome não tem


largura suficiente para apresentar os nomes dos alunos,
vamos ver quantos espaços em branco nós temos que
colocar depois da palavra Nome, para que esta coluna
tenha a largura que precisamos. Se o nome do aluno tem
até 20 letras e a palavra Nome tem apenas 4 letras, faremos
a seguinte conta: 20 – 4 = 16. Assim, depois da palavra
Nome, temos que colocar 16 espaços em branco, para que
a nossa coluna passe a ter a largura que precisamos (20).

» Por fim, temos que definir um espaçamento para separar


uma coluna da outra. Nos nossos exemplos, vamos usar
sempre três espaços separando uma coluna da outra.
A padronização do espaçamento entre as colunas visa
facilitar a programação, já que estamos vendo este assunto
agora e o mesmo é cheio de detalhes.

» Agora vamos montar o printf, vejam a figura 2.6. Nós


vamos colocando os títulos das colunas da tabela, e entre
cada palavra, vamos colocando três espaços em branco,

50
Programação I

que foi o espaçamento definido para separar as colunas.


Só no caso da coluna nome, que depois que colocamos
Nome, devemos dar os 16 espaços em branco para que ela
passe a ser uma coluna de largura 20. Mas ainda teríamos
que dar mais 3 espaços em branco, que é para separar a
coluna nome, da coluna serie.

Figura 2.6: Detalhamento do printf da linha 39

» O printf está pronto! A primeira vista, parece complicado,


mas depois vocês estarão fazendo a tabela bem rápido.

» Linha 40: printf para passar uma linha na tela. Esta linha vai
delimitar o cabeçalho da tabela.

» Linha 41: for para visitar cada uma das posições do vetor e
apresentar os dados dos alunos. A variável de controle do for,
o i, vai variar de 0 até a ultima posição ocupada do vetor. A
variável que tem esta informação é o qa.

» Linha 42: este printf é que vai fazer a montagem das linhas
da tabela, apresentado os dados dos alunos que estão
armazenados no vetor de registro. Este printf também tem
macetes, pois está relacionado com o printf da linha 39. Vamos
lá! Lembram que fizemos a contagem para saber a largura
de cada coluna da tabela? Vamos precisar desta informação
agora.

» Na primeira parte do printf, temos a string de controle


(a figura 2.7 faz o detalhamento dessa parte do printf).
Sabemos que as colunas da tabela são: matricula( número
inteiro e esta coluna deve ter largura 9), nome (vetor de
caracteres com até 20 letras), serie (número inteiro e esta
coluna tem largura 5), irmão (número inteiro e esta coluna
tem largura 5) e mensalidade (número real e esta coluna
tem largura 11). Além disso, sabemos que entre cada
coluna, nós colocamos três espaços em branco. Com estas
informações, vamos montar a string de controle do printf da

51
Programação I

linha 42.

Figura 2.7: Detalhamento do printf da linha 42

» Entre o % e a letra que indica o que vai ser impresso (%d,


%s ou %f), devemos colocar a largura da coluna. A primeira
coluna da tabela é a da matricula, que é um número inteiro
e que tem largura 9. Por isso, temos o %9d. Após cada
uma das formatações, colocamos três espaços em branco,
já que foi o espaçamento definido entre as colunas da
tabela. No caso da variável caractere nome do aluno (que
é a segunda coluna da tabela) colocamos %-20s (o – é
para que o nome do aluno seja alinhado pela esquerda).
Nas demais formatações não precisamos colocar o -, só
utilizamos em campos caractere.

» Após a string de controle, colocamos as variáveis que serão


apresentadas na tela, na ordem em que as colunas foram
definidas.

» Linha 43: printf para passar uma linha na tela. Esta linha vai
fechar a tabela.

» Linha 44: printf que informa que o usuário deve teclar enter
para sair.

» Linha 45: getche() que evita que a tela de execução feche


antes de vermos os resultados.

» Linha 46: fecha chaves do programa principal.

A figura 2.8 apresenta a tela de execução do programa 2.1, na


fase do cadastramento dos alunos.

52
Programação I

Figura 2.8: Tela de execução do programa completo 2.1 - Cadastro

A figura 2.9 apresenta a tela de execução do programa 2.1, na


fase do apresentação dos dados de todos os alunos cadastrados, em
forma de tabela.

Figura 2.9: Tela de execução do programa completo 2.1 – Relatório Geral

Viram como esta questão é cheia de detalhes? Mas não se


assustem, a explicação precisava ser minuciosa, para que cada linha
do programa fosse entendida. Agora precisamos treinar esse tipo de
questão. Não percam tempo!

Atividades e Orientações de Estudos

Vamos resolver mais uma lista de exercícios? Esta lista é composta


por questões em que se faz necessário o uso de vetor de registro.
DICA: sempre coloque as tabelas com os mesmos cabeçalhos
propostos nos enunciados (exemplos de telas). Mãos a obra!

1. Uma empresa de turismo deseja um programa que calcule o


valor das viagens dos clientes. Serão informados os seguintes

53
Programação I

dados: código do cliente, nome, roteiro desejado(1-Brasil,


2-EUA, 3-África), tipo de quarto (1-Standard, 2-Luxo), Se deseja
alugar carro(1-sim/0-nao) e a quantidade de dias. A quantidade
de clientes é desconhecida. O programa irá calcular o total da
viagem usando os valores da tabela abaixo, que variam de
acordo com o roteiro escolhido. A diária do quarto de luxo é
R$30 mais cara que o valor da diária em um quarto standard.
Exemplo: Se a pessoa escolher roteiro 2, em quarto de luxo, a
diária irá custar: 320 + 30 = R$ 350.

Roteiro Diária – Hotel Diária - Aluguel


Quarto Standard de carro

1 R$ 170 R$ 50

2 R$ 350 R$ 60

3 R$ 370 R$ 75

Total da Viagem:
dias*diáriahotel + dias*diariacarro(se o cliente for alugar carro)

Armazenar os dados em um vetor de registro. Imprimir os dados


em forma de tabela. Exemplo das telas:

Viagem Legal – Turismo

Cadastro de Cliente

Codigo:
Nome:
Roteiro (1-Brasil, 2-EUA, 3-África):
Tipo de Quarto (1- Standard, 2-Luxo):
Alugar Carro (1-sim/0-nao)?
Quantidade de Dias:

Inserir outro (1-sim,0-nao)?

Viagem Legal – Turismo

Relatório Geral

Código Nome Roteiro Quarto Carro Dias Total

xx xxxxx x x x xx xx.xx

xx xxxxx x x x xx xx.xx

xx xxxxx x x x xx xx.xx

Tecle enter para sair...

54
Programação I

2. Faça um programa para montar a folha de pagamento dos


empregados de uma empresa. Para cada empregado serão
lidos os seguintes dados: matricula, nome, cargo(1-Analista
de Sistemas/2- programador), sexo(1-mas/2-fem), anos de
experiência e quantidade de filhos. O programa irá calcular
para cada empregado o seu salário. Sabe-se que:

Cargo Salário Base

1 R$ 2500

2 R$ 1700

O salário será calculado da seguinte forma: cada cargo tem


o salário base. Além do salário base, o empregado recebe os
seguintes adicionais: R$ 50, para cada ano de experiência e R$
40 por cada filho. Portanto, um analista de sistemas com três
anos de experiência e dois filhos terá o salário = 2500 + 50*3 +
40*2 = R$ 2730.

Armazenar as informações em um vetor de registros. Imprimir


o relatório geral em forma de tabela contendo os dados de
cada empregado. A quantidade de empregados da empresa é
desconhecida (declarar o vetor com capacidade de armazenar
20 funcionários). Exemplos das telas:

Empresa Legal

Cadastro de Funcionario

Matricula:
Nome:
Cargo(1-Analista de Sistemas, 2- programador):
Sexo(1-mas/2-fem):
Anos de experiência:
Quantidade de filhos:

Cadastrar outro (1-sim/2-nao)?

55
Programação I

Empresa Legal

Listagem Geral

Matricula Nome Cargo Sexo Anos Q. Filho Salário

xx xxxxx x x xx x xxx.xx

xx xxxxx x x xx x xxx.xx

xx xxxxx x x xx x xxx.xx

xx xxxxx x x xx x xxx.xx

Tecle enter para sair...

3. Faça um programa para uma empresa de celular contendo as


seguintes operações: cadastro de clientes e listagem geral.
Para cada cliente devemos armazenar: código, nome, sexo
(1-feminimo/2-masculino), quantidade de ligações, plano que
o cliente está associado (1-Dia/2-Noite/3-Fixo/4-Empresarial) e
Valor da conta. O programa irá calcular o valor da conta de cada
cliente. Sabe-se que, cada plano tem uma tarifa diferenciada,
segundo a tabela abaixo:

Plano Valor de 1 ligação

Dia 1.30

Noite 1.60

Fixo 1.25

Empresarial 1.10

Armazenar os dados em um vetor de registro. Após o cadastro dos


clientes, apresentar a listagem com os dados de todos os clientes, em
forma de tabela. A quantidade de clientes é desconhecida. Declare o
vetor com capacidade de receber até 50 clientes.

Exemplos das telas:

56
Programação I

Ligue Mais

Cadastro de Cliente

Código:
Nome:
Sexo(1-fem/2-mas):
Quantidade de Ligações:
Plano(1-Dia/2-Noite/3-Fixo/4-Empresarial):

Cadastrar outro (1-sim/0-nao)?

Ligue Mais

Listagem Geral

Codigo Nome Sexo Quant. Lig. Plano Total

xx xxxxx x xx x xxx.xx

xx xxxxx x xx x xxx.xx

xx xxxxx x xx x xxx.xx

xx xxxxx x xx x xxx.xx

Tecle enter para sair...

4. Um professor quer um programa para o cálculo da média dos


alunos de uma turma. Serão informadas a matrícula, nome (20
caracteres), e as três notas dos alunos. O professor descarta
a menor nota do aluno e a media é calculada com as duas
maiores notas. Calcular a média e apresentar os resultados em
forma de tabela, após o cadastramento. Armazenar os dados em
um vetor de registro. A quantidade de alunos é desconhecida,
declare o vetor com capacidade de receber até 20 alunos.

Exemplos das Telas:

Universidade Legal

Cadastro de aluno

Matricula:
Nome:
Nota 1:
Nota 2:
Nota 3:

Cadastraroutro (1-sim/0-nao)?

57
Programação I

Universidade Legal

Relatório Geral

Matricula Nota1 Nota2 Nota3 Media

x xxxxxxxxx x.x x.x x.x x.x

x xxxxxxxxx x.x x.x x.x x.x

x xxxxxxxxx x.x x.x x.x x.x

x xxxxxxxxx x.x x.x x.x x.x

Tecle enter para sair...

5. O MEC quer um programa para fazer um relatório sobre os


polos de educação a distância da UFRPE. Para cada polo são
informados os seguintes dados: código do polo, cidade, total
de alunos, total de tutores, se possui laboratório de informática
(1-sim/0-não) e se possui laboratório de ciências (1-sim/0-não).
O MEC quer saber quanto deve ser liberado de verba para cada
polo. O calculo será feito da seguinte forma:

» Por cada aluno são liberados: R$ 100

» Por cada tutor são liberados: R$ 500

» Se o polo tem não tem laboratório de informática são liberados:


R$ 20.000

» Se o polo não tem laboratório de ciências são liberados: R$


17.000

Ex: um polo com 150 alunos, com 15 tutores, que tem laboratório
de informática, mas não tem laboratório de ciências: Verba = 100 x
150 + 500 x 15 + 17000 = 15000 + 7500 + 17000 = 39500.

Armazenar os dados dos polos em um vetor de registro. A


quantidade de polos é desconhecida. Declarar o vetor com a
capacidade de armazenar até 20 polos. Após o cadastros dos polos,
apresentar todos os dados dos polos em forma de tabela.

Exemplos das telas:

58
Programação I

Ministério da Educação

Cadastro de Polo

Codigo:
Cidade:
Quantidade de alunos:
Quantidade de tutores:
Tem lab. de informatica (1-sim/0-nao)?
Tem lab. de ciencias (1-sim/0-nao)?

Cadastrar outro polo (1-sim,0-nao)?

Ministério da Educação

Listagem Geral

Codigo Cidade Alunos Tutores LI LC Verba Liberada

xx xxxxx xxx xxx x x xxxxx.xx

xx xxxxx xxx xxx x x xxxxx.xx

xx xxxxx xxx xxx x x xxxxx.xx

xx xxxxx xxx xxx x x xxxxx.xx

Tecle enter para sair...

Conheça Mais

Vocês poderão aprender mais sobre registros e vetores de registros


lendo os livros:

MONTGOMERY, Eduard. Programando em C: Simples e


Prático. São Paulo: Alta Books, 2006.

SCHILDT, Herbert. C Completo e Total. São Paulo: Makron,


1996.

Vamos Revisar?

Nesta seção iremos revisar os principais tópicos vistos neste

59
Programação I

capítulo. Vale a pena dar uma lida para verificar como está o nosso
aprendizado. Observem o resumo a seguir:

Os registros são um agrupamento de variáveis de tipos diferentes,


mas que tem uma relação lógica.

Por ser formado por elementos de diferentes tipos, os registros são


chamados de estruturas de dados heterogêneas.

Para declarar uma variável registro, precisamos definir um novo


tipo de dado para o programa, utilizando o typedef.

Cada elemento do registro é chamado de campo.

Unindo os conceitos de vetores e de registros, temos os vetores


de registro que facilitam a declaração e o manuseio de grandes
volumes de dados.

60
Programação I

Capítulo 3 – Armazenamento de
Dados em Arquivos

Vamos conversar sobre o assunto?

Neste capítulo, vamos aprender a armazenar nossos dados de


forma definitiva. Até então, ao terminar a execução de um programa,
todos os dados que foram armazenados nas variáveis eram perdidos.
Em muitas aplicações isto não pode acontecer. Por exemplo, um
professor precisa ter certeza de que todo o trabalho para digitar
as notas dos alunos da turma não será perdido quando ele fechar
o programa. Com os arquivos, poderemos armazenar os dados e
recuperá-los quando necessário. Este capítulo abordará os comandos
que nos possibilitarão manipular dados armazenados em um arquivo.
Vamos começar?

3.1 O que são arquivos?

Os arquivos são estruturas de dados manipuladas fora do ambiente


do programa. Considera-se como ambiente do programa a memória
principal, onde nem sempre é conveniente manter certas estruturas
de dados. De modo geral, os arquivos são armazenados na memória
secundária, como, por exemplo: disco rígido (HD - hard disk), CD e
pendrive.

3.1.1. Como os arquivos são organizados?

A linguagem C utiliza o conceito de fluxo de dados (stream) para


manipular os vários tipos de dispositivos de armazenamento e seus
diferentes formatos. Os dados podem ser manipulados em dois
diferentes tipos de fluxos: fluxos de texto e fluxos binários.

Um fluxo de texto (text stream) é composto por uma sequência


de caracteres, que pode ou não ser dividida em linhas, terminadas
por um caractere de final de linha. Um fluxo binário (binary stream) é
composto por uma sequência de bytes, que são lidos, sem tradução,
diretamente do dispositivo externo. A Figura 3.1 ilustra estes dois tipos
de fluxos.

61
Programação I

Figura 3.1: Fluxo de dados

No fluxo de texto, os dados são armazenados como caracteres


sem conversão para a representação binária. Cada um dos caracteres
ocupa um byte. O número 12 ocupa dois bytes e o número 113 ocupa
3 bytes. Um caractere em branco foi inserido entre cada um dos
números para separá-los, de modo que a função de entrada e saída
possa descobrir que são dois números inteiros (12 e 113) e não o
número 12113. No fluxo binário, cada número inteiro ocupa 32 bits (4
bytes) e é armazenado na forma binária. Observem que, em arquivos
binários, não há necessidade de separar os números já que eles
sempre ocupam 32 bits.

Os arquivos binários são utilizados quando queremos armazenar


registros completos. Com estes arquivos, poderemos acessar
qualquer registro de forma mais rápida. No caso dos arquivos texto,
quando queremos encontrar alguma informação, temos que fazer uma
varredura sequencial no arquivo, tornando a busca pouco eficiente.

Neste capítulo, será dada ênfase ao armazenamento de dados


em arquivos binários. Nas próximas seções, iremos conhecer os
comandos para manipular este tipo de arquivo.

3.1.2 Ponteiros

Antes de começarmos a conhecer os comandos de manipulação


de arquivos binários, vamos ver um conceito que será utilizado
neste capítulo, que é: ponteiro. Um ponteiro é um tipo de variável
que armazena um endereço de memória. Nós já vimos variáveis que
armazenam números inteiros, números reais e caracteres. Ao trabalhar
com arquivos, precisamos saber em qual endereço de memória o
arquivo está armazenado. O endereço de memória onde o arquivo

62
Programação I

está armazenado será colocado em uma variável que armazena


endereço de memória (ponteiro).

Para declarar uma variável que é capaz de armazenar um endereço


de memória, usamos a seguinte sintaxe:

Sintaxe

tipo *nome_do_ponteiro;

Onde:

» tipo: tipo de variável que o ponteiro armazena endereço.


Podemos dizer que nosso ponteiro armazena o endereço de
uma variável inteira, real, caractere, etc. Para este capítulo,
estaremos utilizando um ponteiro que vai armazenar o endereço
de um arquivo.

» *: o asterisco na frente do nome de uma variável simboliza que


a variável que está sendo declarada é um ponteiro.

» nome_do_ponteiro: daremos um nome à nossa variável que


armazena endereços.

O exemplo 3.1 apresenta exemplos de declarações de ponteiros


que armazenam endereços de memória de arquivos.

Exemplo 3.1: Declaração de ponteiros para arquivos

1 FILE *p aluno;

2 FILE *p produto;

Na linha 1, temos a declaração do ponteiro paluno, que irá


armazenar o endereço de um arquivo (FILE). Devemos colocar o
FILE em maiúsculo. Na linha 2, temos a declaração de outro ponteiro,
pproduto, que armazena o endereço de um FILE.

Quando queremos inicializar uma variável real ou inteira, atribuímos


zero às mesmas. Quando precisarmos inicializar um ponteiro,
devemos atribuir: NULL. Quando um ponteiro armazena NULL, quer
dizer que ele não está armazenando um endereço no momento.

Tenham calma, daqui a pouco o conceito de ponteiros ficará mais


claro. Vamos começar a conhecer os comandos de manipulação de
arquivos binários e entenderemos melhor onde o conceito de ponteiro
será aplicado.

63
Programação I

3.2 Comandos para manipular arquivos


binários

Como já mencionado, os arquivos binários são utilizados quando


queremos armazenar registros. É como se tivéssemos um vetor de
registro, só que os dados não são perdidos ao terminar a execução do
programa. A figura 3.2 mostra a representação gráfica de um arquivo
binário.

Figura 3.2: Representação gráfica de um arquivo binário

O arquivo binário é formado por um conjunto de registros,


armazenados um após o outro. As operações realizadas em um
arquivo binário dependerão do local onde se encontrar o leitor. Pense
no leitor como se fosse a agulha de uma vitrola (Figura 3.3). Para
tocar uma música, a agulha passa sobre o disco, fazendo a leitura da
música. Dependendo de onde a agulha seja posicionada, é tocada
uma música do disco.

Figura 3.3: Vitrola com agulha tocando uma música

O leitor do arquivo passará sobre os registros, fazendo a leitura


dos mesmos. Nós podemos colocar o leitor sobre qualquer registro
e executar uma operação sobre o mesmo (leitura e/ou gravação). O
arquivo tem uma marcação indicando onde ele termina (end of file).

Nas próximas seções, iremos detalhar os comandos para manipular


arquivos binários. As operações para a manipulação de arquivo estão
na biblioteca stdio.h. Com isso, ao trabalhar com arquivos, devemos

64
Programação I

incluir esta biblioteca nos nossos programas.

3.2.1 Declaração de um ponteiro para arquivo

Na linguagem C, as funções que manipulam arquivos trabalham


com o conceito de ponteiros para arquivo. Com isso, teremos
uma variável que armazenará o endereço de memória onde está
armazenado nosso arquivo. Nós vimos na seção 3.2.1 (exemplo 3.1),
como fazemos para declarar um ponteiro para um arquivo. Devemos
declarar um ponteiro para cada arquivo que formos manipular no
nosso programa.

3.2.2 Comando para abrir um arquivo

A maior parte das operações sobre um arquivo (leitura, gravação,


etc) só pode ser executada com o arquivo aberto. O comando de
abertura do arquivo (fopen) apresenta a seguinte sintaxe:

Sintaxe

ponteiro_arquivo = fopen(“nome_do_arquivo”,

“modo_de_abertura”);

Onde:

» ponteiro_arquivo: ao abrir um arquivo, a função fopen retorna


o endereço de memória do arquivo. Por conta disso, devemos
atribuir o endereço de memória do arquivo, para um ponteiro.
Após o arquivo ser aberto, usaremos este endereço de memória
para acessá-lo.

» nome_do_arquivo: determina qual arquivo deverá ser aberto.


Neste espaço é colocado o nome do arquivo, da forma que
foi salvo no diretório. O comando fopen procura o arquivo que
desejamos abrir, no mesmo diretório onde está armazenado o
programa executável.

» modo_de_abertura: informa que tipo de uso você vai fazer do


arquivo. O modo de abertura indica o que faremos no arquivo:
leitura, gravações e alterações. Além disso, o modo de abertura
também vai indicar se queremos que um novo arquivo seja
criado. A tabela abaixo apresenta os principais modos de
abertura.

65
Programação I

Modo Significado

“r+b” Abre um arquivo binário para leitura e escrita.  O arquivo deve


existir antes de ser aberto. Dessa forma, este modo de abertura
só pode ser usado se o arquivo que estamos querendo abrir já
existe no nosso computador.
“w+b” Cria um arquivo binário para leitura e escrita. Se o arquivo não
existir, ele será criado. Se já existir, o conteúdo anterior será
destruído. Este modo de abertura tem a capacidade de criar novos
arquivos. Mas, se solicitarmos que seja aberto um arquivo que já
existe, o conteúdo do arquivo será apagado.

“a+b” Acrescenta dados ou cria um arquivo binário para leitura e escrita.


Caso o arquivo já exista, novos dados podem ser adicionados,
apenas, no final do arquivo. Se o arquivo não existir, um novo
arquivo será criado. 

O exemplo 3.2, apresenta o uso do fopen.

Exemplo 3.2: Abertura de arquivo

1 FILE *paluno, *pprofessor;

2 paluno = fopen(“alunos.bin”, “w+b”);

3 pprofessor = fopen(“professores.bin”, “r+b”);

4 if (pprofessor == NULL)

5 printf(”Arquivo de professores não existe”);

Na linha 1, temos a declaração de dois ponteiros para armazenar


os endereços dos arquivos que iremos abrir logo em seguida.

Na linha 2, temos um fopen que irá abrir o arquivo alunos.bin,


utilizando o modo de abertura w+b. Caso o arquivo alunos.bin não
exista, ele será criado (com o nome que passamos como parâmetro).
Normalmente, usamos o modo de abertura w+b quando executamos
o nosso programa pela primeira vez. Neste momento, o arquivo ainda
não existe. Dessa forma, desejamos que o mesmo seja criado. Mas,
se o arquivo alunos.bin já existir, todo o seu conteúdo será apagado.
E, como resultado, teremos o arquivo aberto, mas sem nenhum
registro armazenado. Ao abrir o arquivo, o endereço de memória do
arquivo será armazenado no ponteiro paluno.

Na linha 3, temos um fopen que abrirá o arquivo professores.


bin, utilizando o modo de abertura r+b. Este modo de abertura só é
utilizado para arquivos que já existem, pois, diferente do modo de
abertura w+b, ele não tem a capacidade de criar um arquivo novo. Se
tentarmos abrir um arquivo que não existe, o fopen retornará NULL.

66
Programação I

Para saber se um arquivo foi aberto corretamente, podemos fazer


um teste como mostra as linhas 4 e 5. Após executar um fopen,
verificamos se o ponteiro está com NULL. Caso afirmativo, é porque a
abertura não foi executada corretamente.

Uma vez aberto, o arquivo fica disponível para leituras e gravações


através da utilização de funções adequadas.

3.2.3 Comando para fechar um arquivo

Após terminar de usar um arquivo, devemos fechá-lo. Para isso,


usamos a função fclose, que tem a seguinte sintaxe.

Sintaxe

fclose(ponteiro_arquivo);

Onde:

» ponteiro_arquivo: é o ponteiro que tem armazenado o


endereço de memória do arquivo que queremos fechar.

Só podemos fechar arquivos que estão abertos. O exemplo 3.3,


apresenta o uso do comando fclose. Vamos utilizar os ponteiros
declarados no exemplo anterior.

Exemplo 3.3: Fechamento de arquivo

1 fclose(palunos);

2 fclose(pprofessores);

Na linha 1, fechamos o arquivo que está armazenado no endereço


de memória palunos (que é o ponteiro que armazena o endereço do
arquivo). Nós só utilizamos o nome do arquivo (o nome que está salvo
no diretório), no momento da abertura. Depois de aberto, só utilizamos
seu endereço de memória, certo?

3.2.4 Comando para ler um registro armazenado no arquivo

Vamos aprender a ler os dados de um registro armazenado no


arquivo? Neste comando, teremos vários detalhes e devemos ter em
mente o seguinte:

» A leitura é feita a partir do ponto onde o leitor se encontra. Ao


abrir o arquivo, o leitor é posicionado no início do primeiro

67
Programação I

registro, como mostra a figura 3.2. À medida que vamos


executando leituras, o leitor vai se deslocando. Dessa forma,
precisamos ter noção da posição onde o leitor se encontra.

» Nos arquivos binários, SEMPRE fazemos a leitura de um


registro completo, independente de quantos campos ele tenha.

» Um arquivo deve armazenar registro do mesmo tipo. Se os


registros são do mesmo tipo, cada um deles ocupará o mesmo
espaço de memória. Dessa forma, o leitor sempre se deslocará
em intervalos regulares. Vamos entender isto melhor, daqui a
pouco.

Vamos, primeiro, ver a sintaxe do comando de leitura:

Sintaxe

fread (&registro, numero_de_bytes, quantidade,

ponteiro_arquivo);

Onde:

» &registro: é o registro que armazenará os dados do registro


lido do arquivo. É assim, nós pegamos um registro que está no
arquivo, e armazenamos no registro passado como parâmetro.

» numero_de_bytes: na verdade, o que o comando de leitura


faz é informar que o leitor precisa se deslocar, fazendo a leitura
de uma certa quantidade de bytes. A quantidade de bytes que o
leitor deve se deslocar é exatamente quantos bytes de memória
o registro ocupa. Por exemplo: se o nosso arquivo armazena
registros de alunos, composto pelos campos: matricula (int),
nota1 (float), nota2 (float) e media (float). Sabe-se que um int
ocupa 4 bytes e um float, também, ocupa 4 bytes. Dessa forma,
teremos: 4 bytes para a matricula + 4 bytes para a nota1 + 4
bytes para a nota2 + 4 bytes para a media = 16 bytes. Assim,
esse registro ocupa 16 bytes (Figura 3.4). É esse o número de
bytes que o leitor deverá ler, para recuperar o registro de um
aluno, armazenado no arquivo. Existe uma função chamada
sizeof que informa quantos bytes ocupa um tipo de dado.
Assim, não precisamos estar lembrados de quantos bytes um
int ocupa. Além disso, não precisamos fazer as contas para
saber quantos bytes o nosso registro ocupa. Para utilizar a
função sizeof, precisamos apenas, passar como parâmetro

68
Programação I

para a função, que tipo de dado queremos saber quantos bytes


ele ocupa. Por exemplo: sizeof(int) ou sizeof(TAluno). No caso
de um registro, a função vai fazer as contas de quantos bytes
cada um dos campos do registro ocupa, e retorna a soma.

4 bytes 4 bytes 4 bytes 4 bytes

matricula nota1 nota2 media

Figura 3.4: Campos do registro aluno

» quantidade: neste terceiro parâmetro, usaremos SEMPRE 1.


Este parâmetro significa quantas vezes a leitura será executada.
Nós sempre queremos que seja feita a leitura de um registro
por vez. Por isso, sempre utilizaremos 1.

» ponteiro_arquivo: precisamos informar em qual arquivo a


leitura será feita. Com isso, passamos o endereço de memória
onde o arquivo que será lido está armazenado. Assim, utilizamos
o ponteiro que tem o endereço do arquivo.

Agora vamos ver o exemplo 3.4, que apresenta a leitura de um


registro do arquivo. Para um melhor entendimento, foram feitas as
declarações das variáveis que serão usadas no fread.

Exemplo 3.4: Leitura de um registro do arquivo

1 typedef { int matricula;

2 float nota1, nota2, media;

3 } TAluno

5 TAluno aluno;

6 FILE *paluno;

8 fread(&aluno, sizeof(TAluno), 1, paluno);

Nas linhas 1 a 3, temos a declaração de um novo tipo de dado,


que é o agrupamento dos dados do aluno. Este tipo foi chamado de
TAluno. Na linha 5, temos a declaração da variável aluno, que é um

69
Programação I

registro do tipo TAluno. Na linha 6, declaramos um ponteiro chamado


paluno, que armazena endereço de memória de arquivo.

Na linha 8 é que temos o comando de leitura. Vamos interpretar


Atenção
cada parte do comando. No primeiro parâmetro, temos a variável
5
Não esquecer registro que vai armazenar as informações lidas do arquivo5. Assim, o
de colocar o & na registro que for lido do arquivo, será armazenado no registro aluno. No
frente da variável.
segundo parâmetro, precisamos dizer quantos bytes serão lidos. Se
iremos ler os dados do registro do aluno, precisamos saber quantos
bytes ele ocupa. Para isso, foi usada a função sizeof. Como parâmetro
do sizeof foi colocado TAluno, que é um tipo criado no programa e que
queremos saber quantos bytes esse tipo de dado ocupa. No terceiro
parâmetro, nós sempre usaremos 1. Finalmente, no quarto parâmetro
informamos o endereço do arquivo em que será feita a leitura. Neste
caso, o endereço do arquivo está armazenado no ponteiro paluno.

Após a leitura de um registro do arquivo, o leitor estará posicionado


no início do próximo registro. A Figura 3.5 apresenta a posição do
leitor antes e depois da execução do fread.

Figura 3.5: Posição do leitor antes e após a execução de um fread

Agora que já sabemos como fazer para ler um registro que está
armazenado no arquivo, vamos aprender a gravar um registro no
arquivo.

70
Programação I

3.2.5 Comando para gravar um registro no arquivo

Para gravar um registro em um arquivo binário, nós utilizamos


o comando fwrite. Este comando é muito parecido com o fread.
A diferença é que o fread lê uma sequência de bytes no arquivo, e
armazena em um registro (primeiro parâmetro do fread). E o fwrite,
pega um registro, e armazena suas informações no arquivo. Vamos
ver a sintaxe do fwrite:

Sintaxe

fwrite(&registro, numero_de_bytes, quantidade,

ponteiro_arquivo);

Onde:

» &registro: é o registro que será armazenado no arquivo.

» numero_de_bytes: é a quantidade de bytes que serão


gravadas no arquivo. Neste parâmetro, também usaremos o
sizeof.

» quantidade: neste terceiro parâmetro, também, usaremos


SEMPRE 1. Este parâmetro significa quantas vezes a gravação
será executada. Nós sempre queremos que seja feita a
gravação de um registro por vez. Por isso, sempre utilizaremos
1.

» ponteiro_arquivo: precisamos informar em qual arquivo a


gravação será feita. Assim, utilizamos o ponteiro que tem o
endereço do arquivo.

Agora vamos ver o exemplo 3.5, que apresenta a gravação de um


registro no arquivo. Para um melhor entendimento, foram feitas as
declarações das variáveis que serão usadas no fwrite.

71
Programação I

Exemplo 3.5: Leitura de um registro do arquivo

1 typedef { int matricula;

2 float nota1, nota2, media;

3 } TAluno

5 TAluno aluno;

6 FILE *paluno;

8 fwrite(&aluno, sizeof(TAluno), 1, paluno);

Na linha 8 é que temos o comando de gravação. Vamos interpretar


cada parte do comando. No primeiro parâmetro, temos a variável
registro que será gravada no arquivo. No segundo parâmetro,
precisamos dizer quantos bytes serão gravados. Para isso, foi usada
a função sizeof. No terceiro parâmetro, nós sempre usaremos 1.
Finalmente, no quarto parâmetro informamos o endereço do arquivo
em que será feita a gravação. Neste caso, o endereço do arquivo está
armazenado no ponteiro paluno.

Devemos lembrar que o comando de gravação no arquivo (fwrite)


é executado na posição onde o leitor se encontra no momento. Se o
leitor estiver posicionado no início de um registro e executarmos um
fwrite, o registro será gravado sobre o outro. Dessa forma, quando
vamos inserir um novo registro no arquivo, devemos posicionar o leitor
num ponto do arquivo que não tenha nenhum registro armazenado,
ou seja, no final do arquivo. Vamos ver como faz isso?

3.2.6 Comando para posicionar o leitor em um ponto do


arquivo

As operações de leitura e gravação são feitas na posição onde o


leitor se encontra no momento. Podemos mudar a posição do leitor,
colocando-o em um ponto específico do arquivo. Este comando é o
fseek. A sintaxe do fseek é a seguinte:

Sintaxe

fseek(ponteiro_arquivo,numero_de_bytes, origem);

72
Programação I

Onde:

» ponteiro_arquivo: precisamos informar em qual arquivo o leitor


está sendo posicionado.

» numero_de_bytes: é a quantidade de bytes que o leitor irá se


deslocar pelo arquivo, até chegar no local desejado.

» origem: determina a partir de onde os número_de_bytes de


deslocamento do leitor serão contados. Os possíveis valores
são:

Origem Significado

SEEK_SET O deslocamento do leitor será contado a partir do início do


arquivo.

SEEK_CUR O deslocamento do leitor será contado a partir da sua posição


corrente.

SEEK_END O deslocamento do leitor será contado a partir do final do


arquivo.

O exemplo 3.6 apresenta o uso do comando fseek.

Exemplo 3.6: Comando fseek

1 fseek(paluno, 0,SEEK_END);

2 fseek(paluno, 2*sizeof(paluno), SEEK_SET);

No exemplo da linha 1, temos um fseek que será muito utilizado


em nossos programas. Neste fseek é solicitado que seja feito Atenção
o posicionamento do leitor do arquivo de endereço paluno. O
6
O parâmetro
deslocamento do leitor será feito iniciando a contagem a partir do origem deve ser
fim do arquivo (SEEK_END)6. O número de bytes que o leitor irá se colocado todo em
letra maiúscula.
deslocar é 0. Este tipo de fseek é usado quando queremos gravar um
novo registro do nosso arquivo. Jogamos o leitor para o fim do arquivo
e não deslocamos nenhum byte. Com isso, temos a garantia que o
leitor não está sobre nenhum registro. Dessa forma, podemos gravar
um novo registro, sem perder registros que já haviam sido gravados
no nosso arquivo.

No fseek da linha 2, foi solicitado que o leitor seja posicionado no


início do arquivo (SEEK_SET), antes do deslocamento ser efetivado.
Notem que, no segundo parâmetro, foi passada uma expressão 2 * o
tamanho de um registro. Neste caso, significa que o leitor irá deslocar
a quantidade de bytes ocupadas por 2 registros, com isso, irá se
posicionar no início do terceiro registro.

73
Programação I

A figura 3.6 apresenta a posição do leitor após a execução dos


fseek do exemplo.

Figura 3.6: Posição do leitor após a execução dos fseek do exemplo 3.6

3.2.7 Comando para posicionar o leitor no início do arquivo

Nós podemos posicionar o leitor no início do arquivo, utilizando o


comando rewind. A sua sintaxe é a seguinte:

Sintaxe

rewind(ponteiro_arquivo);

Onde:

» ponteiro_arquivo: é o ponteiro que tem o endereço do arquivo


que queremos posicionar o leitor.

O exemplo 3.7 apresenta o uso do comando rewind.

Exemplo 3.7: Uso do comando rewind

1 rewind(paluno);

O comando rewind é utilizado quando precisamos fazer uma


varredura por todos os registros do arquivo. A varredura é iniciada
colocando o leitor no início do arquivo.

74
Programação I

3.2.8 Comando para verificar se chegou ao final do arquivo

Quando fazemos uma varredura no arquivo, não sabemos quantos


registros tem armazenados no mesmo. No entanto, precisamos saber
o momento de parar de executar a leitura dos registros. O comando
feof (end of file) informa se o leitor chegou ao final do arquivo ou não.
A sintaxe do feof é a seguinte:

Sintaxe

int feof(ponteiro_arquivo);

Onde:

» int: é o retorno da função. A função feof retorna um número


inteiro, que indica se o arquivo terminou ou não. Quando a
função retorna zero, significa que ainda não chegou no final do
arquivo. Qualquer valor diferente de zero, indica que chegou ao
final do arquivo.

» ponteiro_arquivo: é o ponteiro que tem o endereço do arquivo


que queremos verificar se chegou ao fim.

O exemplo 3.8 apresenta o uso do comando feof.

Exemplo 3.8: uso do comando feof

1 while (feof(paluno)==0)

Normalmente, o feof é usando como condição de um while, como


mostra o exemplo 3.8. Este while será executado enquanto não
chegar no final do arquivo.

3.2.9 Comando para remover um arquivo

Quando desejamos apagar um arquivo do diretório, podemos


utilizar o comando remove. Este comando só pode ser utilizado em
arquivos fechados. A sua sintaxe é a seguinte:

Sintaxe

remove(“nome_do_arquivo”);

Onde:

» nome_do_arquivo: é o nome do arquivo que queremos apagar.

75
Programação I

Neste caso, é utilizado o nome do arquivo salvo no diretório do


nosso computador.

O exemplo 3.9 apresenta o uso do comando remove.

Exemplo 3.9: uso do comando remove

1 remove(“alunos.bin”);

Neste exemplo, o arquivo alunos.bin será removido do


computador.

3.2.10 Comando para renomear um arquivo

Nós podemos renomear um arquivo no diretório do nosso


computador. Para isso, utilizamos o comando rename. Este comando,
também, só pode ser utilizado em arquivos fechados. A sua sintaxe é
a seguinte:

Sintaxe

rename(“nome_do_arquivo”, “novo_nome_do_arquivo”);

Onde:

» nome_do_arquivo: é o nome do arquivo que queremos


renomear. Neste caso; é utilizado o nome do arquivo salvo no
diretório do nosso computador.

» novo_nome_do_arquivo: é o novo nome para o nosso


arquivo.

O exemplo 3.10 apresenta o uso do comando rename.

Exemplo 3.10: uso do comando rename

1 rename(“alunos.bin”, “alunos_temp.bin”);

Neste exemplo, o arquivo alunos.bin, será renomeado para


alunos_temp.bin.

3.3 Implementação das operações básicas


em um arquivo

Agora é a hora de fazermos o nosso programa completo, que

76
Programação I

irá aplicar os comandos de manipulação de arquivo, descritos na


seção 3.2. Este programa irá gerenciar os dados dos alunos de uma
turma, que serão armazenados em um arquivo. O registro do aluno
é composto pela matrícula, nome e média do aluno. O programa
implementará as seguintes operações: cadastrar aluno, remover
aluno, consultar aluno por matrícula, alterar média do aluno e listagem
de todos os alunos.

Mais uma vez, teremos um programa cheio de detalhes, bem maior


do que os que fizemos até então. Por isso, o programa completo 3.1
foi desenvolvido de forma modularizada. Para facilitar o entendimento
deste programa, que tem quase 200 linhas, o mesmo foi dividido em 8
partes. Vamos começar?

Na primeira parte do programa completo 3.1, teremos as


declarações das variáveis globais do programa. Além de módulos
auxiliares, que serão utilizados ao longo do programa, por outros
módulos.

Programa Completo 3.1 - Parte 1

1 #include <stdio.h>

3 typedef struct{ int mat;

4 char nome[20];

5 float med;

6 } TAluno;

8 FILE *paluno;

9 TAluno aluno_aux, aluno_nulo;

10

11 void linha()

12 { int i;

13 for (i=1; i<=80; i++)

14 printf(“_”);

15 }

16

77
Programação I

17 void cabec()

18 { system(“cls”);

19 printf(“Universidade Federal Rural de


Pernambuco\n”);

20 linha();

21 }

22

23 void abre_arquivo()

24 { paluno = fopen(“aluno.dat”, “r+b”);

25 if (paluno == NULL)

26 paluno = fopen(“aluno.dat”, “w+b”);

27 }

Comentários sobre o Programa Completo 3.1, Parte 1:

» Linha 1: inclusão da biblioteca stdio.h devido o uso do comando


fflush e comandos de manipulação de arquivo.

» Linhas 3 a 6: definição de um novo tipo de dados – TAluno,


que agrupa os dados de um aluno. O tipo TAluno é composto
pela matrícula, nome e média do aluno.

» Linha 8: declaração do ponteiro paluno, que armazenará o


endereço do arquivo com os registros dos alunos.

» Linha 9: declaração de dois registros: aluno_aux e aluno_nulo.


O registro aluno_aux será utilizado quando precisamos ler
ou gravar um registro no arquivo. O registro aluno_nulo será
utilizado no momento da remoção de um aluno do arquivo.
As variáveis declaradas nas linhas 8 e 9 são globais, por isso,
podem ser acessadas por todos os módulos do programa.

» Linhas 11 a 15: temos o primeiro módulo do nosso programa. O


módulo linha tem como objetivo passar uma linha na tela. Este
módulo será chamado pelos demais módulos do programa.

» Linhas 17 a 21: temos a sequência de comandos do módulo


cabec. O módulo cabec faz o cabeçalho das tela. Ao iniciar uma
operação do programa (cadastro, remoção, etc), a tela deve ser
limpa e precisamos colocar o nome da universidade no topo

78
Programação I

da tela. O módulo cabec vai: limpar a tela, colocar o nome da


instituição e passar uma linha (fazendo uso do módulo linha).

» Linhas 23 a 27: temos a sequência de comandos do módulo


que é responsável por abrir o arquivo dos alunos, e deixá-lo
disponível para uso. Vamos entender a lógica deste módulo? Atenção
Primeiramente, é feita uma tentativa de abrir o arquivo
dos alunos – alunos.dat – com o modo de abertura r+b, no 7
O nome do
arquivo que
comando fopen. Lembrem que o modo de abertura r+b só nós passarmos
como parâmetro
pode ser utilizado quando o arquivo já existe. O processador
no fopen será
vai procurar o arquivo alunos.dat no diretório. Se o arquivo utilizado para
salvar nosso
não for encontrado, o ponteiro paluno, ficará com NULL. Mas, arquivo no
diretório. Por
se for encontrado, o endereço de memória do arquivo será
exemplo, após
armazenado no ponteiro paluno. Na sequência (linha 25), a execução do
módulo abre_
temos um if que testa o valor do ponteiro paluno. Se o ponteiro arquivo, teremos
um arquivo
paluno estiver com NULL, significa que o arquivo alunos.dat não
chamado alunos.
existe ainda e precisa ser criado. Se isso acontecer, o comando dat no diretório
onde está salvo
vinculado ao if é executado. Este comando é um fopen, só que o programa
executável. Por
agora utiliza o modo de abertura w+b, que deve ser utilizado
convenção,
para arquivos que não existe. Mas por que não abrimos o coloque os
arquivos de
arquivo usando logo o w+b? Vocês devem estar lembrados dados sempre
com a extensão
que o modo de abertura w+b apaga todos os registros de um
dat ou bin.
arquivo quando ele já existe. Assim, tentamos primeiro abrir o
arquivo com r+b (utilizado para arquivos que já existem e abre
o arquivo sem apagar os registros). Se der erro, é porque o
arquivo não existe. Com isso, tentamos abrir com o modo de
abertura w+b.

Vamos agora para a parte 2 do programa completo 3.1. Nesta


parte temos o módulo inserir, que é responsável pelo cadastro dos
registros dos alunos no arquivo. Para fazer o cadastro de um registro
no arquivo binário, devemos obter os dados do aluno, montando o
registro que iremos gravar no arquivo. Quando o registro estiver com
todas as informações do aluno (mat, nome e media), o mesmo poderá
ser gravado no final do arquivo.

79
Programação I

Programa Completo 3.1 - Parte 2

28 void inserir()

29 { int resp;

30 do { cabec();

31 printf(“\n\nCadastrar novo aluno\n\n”);

32 printf(“\nMatricula: “);

33 scanf(“%d”, &aluno_aux.mat);

34 printf(“\nNome.....: “);

35 fflush(stdin);

36 gets(aluno_aux.nome);

37 printf(“\nMedia....: “);

38 scanf(“%f”, &aluno_aux.med);

39 fseek(paluno, 0, SEEK_END);

40 fwrite(&aluno_aux, sizeof(TAluno), 1,
paluno);

41 printf(“\n\nAluno cadastrado com sucesso!


\n\n”);

42 printf(“\nDeseja cadastrar outro


(1-sim/0-nao)? “);

43 scanf(“%d”, &resp);

44 } while (resp ==1);

45 }

Comentários sobre o Programa Completo 3.1, Parte 2

» Linha 28: início do módulo inserir.

» Linha 29: declaração da variável resp. Esta variável irá


armazenar a resposta do usuário, quando for perguntado se ele
deseja cadastrar mais alunos.

» Linha 30: início de um do/while. O módulo inserir ficará


executando enquanto o usuário desejar cadastrar novos alunos.
Nesta linha, também temos a chamada do módulo cabec. Cada
vez que um cadastro é feito, a tela vai ser limpa, para iniciar um

80
Programação I

novo cadastro.

» Linha 31: printf que informa o que esta tela faz – cadastro de
alunos.

» Linhas 32 e 33: printf solicitando que seja digitada a matrícula


do aluno e scanf que lê esta informação. Os dados do aluno
vão sendo colocados no registro aluno_aux.

» Linhas 34 a 36: printf solicitando que seja digitado o nome do


aluno, fflush para limpar o buffer de entrada (já que teremos a
leitura de uma sequência de caractere) e o gets que lê o nome
do aluno e armazena no registro aluno_aux.

» Linhas 37 e 38: printf solicitando que seja digitada a média do


aluno e scanf que lê esta informação. Neste momento, o registro
aluno_aux acabou de ser todo preenchido com os dados do
aluno e já pode ser gravado no arquivo.

» Linha 39: para gravar o registro no arquivo, devemos posicionar


o leitor no final do arquivo para não correr o risco de fazer a
gravação sobre algum outro registro. Para isso, é executado o
fseek.

» Linha 40: com o leitor posicionado no final do arquivo, podemos


executar o fwrite, que vai gravar o conteúdo do registro aluno_
aux, no nosso arquivo.

» Linha 41: printf para informar que o aluno foi cadastrado com
sucesso.

» Linhas 42 e 43: printf para pergunta se o usuário deseja


cadastrar outro aluno e scanf que lê a resposta para esta
pergunta.

» Linha 44: final do do/while, com a condição de parada. O do/


while é executado enquanto o usuário estiver respondendo que
quer cadastrar mais alunos. Notem que não precisamos nos
preocupar com a capacidade do arquivo. Vamos armazenando
quantos registros desejarmos.

» Linha 45: fecha chaves que indica o final do módulo inserir.

A figura 3.7 apresenta a tela de execução do programa 3.1, na tela


de cadastro de novo aluno.

81
Programação I

Figura 3.7: Tela de cadastro de aluno

Vamos ver agora o código de dois módulos que serão utilizados


pelos módulos: consultar aluno por matrícula, remover aluno e alterar
média do aluno. Quando fazemos uma consulta, alteração ou remoção,
precisamos localizar o registro do aluno no arquivo e apresentar o
registro para o usuário. Por isso, foi criado um módulo responsável
para procurar um registro no arquivo e, outro módulo, responsável por
apresentar os dados do registro de um aluno. Vamos lá, entender a
parte 3 do nosso programa completo 3.1!

Programa Completo 3.1 - Parte 3

46 int procura(int matp)

47 { int p;

48 p = 0;

49 rewind(paluno);

50 fread(&aluno_aux, sizeof(TAluno), 1, paluno);

51 while (feof(paluno)==0)

52 { if (aluno_aux.mat == matp)

53 return p;

54 else

55 { fread(&aluno_aux, sizeof(TAluno), 1,
paluno);

56 p++;

82
Programação I

57 }

58 }

59 return -1;

60 }

61

62 void mostre(int pos)

63 { fseek(paluno, pos*sizeof(TAluno), SEEK_SET);

64 fread(&aluno_aux, sizeof(TAluno), 1, paluno);

65 printf(“\n\n”);

66 linha();

67 printf(“Matricula Nome Media\n”);

68 linha();

69 printf(“%9d %-20s %5.1f\n”, aluno_aux.mat,

70 aluno_aux.nome, aluno_aux.med);

71 linha();

72 }

Comentários sobre o Programa Completo 3.1, Parte 3:

» Linhas 46 a 60: temos a sequência de comandos do módulo


procura. O módulo recebe um parâmetro, que é a matrícula do
aluno que está sendo procurado. Ao finalizar a sua execução,
esse módulo retorna um int que pode ser: -1 (significa que
procurou o registro do aluno no arquivo e não achou) ou um
número positivo (que significa em qual posição do arquivo
o registro foi encontrado). Este módulo possui uma variável
local p, que é incrementada cada vez que é feita a leitura de
um registro no arquivo. É o valor desta variável que indica em
que posição do arquivo o registro foi encontrado. Para localizar
o registro de um aluno, com uma dada matrícula, precisamos
percorrer todo o arquivo, até encontrar o registro ou até o
arquivo chegar ao fim. Para percorrer o arquivo, colocamos
o leitor no início do mesmo (usando o rewind – linha 49) e
efetuamos vários fread, até que chegue no final do arquivo
(while da linha 51). Logo após posicionar o leitor no início do

83
Programação I

arquivo, fazemos a leitura do primeiro registro do arquivo, para


verificar se não é o final de arquivo (end of file). Lembrem que,
assim que um fread é executado, o leitor já fica posicionado no
início do próximo registro, pronto para um novo fread. Quando
um registro do arquivo tem a mesma matrícula que está sendo
procurada, significa que encontramos o aluno. Com isso, já
pode ser dado o retorno, indicando a posição onde o registro
foi encontrado (linha 52 e 53). Se fizermos a leitura de todos
os registros do arquivo e não encontrar nenhum aluno com a
matrícula procurada, o módulo retornará -1 (linha 59).

» Linhas 62 a 72: temos a sequência do módulo mostre. Este


módulo recebe como parâmetro a posição do registro que deve
ser apresentado, recupera o registro no arquivo e apresenta
os dados do registro em forma de tabela. O módulo começa
com o posicionamento do leitor no início do registro que deve
ser mostrado (linha 63). Notem que, no fseek, no campo que
indica o tamanho do deslocamento que o leitor vai dar, é
feita a conta: pos*sizeof(TAluno). Vamos entender o porquê
desta conta. A variável pos indica em que posição o registro
está armazenado no arquivo (se ele é o primeiro, segundo,
etc.). Consequentemente, saberemos quantos registros tem
armazenados antes do registro que queremos mostrar. E assim,
saberemos sobre quantos registros o leitor deve se deslocar,
até ser posicionado no início do registro desejado. Com o leitor
no ponto certo, podemos fazer a leitura do registro do aluno,
armazenando seus dados no registro aluno_aux (linha 64).
Após isto, precisamos apenas apresentar os dados do aluno
(linhas 65 a 71).

Vamos agora entender o módulo responsável por consultar


um aluno através do seu número de matricula. O módulo consultar
vai solicitar que o usuário informe a matrícula do aluno que deseja
consultar. Através do uso do módulo procura é descoberta em que
posição o registro do aluno se encontra armazenado no arquivo. Se o
aluno estiver armazenado no arquivo, seus dados são apresentados,
através do uso do módulo mostre. Se o aluno não for encontrado, é
apresentada uma mensagem de erro.

84
Programação I

Programa Completo 3.1 - Parte 4

73 void consultar()

74 { int resp, matcon, posicao;

75 do{ cabec();

76 printf(“\n\nConsultar Aluno\n\n\n”);

77 printf(“Matricula do aluno: “);

78 scanf(“%d”, &matcon);

79 posicao = procura(matcon);

80 if (posicao == -1)

81 printf(“\n\nMatricula nao encontrada!


\n\n”);

82 else

83 mostre(posicao);

84 printf(“\n\nDeseja consultar outro


(1-sim/0-nao)? “);

85 scanf(“%d”, &resp);

86 } while (resp == 1);

87 }

Comentários sobre o Programa Completo 3.1, Parte 4

» Linha 73: início do módulo consultar.

» Linha 74: declaração das variáveis locais: resp, matcon


(matricula que será consultada) e posicao (armazena em que
posição o registro foi localizado).

» Linha 75: início de um do/while. O módulo consultar ficará


executando enquanto o usuário desejar consultar alunos. Nesta
linha, também temos a chamada do módulo cabec. Cada vez
que uma consulta é feita, a tela vai ser limpa, para iniciar uma
nova consulta.

» Linha 76: printf que informa o que esta tela faz – consultar
aluno.

» Linhas 77 e 78: printf solicitando que seja digitada a matrícula

85
Programação I

do aluno que deseja consultar e scanf que lê esta informação.

» Linha 79: chamada do módulo procura, passando a matrícula


que desejamos consultar como parâmetro. O retorno do módulo
procura é armazenado na variável posicao.

» Linhas 80 a 83: if que verifica se a variável posicao tem


armazenado -1. Se sim, é porque o aluno não foi encontrado.
Com isso, é escrita uma mensagem de erro. Caso posicao não
esteja com -1, é porque o aluno foi encontrado e seus dados
devem ser apresentados. Para apresentar os dados do aluno,
fazemos uma chamada ao módulo mostre, passando a posição
onde o aluno foi encontrado como parâmetro.

» Linhas 84 e 85: printf para pergunta se o usuário deseja


consultar outro aluno e scanf que lê a resposta para esta
pergunta.

» Linha 86: final do do/while, com a condição de parada. O do/


while é executado enquanto o usuário estiver respondendo que
quer consultar mais alunos.

» Linha 87: fecha chaves que indica o final do módulo consultar.

A figura 3.8 apresenta a tela de execução do programa 3.1, na tela


de consulta aluno por matrícula.

Figura 3.8: Tela de consulta aluno por matrícula

Vamos agora entender o módulo responsável por remover um


aluno do arquivo. O módulo da remoção inicia de forma muito similar
ao da consulta. Primeiro, é solicitado o número da matrícula do aluno

86
Programação I

que será removido, seu registro é localizado e apresentado para que o


usuário possa ter certeza que vai remover o registro certo. Na verdade,
um registro não é removido do arquivo, o que fazemos é gravar sobre
o registro do aluno que queremos remover, um registro com os dados
zerados (aluno_nulo). Assim, toda vez que temos um registro com
a matrícula igual a zero no arquivo, significa que ele é um registro
que foi removido. Se o aluno não for encontrado, é apresentada uma
mensagem de erro.

Programa Completo 3.1 - Parte 5

88 void remover()

89 { int matrem, conf, resp, posicao;

90 aluno_nulo.mat = 0;

91 aluno_nulo.med = 0;

92 do{ cabec();

93 printf(“\n\nRemover aluno\n\n\n”);

94 printf(“Matricula: “);

95 scanf(“%d”, &matrem);

96 posicao = procura(matrem);

97 if (posicao == -1)

98 printf(“\nAluno nao encontrado!!\a”);

99 else

100 { mostre(posicao);

101 printf(“\n\nDeseja remover o aluno


(1-sim/0-nao)? “);

102 scanf(“%d”, &conf);

103 if (conf == 1)

104 { f s e e k ( p a l u n o , p o s i c a o * s i z e o f
(TAluno),SEEK_SET);

105 f w r i t e ( & a l u n o _ n u l o ,
sizeof(TAluno), 1, paluno);

106 printf(“\n\nAluno removido com


sucesso!”);

107 }

87
Programação I

108 else

109 printf(“\nRemocao cancelada!”);

110 }

111 printf(“\n\n\nDeseja remover outro


(1-sim/0-nao)? “);

112 scanf(“%d”, &resp);

113 } while (resp ==1);

114 }

Comentários sobre o Programa Completo 3.1, Parte 5:

» Linha 88: início do módulo remover.

» Linha 89: declaração das variáveis locais: resp, matrem


(matricula que será removida), conf (confirmação se deseja
remover realmente) e posicao (armazena em que posição o
registro foi localizado).

» Linhas 90 e 91: inicialização dos campos do registro aluno_


nulo.

» Linha 92: início de um do/while. O módulo remover ficará


executando enquanto o usuário desejar remover alunos. Nesta
linha, também temos a chamada do módulo cabec. Cada vez
que uma remoção é feita, a tela vai ser limpa, para iniciar uma
nova remoção.

» Linha 93: printf que informa o que esta tela faz – remover
aluno.

» Linhas 94 e 95: printf solicitando que seja digitada a matrícula


do aluno que deseja remover e scanf que lê esta informação.

» Linha 96: chamada do módulo procura, passando a matrícula


que desejamos remover como parâmetro. O retorno do módulo
procura é armazenado na variável posicao.

» Linhas 97 a 110: if que verifica se a variável posicao tem


armazenado -1. Se sim, é porque o aluno não foi encontrado.
Com isso, é escrita uma mensagem de erro. Caso posicao não
esteja com -1, é porque o aluno foi encontrado e seus dados
devem ser apresentados. Para apresentar os dados do aluno,

88
Programação I

fazemos uma chamada ao módulo mostre, passando a posição


onde o aluno foi encontrado como parâmetro. Após ver os dados
do aluno, o usuário pode desistir de removê-lo. Na linha 102,
temos o scanf que lê se o usuário confirma ou não a remoção. A
remoção, propriamente dita, é executada nas linhas 104 e 105.
Na linha 104, temos o posicionamento do leitor sobre o registro
que queremos remover. E, na linha 105, temos a gravação do
registro aluno_nulo sobre o registro antigo.

» Linhas 111 e 112: printf para pergunta se o usuário deseja


remover outro aluno e scanf que lê a resposta para esta
pergunta.

» Linha 113: final do do/while, com a condição de parada. O do/


while é executado enquanto o usuário estiver respondendo que
quer remover mais alunos.

» Linha 114: fecha chaves que indica o final do módulo remover.

A figura 3.9 apresenta a tela de execução do programa 3.1, na tela


de remoção de aluno.

Figura 3.9: Tela de remoção do registro do aluno

Agora vamos entender o módulo responsável pela alteração da


média do aluno. Este módulo é parecido com a remoção. Primeiro,
é solicitado o número da matrícula do aluno que será alterado, seu
registro é localizado e apresentado para que o usuário possa ter
certeza que vai alterar o registro certo. Na alteração, gravamos um
registro com a média alterada, sobre o antigo registro do aluno.

89
Programação I

Programa Completo 3.1 - Parte 6

115 void alterar()

116 { int matalt, conf, resp, posicao;

117 do { cabec();

118 printf(“\n\nAlterar media do aluno\n\


n\n”);

119 printf(“Matricula: “);

120 scanf(“%d”, &matalt);

121 posicao = procura(matalt);

122 if (posicao == -1)

123 printf(“\nAluno,nao encontrado!!\a”);

124 else

125 { mostre(posicao);

126 printf(“\n\nAlterar a media do


aluno(1-sim/0-nao)? “);

127 scanf(“%d”, &conf);

128 if (conf == 1)

129 { printf(“\nNova media: “);

130 scanf(“%f”, &aluno_aux.med);

131 printf(“\nMedia alterada com sucesso!


\n\n”);

132 fseek(paluno,posicao*sizeof(TAluno),
SEEK_SET);

133 fwrite(&aluno_aux,sizeof(TAluno), 1,
paluno);

134 mostre(posicao);

135 printf(“\nMedia do aluno alterada com


sucesso!\n”);

136 }

137 else

90
Programação I

138 printf(“\n\nAlteracao cancelada!


\n\n”);

139 }

140 printf(“\n\nDeseja alterar outro


(1-sim/0-nao)? “);

141 scanf(“%d”, &resp);

142 }while (resp ==1);

143 }

Comentários sobre o Programa Completo 3.1, Parte 6:

» Linha 115: início do módulo alterar.

» Linha 116: declaração das variáveis locais: resp, matalt


(matricula que será alterada), conf (confirmação se deseja
alterar a média do aluno) e posicao (armazena em que posição
o registro foi localizado).

» Linha 117: início de um do/while. O módulo alterar ficará


executando enquanto o usuário desejar alterar alunos. Nesta
linha, também temos a chamada do módulo cabec. Cada vez
que uma alteração é feita, a tela vai ser limpa, para iniciar uma
nova alteração.

» Linha 118: printf que informa o que esta tela faz – alterar média
do aluno.

» Linhas 119 e 120: printf solicitando que seja digitada a matrícula


do aluno que deseja alterar e scanf que lê esta informação.

» Linha 121: chamada do módulo procura, passando a matrícula


que desejamos alterar como parâmetro. O retorno do módulo
procura é armazenado na variável posicao.

» Linhas 122 a 139: if que verifica se a variável posicao tem


armazenado -1. Se sim, é porque o aluno não foi encontrado.
Com isso, é escrita uma mensagem de erro. Caso posicao não
esteja com -1, é porque o aluno foi encontrado e seus dados
devem ser apresentados. Para apresentar os dados do aluno,
fazemos uma chamada ao módulo mostre, passando a posição
onde o aluno foi encontrado como parâmetro. Após ver os dados
do aluno, o usuário pode desistir de alterar a sua média. Na

91
Programação I

linha 127, temos o scanf que lê se o usuário confirma ou não a


alteração. Se o usuário confirma que quer alterar, é solicitada
a nova média do aluno (linha 130). A alteração, propriamente
dita, é executada nas linhas 132 e 133. Na linha 132, temos o
posicionamento do leitor sobre o registro que queremos alterar.
E, na linha 133, temos a gravação do registro alterado sobre o
registro antigo. Após os dados serem alterados, o registro do
aluno é reapresentado através de uma chamada ao módulo
mostre (linha 134).

» Linhas 140 e 141: printf para pergunta se o usuário deseja


alterar outro aluno e scanf que lê a resposta para esta
pergunta.

» Linha 142: final do do/while, com a condição de parada. O do/


while é executado enquanto o usuário estiver respondendo que
quer alterar mais alunos.

» Linha 143: fecha chaves que indica o final do módulo alterar.

A figura 3.10 apresenta a tela de execução do programa 3.1, na


tela de alteração de média do aluno.

Figura 3.10: Tela de alteração de média do aluno

Veremos, agora, o último módulo do programa, que é a listagem.


Este módulo é responsável por apresentar todos dados dos alunos
que estão armazenados no arquivo. Os dados serão apresentados
em forma de tabela. Devemos lembrar que só iremos apresentar os

92
Programação I

registros válidos do arquivo, ou seja, registros com matrícula zerada


não devem ser apresentados.

Programa Completo 3.1 - Parte 7

144 void listagem()

145 { cabec();

146 printf(“\n\nListagem Geral\n\n\n”);

147 linha();

148 printf(“Matricula Nome Media\n”);

149 linha();

150 rewind(paluno);

151 fread(&aluno_aux, sizeof(TAluno), 1, paluno);

152 while (feof(paluno)==0)

153 { if (aluno_aux.mat != 0)

154 printf(“%9d %-20s %5.1f\n”, aluno_aux.


mat,

155 aluno_aux.nome, aluno_aux.med);

156 fread(&aluno_aux, sizeof(TAluno), 1,


paluno);

157 }

158 linha();

159 printf(“tecle enter para voltar ao menu...”);

160 getche();

161 }

Comentários sobre o Programa Completo 3.1, Parte 7

» Linha 144: início do módulo listagem.

» Linha 145: chamada ao módulo cabec, responsável por limpar


a tela e escrever o nome da instituição.

» Linha 146: printf que informa o que esta tela faz – listagem
geral.

» Linha 147: chamada do módulo linha, para iniciar o desenho


da tabela.

93
Programação I

» Linha 148: printf que escreve os cabeçalhos das colunas da


tabela.

» Linha 149: mais uma chamada ao módulo linha.

» Linha 150: posiciona o leitor no início do arquivo, para que


possamos “varrer” o arquivo, visitando todos os registros do
arquivo.

» Linha 151: Leitura do primeiro registro do arquivo, para verificar


se não é o final do arquivo.

» Linhas 152 a 157: while que é executado enquanto não chegar


no final do arquivo. Para cada registro lido, é verificado se o
mesmo tem a matrícula igual a zero. Se sim, o registro não é
apresentado na listagem.

» Linha 158: chamada do módulo linha, para fechar a tabela.

» Linha 159: printf informando que o usuário deve teclar enter


para sair da listagem.

» Linha 160: getche para que possamos ver a listagem.

» Linha 161: fecha chaves que indica o final do módulo listagem.

A figura 3.11 apresenta a tela de execução do programa 3.1, na


tela de listagem dos dados de todos os alunos.

Figura 3.11: Tela de listagem de dados de todos os alunos

O programa principal do Programa completo 3.1 é apresentado a


seguir. É no programa principal que serão feitas as chamadas aos
módulos que o usuário deseja executar no momento.

94
Programação I

Programa Completo 3.1 - Parte 8

162 main()

163 { int op;

164 abre_arquivo();

165 do{ cabec();

166 printf(“\n\nOpcoes: \n\n\n”);

167 printf(“ 1- Cadastrar novo aluno\n\n”);

168 printf(“ 2- Remover aluno\n\n”);

169 printf(“ 3- Consultar aluno por


matricula\n\n”);

170 printf(“ 4- Alterar media do aluno
\n\n”);

171 printf(“ 5- Listagem geral\n\n”);

172 printf(“ 0- Sair\n\n”);

173 linha();

174 printf(“Informe a opcao desejada: “);

175 scanf(“%d”, &op);

176 switch(op)

177 { case 1: inserir(); break;

178 case 2: remover(); break;

179 case 3: consultar(); break;

180 case 4: alterar(); break;

181 case 5: listagem(); break;

182 case 6: limpar(); break;

183 case 0: fclose(paluno); break;

184 default: printf(“\n\n\aOpcao


invalida!”);

185 break;

95
Programação I

186 }

187 } while (op != 0);

188 }

Comentários sobre o Programa Completo 3.1, Parte 8:

» Linha 162: início do programa principal.

» Linha 163: declaração da variável local op, que vai armazenar


a operação que o usuário deseja executar.

» Linha 164: chamada do módulo abre_arquivo, disponibilizando


o mesmo para uso.

» Linhas 165 a 187: do/while responsável por ler a operação


que o usuário quer executar e fazer a chamada do módulo que
implementa a operação.

» Linha 188: fecha chaves do programa principal.

A figura 3.12 apresenta a tela de execução do programa 3.1, na


tela do menu principal, onde é informada a operação que desejamos
executar.

Figura 3.12: Tela do menu principal

E assim, terminamos mais um programa completo. Agora, é colocar


a mão no teclado e começar a programar, armazenando dados em
arquivos.

96
Programação I

Atividades e Orientações de Estudos

Temos agora mais uma lista de exercícios para consolidar o nosso


entendimento do assunto visto neste capítulo. Preparem-se, pois as
questões estão maiores. Mas isso é bom porque vemos que estamos
fazendo programas interessantes, não é mesmo?

1. Faça um programa para um shopping contendo as seguintes


telas:

Tela de Menu

Shopping Center

Opções:
1 .Cadastrar loja
2. Consultar loja
3. Listagem de todas as lojas
0. Sair

Entre com a opção:

Cadastro

Shopping Center

Cadastro de Loja

Código:
Nome:
Área:
Tipo(1-Confecções, 2-Alimentação, 3-Livros, 4- Serviços):

Cadastrar outra (1-Sim/0-Nao)?

Consulta

Shopping Center

Consultar Loja

Código da loja que deseja consultar:

Código Nome Área Tipo Condomínio

xxx xxxxxxx xx xx xxxx

Consultar outra (1-Sim/0-Nao)?

97
Programação I

Relatório Geral

Shopping Center

Listagem Geral

Codigo Nome Área Tipo Condomínio

xxx xxxxxxx xx xx xxxxx

xxx xxxxxxx xx xx xxxxx

xxx xxxxxxx xx xx xxxxx

Tecle enter para voltar ao menu...

» O programa irá armazenar os dados das lojas em um arquivo.

» O programa irá calcular o valor do condomínio de cada loja. O


valor do condomínio depende da área e do tipo da loja. Veja
tabela abaixo:

Tipo da loja Valor do m²

1 R$ 50

2 R$ 65

3 R$ 80

4 R$ 95

2. Faça um programa para uma Agência de Turismo armazenando


os dados em um arquivo. O programa deverá ter as seguintes
funções: Cadastrar roteiro, Consultar roteiro, Listagem de todos
os roteiros e Simular valor de viagem. A seguir, sugestões de
telas.

Tela Principal

Vida Boa Turismo

Opções:
1- Cadastrar roteiro
2- Consultar roteiro
3- Listagem de todos os roteiros
4- Simular viagem
0- Sair

Entre com a opção:

98
Programação I

Tela de Cadastro

Vida Boa Turismo

Cadastrar Roteiro

Código:
País(1-Brasil, 2-Espanha, -3-Italia):
Cidade:
Diária de Hotel: R$
Diária Aluguel de Carro: R$

Inserir outro(1-sim,2-não)?

Tela de Remoção de Roteiro

Vida Boa Turismo

Consultar Roteiro

Código do roteiro a ser consultado:

Código País Cidade Diária Hotel Carro

xxx x xxxxxxxx xxx xxxx

Consultar outro (1-Sim/0-Nao)?

Tela de Listagem de todos os roteiros

Vida Boa Turismo

Listagem de todos os roteiros

Código País Cidade Diária Hotel Carro

xxx x xxxxxxxx xxx xxxx

xxx x xxxxxxxx xxx xxxx

xxx x xxxxxxxx xxx xxxx

Página x de x... Tecle enter

Tecle enter para voltar ao menu...

99
Programação I

Tela para simular valor de viagem

Vida Boa Turismo

Simular Viagem

Código do roteiro:

Código País Cidade Diária Hotel Carro

xxx x xxxxxxxx xxx xxxx

Quantidade de dias:
Alugar carro(1-sim, 2-não)?

Valor total da viagem = R$ xxxxx

Simular outro roteiro(1-sim, 2-não)?

Observações:

» Os dados do roteiro devem ser armazenados em um arquivo.


Não pode cadastrar roteiros com códigos repetidos.

» O valor da viagem deve ser calculado com


base nos valores do roteiro escolhido;
viagem = quantos dias * valor diária hotel + quantos dias * valor
diária carro (caso alugue carro).

» Na consulta deve passar o código do roteiro e apresentar os


dados do roteiro.

» Na listagem, apresentar os dados de todos os roteiros em forma


de tabela.

Conheça Mais

Para melhorar o nosso conhecimento sobre manipulação de


arquivos binários, vejam este assunto nos livros:

LAUREANO, Marcos. Programando em C Para Linux, Unix e


Windows. Rio de Janeiro: Brasport, 2005.

MIZRAHI, Victorine Viviane. Treinamento em Linguagem C –


Curso Completo. São Paulo: Makron, 1999.

100
Programação I

Vamos revisar?

Vamos fazer uma revisão do assunto que foi visto neste capítulo,
lendo o resumo a seguir:

» Os arquivos servem para armazenar nossos dados de forma


definitiva.

» Os arquivos binários são adequados para o armazenamento de


registros.

» Cada registro que é armazenado no arquivo ocupa a mesma


quantidade de memória.

» Um ponto importante sobre arquivos é que toda operação sobre


um arquivo será executada no ponto onde o leitor se encontra.

» Com o comando fseek, podemos colocar o leitor sobre o registro


que desejamos ler ou gravar.

» Só podemos manipular um arquivo que esteja aberto. Após o uso


do arquivo, devemos fechá-lo.

» O arquivo criado pelo programa é salvo no mesmo diretório em


que está armazenado o nosso programa executável.

101
Programação I

Referências

ARAÚJO, Jairo. Dominando a Linguagem C. São Paulo:


Ciência Moderna, 2004.

ASCENIO, Ana Fernanda Gomes e CAMPOS, Edilene


Aparecida Veneruchi. Fundamentos de Programação de
Computadores. São Paulo: Prentice Hall, 2002.

DEITEL, H, M e DEITEL, P. J. Como Programar em C. Rio de


Janeiro: LTC, 1999.

LAUREANO, Marcos. Programando em C Para Linux, Unix e


Windows. Rio de Janeiro: Brasport, 2005.

MIZRAHI, Victorine Viviane. Treinamento em Linguagem C –


Curso Completo. São Paulo: Makron, 1999.

MONTGOMERY, Eduard. Programando em C: Simples e


Prático. São Paulo: Alta Books, 2006.

OLIVEIRA, Ulisses. Programando em C – Volume I –


Fundamentos. São Paulo: Ciência Moderna, 2004.

SCHILDT, Herbert. C Completo e Total. São Paulo: Makron,


1996.

102
Programação I

Considerações Finais

Neste volume, tivemos a oportunidade de aprender como


armazenar dados em vetores, registros e arquivos. O armazenamento
adequado dos dados possibilitou o desenvolvimento de programas
com operações mais elaboradas como: cadastro de elementos,
remoção, alteração, consultas e listagens. Perceberam o quanto
nossos programas evoluíram desde o nosso primeiro programa
completo, até hoje? Vejam que todos os conceitos que aprendemos
estão sempre em uso nos nossos programas. Isto é bom porque nos
acostumamos com a sintaxe dos comandos. Agora, temos apenas
mais um módulo para finalizar a nossa caminhada, em busca do
aprendizado da linguagem de programação C. Continuem firmes nos
estudos! Estamos quase no final! Até o próximo módulo.

103
Programação I

Conhecendo a Autora

Sou graduada em Ciência da computação pela Universidade


Federal de Sergipe. Fiz mestrado e doutorado na Universidade Federal
de Pernambuco, desenvolvendo pesquisas nas áreas de Sistemas
Distribuídos e Geoprocessamento. Começei a ensinar em 2000, nos
cursos de Ciência da Computação e Sistemas de Informação. Desde
o início da minha carreira como professora, ministro disciplinas de
Programação e tenho uma paixão pela linguagem C. Atualmente,
encontrei uma nova paixão: Educação a Distância.

104

Вам также может понравиться