Universidade Metodista de Piracicaba UNIMEP
Faculdade de Ciência e Tecnologia da Informação

Março/2000

ÍNDICE

1.	Funções
. Conceituação

. Passagem de parâmetros por valor;

. Passagem de parâmetros por referência.

2.	Ponteiros
. Conceituação
. Operadores associados a ponteiros;
	. Ponteiros e Matrizes
	
3.	Tipos Estruturados
. Estruturas;
. Uniões;
. Enumeração e 
. Tipo Definido.
4.	Arquivos
. Operações Básicas com arquivos;
. Operações Básicas com registros;
. Modos de acesso a registros.

1.	FUNÇÕES

As funções permitem ao programador separar um programa longo em várias partes menores, cada qual com uma finalidade específica, tornando assim o programa modular. Além desta vantagem podemos destacar outras como: a repetição das mesmas instruções de programa em diferentes pontos do programa, clareza na representação de lógica, portabilidade no caso da criação de bibliotecas e etc.
Sendo assim a função é um seguimento independente do programa que executa uma tarefa específica. Todo o programa em “C” é formado por uma ou mais funções. Uma dessas funções deve ser a função main(). As funções adicionais do programa estarão subordinadas à função main() ou a alguma outra função. Se um programa contém várias funções, suas definições podem aparecer em qualquer ordem. Uma função será executada quando for chamada. Após a execução, o controle retorna para o ponto no qual a função foi chamada.
Forma Geral:-
		tipo   nome_da_função (lista de parâmetros)
		  {
			corpo da função;
  		  }
Onde: 
tipo – define o tipo da informação que a função vai retornar, podendo ser qualquer tipo válido. Se nenhum tipo for especificado o compilador assume que a função devolve um resultado inteiro (default), quando a função não retorna nenhum resultado coloca-se void;
nome_da_função – identificador criado pelo programador;
lista de parâmetros – são as informações passadas para a função também conhecidas como argumentos. Uma função pode não conter argumentos, lista vazia entre parênteses. Todos os parâmetros da função devem conter o tipo e o nome da variável.
As variáveis declaradas dentro de uma função não podem interagir com o código ou os dados definidos em outra função, conceito de variáveis locais.
O padrão ANSI expandiu a declaração de funções colocando-se a utilização de protótipos. Sua finalidade é a de informar ao compilador a existência de outras funções no programa além da função main(). Isto faz com que o compilador avalie os tipos especificados nos parâmetros evitando incompatibilidade de tipo na chamada a função.
Exemplo:
#include <stdio.h>
#include <conio.h>
void tela1();     // protótipo da função tela1()
void tela2();     // protótipo da função tela2()

void  tela1()
{   clrscr();
    gotoxy(20,10);printf(“Digite o Registro Acadêmico.....”);
    gotoxy(20,12);printf(“Digite o nome do aluno.............”);
    gotoxy(20,14);printf(“Digite a média do aluno............”);
}
void tela2()
{    clrscr();
     gotoxy(20,10);printf(“A média geral da classe é.....”);
     gotoxy(40,20);printf(“Tecle algo !!”);
}
void main()
{   float media_a, media_g=0;
    char ra[10], nome[25];
    int x;
    for (x=1;x<=40;x++)
       { tela1();
         gotoxy(40,10);gets(ra);
         gotoxy(40,12);gets(nome);
         gotoxy(40,14);scanf(“%f”,&media_a);
         media_g+=media_a;
       }
      media_g/=40;
      tela2();
      gotoxy(50,10);printf(“%6.2”,media_g);
      getchar();
}   

A função pode retornar um tipo de dado através do comando return. Esse comando tem dois importantes usos: provoca uma saída imediata da função retornando ao código chamador e ele pode ser usado também para devolver uma informação. Todas as  funções podem devolver uma informação exceto as do tipo void (vazio). O default é o tipo int, ou seja, uma função para a qual não declaramos o tipo de retorno é considerada como retornando um inteiro.
Além de retornar informações as funções podem receber informações através dos argumentos (passagem de parâmetros).
Exemplo1:- O programa abaixo verifica se um número é par ou ímpar.
#include <stdio.h>
#include <conio.h>
int verifica( int a);
int verifica ( int a)
{    
    if (a % 2) return (0);
    else return (1);
}
void main()
  {    int num,resp;
   clrscr();
   printf(“Entre com um numero inteiro : “);
   scanf(“%d”,&num);
  resp=verifica(num);
  if  (resp==1)   printf(“ O número é impar !!  \n”);
  else                printf(“ O número é par!! \n”);
}

Exemplo2:- O programa abaixo retorna o quadrado de um número dado.

#include <stdio.h>
#include <conio.h>
int quadrado( int x);

void main()
  {    int n;
   clrscr();
   printf(“Entre com um numero inteiro : “);
   scanf(“%d”,&n);
   printf(“ \n\n O quadrado do número é : %d”, quadrado(n));
}

int quadrado( int x)
{    return (x*x); }

Em “C” podemos ter dois tipos de parâmetros: passagem de parâmetros por valor e passagem de parâmetros por referência.
Na passagem de parâmetros por valor as informações dos parâmetros  são copiadas para a função receptora. As alterações nesses parâmetros não tem nenhum efeito na função de origem da informação.
Na passagem de parâmetros por referência, é enviado o endereço do parâmetro para a função receptora, dessa forma o endereço é usado para acessar as informações originais. Isto  significa que qualquer alteração efetuada no parâmetro estará modificando  o conteúdo original da informação enviada.

Exemplo3:-  O exemplo abaixo envia duas variáveis numéricas para uma função utilizando passagem de parâmetros por referência.

#include <stdio.h>
#include <conio.h>
void  calculo (int *a,int *b);
void main()
{
   int num1=100,num2=200;
   calculo (&num1,&num2);
printf(“\n Os valore atuais de num1= %d   e num2 = %d”,num1,num2);
}
void  calculo (int *a, int *b)
{
    *a = *a *2;
    *b = *b – 50;
}
O resultado será:  num1=200 e num2=150;

Exemplo4 :-  O programa abaixo lê uma string e conta quantos caracteres são dígitos, quantos são vogais, quantos são consoantes e quantos são espaços em branco. O exemplo usa passagem de parâmetros e aritmética de ponteiros  

#include <stdio.h>
#include <conio.h>
#include <ctype.h>

void analisa (char linha[], int *pv, int *pc,int *pd, int *pb, int *po);

void main()
{ char linha[80];
  int vogais=0,consoantes=0,digitos=0,brancos=0,outros=0;
  clrscr();
  printf("Digite uma linha de texto:\n");
  gets(linha);
  analisa(linha, &vogais, &consoantes, &digitos, &brancos,&outros);
  printf("\n No de vogais: %d",vogais);
  printf("\n No de consoantes: %d",consoantes);
  printf("\n No de digitos: %d",digitos);
  printf("\n No de brancos: %d",brancos);
  printf("\n No de outros: %d",outros);
  getchar();getchar();
  }
  void analisa (char linha[], int *pv, int *pc, int *pd, int *pb, int *po)
  {  char c;
     int cont=0;
     while ((c=toupper(linha[cont])) != '\0') {
     if (c=='A' || c=='E' || c=='I' || c=='O'|| c=='U')
     ++ *pv;
     else if (c>= 'A'&& c<='Z')
     ++ *pc;
     else if (c>='0' && c<='9')
     ++ *pd;
     else if (c==' '  || c=='t')
     ++ *pb;
     else ++*po;
     ++ cont;
     }
     }

Exemplo5:-  O programa abaixo lê um vetor de números inteiros e eleva cada um dos seus elementos ao quadrado armazenado o resultado no próprio vetor. Os elementos do vetor são enviados um por um para uma função que calcula o quadrado do número.

#include <stdio.h>
#include <conio.h>

void eleva (int *x);

void main()
{ int x[10];
  int i;
  clrscr();
  for (i=0;i<9;i++){
    gotoxy(10,i+2);
    scanf("%d",&x[i]);
    eleva(&x[i]);
    printf("%d",x[i]);
    }
    getchar();
    }
void  eleva (int *x)
  {*x=*x * *x;}

2. PONTEIROS
Uma das mais poderosas características oferecidas pela Linguagem “C” é o uso de ponteiros.
Um ponteiro proporciona um modo de acesso a variáveis sem referenciá-las diretamente. O mecanismo usado para isto é o endereço da variável.
Os ints guardam inteiros, os floats guardam números de ponto flutuante , os chars guardam caracteres e os ponteiros guardam endereços de memória.
“Um ponteiro é uma variável que contém um endereço de memória. Esse endereço é normalmente a posição de uma outra variável na memória. Se uma variável contém o endereço de uma outra, então diz-se que a 1ª variável aponta para a segunda”.

Podemos destacar algumas razões para o uso de ponteiros.
1.	 Ponteiros são usados em situações em que a passagem de argumentos valores é difícil ou ainda quando deseja-se retornar mais que uma informação para uma função;
2.	 Passar matrizes e strings de uma função para outra;
3.	 Para manipular matrizes (aritmética de ponteiros);
4.	 Para criar estruturas de dados mais complexas como: listas encadeadas e árvores binárias;
5.	 Para localização de memória livre  através da função malloc();
6.	 Para compilação mais eficiente do código => notação de ponteiros é mais rápida.

Operadores Associados a Ponteiros
	& - operador unário que devolve o endereço da memória do seu operando;
* - operador unário que devolve o conteúdo da variável localizada no endereço de memória do seu operando, que é uma variável ponteiro.

Ponteiros também tem tipos. Quando declaramos um ponteiro nós informamos ao compilador para que tipo de variável o ponteiro está apontando.
	Forma Geral :-
		tipo   *identificador;
Exemplo:-
			int *px,*py;
	Para atribuir valores as variáveis ponteiro e para acessar as informações usamos:-
		*px=3;
		*py=5;
Na declaração, o símbolo * indica o tipo apontado (o ponteiro) em outras situações indica o conteúdo da variável apontada.
O ponteiro deve ser inicializado (apontado para algum lugar conhecido) antes de ser usado.
Ponteiros são sempre inicializados com o valor 0 ou NULL  então antes de usá-los devemos atribuir algum endereço válido a eles, o que é feito pelas instruções:

		px=&x;
		py=&y;
	Exemplo:
		int x=5,y=6;
		int *px,*py;
		px=&x;
		py=&y;
		printf(“px=%p,  *px=%d,  &px=%p\n”, px,*px,&px);
		printf(“py=%p,  *py=%d,  &py=%p\n”, py,*py,&py);
	O resultado será:
		px=65488,  *px=5,  &px=65492
		py=65490,  *py=6,  &py=65494

OBS:- O formato %p no printf indica que vai ser exibido um endereço.
	Na memória:

  5

  6

		    X                    Y	
		555
                      65488              65490

65490

654888

                         px                    py
                                                                 
                     65492               65494    

	Onde: px => retorna o endereço para o qual o ponteiro aponta;
		&px => retorna o endereço do ponteiro;
		*px => retorna o conteúdo da variável apontada.
Podemos fazer algumas operações aritméticas com ponteiros. A primeira, e mais simples, é a de igualar dois ponteiros p1=p2, assim p1 aponta para o mesmo lugar que p2. Se quisermos que a variável apontada por p1 tenha o mesmo conteúdo da variável apontada por p2 devemos fazer *p1=*p2.
Outras operações com ponteiros também bastante usadas são o incremento e o decremento. Quando incrementamos um ponteiro ele passa a apontar para o próximo valor do mesmo tipo para o qual o ponteiro aponta (avança um número de bytes na memória) como por exemplo:

	int  *p;
         		p++;  // avança dois bytes na memória
		p--;   // decrementa dois bytes na memória

Para incrementar o conteúdo da variável apontada pelo ponteiro p temos:
                     	*p++;

Outras operações podem ser efetuadas com ponteiros como a adição e subtração de inteiros com ponteiros, bem como os operadores de (== , !=, >, <, >=,<=).

	Exemplos:

	p=p+15;    // desloca o ponteiro 15 posições;
	*(p+15);   // utiliza o conteúdo do ponteiro 15 posições adiante;
	p1>p2;     // compara qual dos dois ponteiros está mais adiante na memória.

Existem operações que não podem ser efetuadas com ponteiros, como por exemplo dividir ou multiplicar ponteiros.

Exemplos:-

#include <stdio.h>
void main()
{
   int num,valor;
int *p;
num=70;
p=&num;       // recebe o endereço de num
valor=*p;       // valor recebe o mesmo conteúdo de num
printf(“\n\n %d \n”,valor);
printf(“Endereço para onde o ponteiro aponta: %p \n”,p);
printf(“Valor da variável apontada: %d \n”,*p);
*p=100;               // modifica o conteúdo da variável num indiretamente
printf(“Valor da variável modificada %d \n”,*p);
}

PONTEIROS E MATRIZES

Uma das aplicações mais importantes com ponteiros e a varredura seqüencial de uma matriz, isto é, quando temos que percorrer todos os elementos de uma matriz de uma forma seqüencial, podemos usar um ponteiro incrementando-o até o final da matriz.
Em uma matriz o próprio nome da matriz é o endereço do primeiro elemento da matriz. Portanto, se x é uma matriz unidimensional, então, o endereço do primeiro elemento da matriz pode ser expresso &x[0] ou simplesmente x. Além disso o endereço do segundo elemento da matriz pode ser expresso por &x[1] ou  (x + 1), e assim por diante até o enésimo elemento da matriz &x[ i ] ou (x + i). Desta forma temos dois modos diferentes de acessar os elementos de uma matriz. A vantagem de se utilizar ponteiros é que o acesso é mais rápido.
Na expressão (x + i)  x representa o endereço e i representa uma quantidade inteira que significa i elementos depois do primeiro (deslocamento).
Como &x[ i ] e (x + i) representam o endereço do inésimo elemento de x, x[ i ] e *(x + i) representam o conteúdo desse endereço.
Exemplo:
#include <stdio.h>
#include <conio.h>
void main()
{ int x[10], i;
clrscr();
for (i=0;i<=9;i++)
   {
       scanf(“%d”,&x[i]);
       printf(\n i= %d  x[i]= %d   *(x+i) = %d &x[i] = %p  x+1 = %p”,i , x[i], *(x+i), &x[i], x+i);
  }
   getchar(); 
}
Resultado:-
i = 0    x[ i ]= 10    *(x+i) = 10       &x[ i ] = 72         x + i=72
i = 1    x[ i ]= 11    *(x+i) = 11       &x[ i ] = 74         x + i=74
i = 2    x[ i ]= 12    *(x+i) = 12       &x[ i ] = 76         x + i=76
i = 3    x[ i ]= 13    *(x+i) = 13       &x[ i ] = 78         x + i=78
i = 4    x[ i ]= 14    *(x+i) = 14       &x[ i ] = 7A         x + i=7A
......
Ponteiros associados a matrizes substituem com vantagem a indexação de matrizes sendo um processo conhecido com aritmética de ponteiros.

Exemplo1:-  Desenvolver um programa que dado um vetor de 10 elementos numéricos inteiros calcular um outro vetor que deverá conter os elementos do 1º vetor elevados ao quadrado. Usar aritmética de ponteiros.

#include <stdio.h>
#include <conio.h>
#include <math.h>   
void main()
{ 
    int vet1[10],vet2[10],x;
    clrscr();
    for(x=0;x<10;x++)
       { scanf("%d",(vet1+x));            // não precisa &
         *(vet2+x)=pow(*(vet1+x),2);
         printf("%d\n",*(vet2+x));
       }
       getchar();
  }

OU

 void main()
   {  
      int vet1[10],vet2[10],x,*pt;
      clrscr();
      pt=vet1;                     // não precisa & porque o nome de uma matriz é um ponteiro
      for(x=0;x<10;x++)
           { scanf("%d",(pt+x));        
              *(vet2+x) = pow (*(pt+x),2);
              printf("%d\n",*(vet2+x);}   
  getchar();
  }
  
Exemplo2:- Dados dois vetores numéricos de 5 elementos cada desenvolver um programa utilizando aritmética de ponteiros que compare os elementos desses vetores.

#include <stdio.h>
#include <conio.h>
void main()
{  float x[5],y[5],i;
   clrscr();
    for (i=0;i<5;i++)
     {  scanf(“%f”, x+1);
        scanf(“%f”, y+1);
        if (*(x+i) < *(y+i)) printf(“%f é o menor”,*(x+i));
        else if (*(x+i) == *(y+i)) printf(“%f e  %f são iguais”,*(x+i),*(y+i));
       else printf(“%f é o maior”, *(y+i));
     }
  getchar();
}
3. Estruturas, Uniões, Tipos Definidos e Enumerações

A Linguagem “C” permite que se crie vários tipos diferentes de dados que possam ser agrupados de formas  definidas. Essas formas são um tipo de dado definido pelo programador  e são conhecidas como: estruturas e uniões.
ESTRUTURA
Uma estrutura é uma coleção de tipos diferentes referenciadas por um nome, isto é, a estrutura é uma forma de se ter informações agrupadas.
	Forma Geral:
				struct  nome {
					tipo nome_da_variável;
					tipo nome_da_variável;     elem. da estrutura
					....
				} variáveis da estrutura;
OBS:- A struct é um tipo de dado, não existe um espaço reservado na memória para ela até que seja declarada uma variável para armazenar o tipo definido.
	Exemplo:- 		struct veículo {
					char modelo[25];
					char marca[15];
					float custo;
				};  			/* leva ; */
				 veículo carro; 
	onde: veículo é o nome da estrutura e carro é o nome da variável que tem o tipo de estrutura veículo.
Outra forma de declarar uma estrutura pode ser:-
	struct  veículo {
		char modelo[25];
		char marca[15];
		float custo;
	} carro; 
 /* é possível combinar as duas declarações. */
Se tivermos duas ou mais variáveis que são do mesmo tipo de estrutura podemos:
		struct xy {
			int x;
			float y;
		} a,b; 
/* onde a e b são duas variáveis do mesmo tipo; 
Para referenciar cada elemento da estrutura utiliza-se o operador ponto.
		Forma Geral:- nome_da_variávelnome_do_elemento;
		Exemplo:-
			a . x =10;   b . x =5;
			a . y =2.5;  b . y = 0.5;
			gets(carro.modelo);
			scanf(“%f”,&carro.custo);
É possível também ter-se uma matriz de estruturas. Exemplos:
	struct veículo {
		char modelo[20];
		char marca[15];
		float custo;
	} carro[100]; 
/* isto cria 100 conjuntos de variáveis que estão organizadas com os elementos acima */.
Para referenciar cada elemento da estrutura utiliza-se:
		gets(carro[0].marca);
	gets(carro[0].modelo);
		scanf(“%f”, &carro[0].custo);
	....
Para simplificar esta estrutura poderíamos ter:-
	for (x=0;x<100;x++)
 	{	gets(carro[x].marca);
		gets(carro[x].modelo);
	scanf(“%f”, &carro[x].custo);   }
UNIÃO
São estruturas que possuem vários tipos diferentes de dados. Em uma “union“ os elementos  compartilham a mesma área de memória, enquanto em uma “struct” cada elemento tem sua própria área de memória. Assim as uniões são utilizadas com a finalidade de economizar memória. Em uma união o compilador se encarrega de contabilizar a memória necessária para armazenar os membros.
	Forma Geral:-
		union  nome {
			tipo nome_da_variável;
			tipo nome_da_variável;
			....
		} variáveis_da_união; 
	Exemplo:-
		union modelo {
			char cor[12];
			int tamanho;
		} calça,camisa;

Cada uma dessas variáveis calça e camisa podem representar uma string de [12] caracteres e um número inteiro em um determinado momento do programa.
Para acessar um elemento de uma união  utiliza-se a mesma sintaxe que é utilizada para estrutura.
OBS:- Uniões são usadas freqüentemente quando são necessárias conversões de tipos diferentes;

ENUMERAÇÕES
É um conjunto de constantes inteiras que especifica todos os valores legais que uma variável desse tipo pode ter.
	Forma Geral:-
			enum nome {lista de enemeração} lista_de_variáveis;

OBS:- o nome e a lista de variáveis é opcional.
As enumerações são análogas as estruturas. Cada símbolo representa um valor inteiro. Pode ser usado em qualquer lugar em que um inteiro pode ser usado. O valor do 1º símbolo da enumeração é 0. A cada símbolo o inteiro é incrementado. 
	Exemplo:-	enum semana {Segunda=2, terça, quarta,quinta,sexta};
			semana u;
		u=quinta;
		printf(“%i”,u);
/* o resultado do printf será o número 5 porque quinta é o quarto valor da lista, que começa no número 2. O default é começar no zero.
É possível especificar o valor de um ou + símbolos usando um inicializador. Isto é, colocando-se um sinal de igual e um valor inteiro após o símbolo. 
	Exemplo:- 	enum moeda {dolar=1,iene,lira,libra};
Neste caso os valores dos símbolos serão: dolar=1; iene=2;lira=3;libra=4;
Uma suposição comum, porém errônea, sobre enumerações é que os símbolos podem ser enviados e recebidos da entrada de dados. Isto não acontece.
	Exemplo:-    	moeda=dolar;
			Printf(“%d”,moeda);
OBS:- Dolar é simplismente um nome para um inteiro,não uma string.
Uma enumeração é freqüentemente usada para definir uma tabela de símbolos de um compilador, por exemplo.

TIPOS DEFINIDOS PELO USUÁRIO

O usuário ainda pode definir um novo nome para o tipo de dado que ele deseja declarar. Essa forma de declaração sugere a mesma finalidade da estrutura, mas são freqüentemente utilizados para tornar os programas mais portáteis e também para documentação e padronização permitindo nomes mais definidos.
	Forma Geral : -   	typedef  tipo novo_tipo;
	Exemplo1:- 		typedef int idade;
				idade homem,mulher;
	Onde: homem e mulher são duas variáveis equivalentes do tipo inteiro.
	Exemplo2:-		typedef struct {
					int a;
					float b;
				} num;
				num   x;
	Onde: x possue dois elementos x.a do tipo inteiro e x.b do tipo ponto flutuante.
O recurso do typedef pode ser usado repetidamente para padronizar um tipo de dado em relação aos outros tipos.
	Exemplo:-	typedef struct {
				int dia;
				int mês;
				int anos;
			} data;
		data dat;
.....
no programa: 	dat.dia=10;   dat.mês=12;   dat.ano=1998;

Exemplos de programas utilizando os comando dados:

Exemplo1: O programa abaixo contem uma estrutura que armazena o número da conta e o saldo de 5 clientes. O programa calcula o saldo médio dos 5 clientes e exibe na tela quais os clientes que possuem saldo acima ou igual a média. 

#include <stdio.h>
#include <conio.h>

void main()
{
   struct cliente
   {  char conta[20];
      float saldo;
   };
   cliente cli[5];
   float saldo_medio=0,aux;
   int x;

   for (x=0;x<5;x++)
   {
	   clrscr();
	   printf("\t\t\t CONTROLE BANCARIO \n");
	   printf("\t Nr da Conta.........: ");gets(cli[x].conta);
	   printf("\t Saldo ..............: ");scanf("%f",&aux);
	   cli[x].saldo=aux;
	   saldo_medio += cli[x].saldo;
	   getchar();
   }
   saldo_medio=saldo_medio/5;
   clrscr();
   printf("\t\t CLIENTES COM SALDO ACIMA DA MEDIA \n\n\n");
   printf("\t Nr da conta \t Saldo \n\n");
   for (x=0;x<5;x++)
   {  if (cli[x].saldo >=saldo_medio)
       printf("\t %s  \t\t %8.2f \n", cli[x].conta,cli[x].saldo);
   }
   getchar();
}

Exemplo2:- O programa abaixo contem uma união para armazenar o ano de nascimento e a idade de um aluno e uma estrutura que armazena o ra, o nome e a idade do aluno. O programa lê os dados calcula e exibe a idade utilizando as estruturas de armazenamento.

#include <stdio.h>
#include <conio.h>
#include <dos.h>
void main()
{
   union id
   {  int ano_nas;
      int i;
   };

   struct classe
   {  char ra[10];
      char nome[20];
      id idade;
   }aluno;

   struct time t;
   struct date d;

	   clrscr();
	   gettime(&t);
	   getdate(&d);
	   printf("Data :%02d/%02d/%4d\n", d.da_day,d.da_mon,d.da_year);
	   printf("Hora: %2d:%2d:%2d\n", t.ti_hour,t.ti_min,t.ti_sec);
	   printf("\t\t\t CONTROLE DE ALUNOS \n\n\n");
	   printf("\t Registro Academico.....: ");gets(aluno.ra);
	   printf("\t Nome...................: ");gets(aluno.nome);
	   printf("\t Ano de Nascimento......: ");scanf("%d",&aluno.idade.ano_nas);
	   aluno.idade.i= d.da_year - aluno.idade.ano_nas;
	   printf("\t Idade..................: %d",aluno.idade.i);
	   getchar();getchar();
}

Exemplo3:- O programa abaixo lê o nome de uma pessoa, o valor e o tipo de moeda e faz a conversão utilizando tipo definido e tipo enumerado.

#include <stdio.h>
#include <conio.h>
#include <dos.h>
void main()
{
   typedef char string;
   typedef float real;
   string nome[30];
   real valor,valor_conv;
   enum moeda {dolar=1,franco,libra};
   moeda x;

	   clrscr();
	   printf("\t\t\t CAMBIO \n\n\n");
	   printf("\t Nome...................: ");gets(nome);
	   printf("\t Valor..................: ");scanf("%f",&valor);
	   printf("\t 1. Dolar \n");
	   printf("\t 2. Franco \n");
	   printf("\t 3. Libra \n\n");
	   printf("\t\t OPCAO <1-3> ");scanf("%d",&x);
	   switch (x) {
	    case 1:valor_conv=valor/1.12; printf("\t Valor Convertido %10.2f  em dolar",valor_conv); break;
	    case franco:valor_conv=valor/1.473; printf("\t Valor Convertido %10.2f  em franco",valor_conv);break;
	    case libra:valor_conv=valor/1.101; printf("\t Valor Convertido %10.2f em libra",valor_conv);break;
	    default: printf("\tMoeda Invalida !!");
	    }
	    getchar();getchar();
   }

Exemplo4:- O exemplo abaixo lê as informações de um cliente como: nome, número da conta, tipo e saldo e armazena em uma estrutura. As informações da estrutura são enviadas para uma função que calcula um reajuste no saldo dependendo do tipo de conta do cliente.

#include <stdio.h>
#include <conio.h>
struct teste{
	char nome[20];
	char numcont[15];
	char tipo;
	float saldo;
};
void ajuste (teste *cliente);

void main()
{  teste pess;
   int i;
   float sal;
   clrscr();
   printf("Nome....: \n");gets(pess.nome);
   printf("Numero Conta...:\n");gets(pess.numcont);
   printf("Tipo da Conta..:\n");scanf("%c",&pess.tipo);
   printf("Saldo..........:\n");scanf("%f",&sal);
   pess.saldo=sal;  
   ajuste(&pess);
   printf("Novo Saldo.....:%8.2f\n",pess.saldo);
   getchar();getchar();
}

void ajuste(teste *cliente)
{
   if (cliente->tipo=='P') cliente->saldo = cliente->saldo*1.10;          
		else   cliente->saldo=cliente->saldo*1.05;
}
OBS:- para utilizar os elementos da estrutura é necessário usar o operador  seta (->).

Exemplo5:- Outra forma  de resolver o mesmo exercício.

#include <stdio.h>
#include <conio.h>
struct teste{
	char nome[20];
	char numcont[15];
	char tipo;
	float saldo;
};
void ajuste (char tipo,float *vl);

void main()
{  teste pess;
   int i;
   float sal;
   clrscr();
   printf("Nome....: \n");gets(pess.nome);
   printf("Numero Conta...:\n");gets(pess.numcont);
   printf("Tipo da Conta..:\n");scanf("%c",&pess.tipo);
   printf("Saldo..........:\n");scanf("%f",&sal);
   pess.saldo=sal;
   ajuste(pess.tipo,&pess.saldo);
   printf("Novo Saldo.....:%8.2f\n",pess.saldo);
   getchar();getchar();
}
void ajuste(char tipo,float *vl)
{
   if (tipo=='P') *vl = *vl * 1.10;
		else   *vl=*vl * 1.05;
}

Exemplo6:- O mesmo exercício anterior  usando uma matriz de estruturas.

#include <stdio.h>
#include <conio.h>
struct teste{
	char nome[20];
	char numcont[15];
	char tipo;
	float saldo;
};
void ajuste (teste cliente[5]);

void main()
{  teste pess[5];
   int x;
   float sal;
   clrscr();
   for (x=0;x<5;x++)
   {
   printf("Nome....: \n");gets(pess[x].nome);
   printf("Numero Conta...:\n");gets(pess[x].numcont);
   printf("Tipo da Conta..:\n");scanf("%c",&pess[x].tipo);
   printf("Saldo..........:\n");scanf("%f",&sal);
   pess[x].saldo=sal; getchar();
   }
  ajuste(pess);
   for (x=0;x<5;x++)
   {
     printf("Novo Saldo.....:%8.2f\n",pess[x].saldo);}
  // as informacoes serao modificadas na variavel real
   getchar();getchar();
}
void ajuste(teste cliente[5])
{  int x;
  for (x=0;x<5;x++)
  {
   if (cliente[x].tipo=='P') cliente[x].saldo = cliente[x].saldo*1.10;
		else   cliente[x].saldo=cliente[x].saldo*1.05;

   }
}

4.	ARQUIVOS 

Quando desenvolvemos programas de computadores é muito comum precisarmos “guardar” dados para posterior recuperação. A  recuperação dos dados pode ser alguns minutos depois, dias depois, ou até mesmo anos depois do armazenamento inicial. Sendo assim  dados que precisam ser guardados por um tempo indeterminado ficam armazenados em arquivos.

Até o momento somente trabalhamos com o conceito de dados armazenados de forma temporária (em memória principal). Quando desejamos armazenar dados por um período de tempo indeterminado, podendo reutilizá-los, modificá-los e ou continuar a armazenar mais dados utilizamos arquivos. 

ARQUIVO :- É um conjunto de registros logicamente organizados armazenados em um dispositivo de memória secundária (disco rígido, disquetes, fitas magnéticas, cd, etc), onde cada registro compreende um conjunto de  informações denominadas campos. Em um arquivo é possível armazenar um volume grande de dados.

ARQUIVO

REGISTRO

CAMPO

Um arquivo é formado por um ou mais registros, que por sua vez,  como já sabemos, é formado por um conjunto de campos. 

O sistema de E/S em “C” fornece uma interface que permite a utilização de qualquer dispositivo real de armazenamento (console, disco rígido, disco flexível, fita magnética, etc). Embora cada um dos dispositivos seja muito diferente, o sistema de E/S  os transforma em um dispositivo lógico independente, chamado de stream. Isto significa que a mesma função, pode escrever em um arquivo em disco ou em um outro dispositivo qualquer. Sendo assim na abertura do arquivo é necessário informar a associação da stream com o dispositivo específico de armazenamento.

Para que um programa em “C” possa ler e gravar dados em um arquivo podemos utilizar várias maneiras. A linguagem “C” divide as categorias de acesso a disco em dois grupos chamados alto nível, ou leitura e gravação bufferizada e de baixo nível, ou leitura e gravação não bufferizada. Neste curso iremos estudar a categoria do grupo de alto nível por possuir algumas vantagens sobre a de baixo nível, entre elas: a facilidade para ler e gravar qualquer tipo de dado e a portabilidade, seguindo padrões definidos pela ANSI, o  que não ocorre com o grupo de baixo nível. Outra vantagem da categoria de alto nível é poder contar com a utilização de várias funções de biblioteca para leitura e gravação de dados no arquivo, como por exemplo: dados lidos e escritos um caracter por vez;  dados lidos e escritos como strings;  dados lidos e escritos de modo formatado; dados lidos e escritos num formato chamado registro. A forma mais comum é  armazenar as informações em registros, isto é estruturas, para posteriormente serem gravadas no arquivo.

Além das duas categorias de acesso ao disco anteriormente discutidas na linguagem de programação “C” é possível classificar os arquivos conforme a forma como eles são abertos: em modo texto ou em modo binário. 
Um arquivo aberto em modo texto é interpretado em “C” como sendo uma seqüência de caracteres agrupados em linhas que devem ser separadas por um caracter de nova linha, as informações numéricas também são armazenadas em cadeias de caracteres, enquanto que, no modo binário tudo é muito mais simples. Não há necessidade de nenhuma conversão de tipos. Para os tipos numéricos  na forma binária eles são armazenados como estão na memória, nem mesmo a indicação de final de arquivo é necessária pois acaba sendo interpretada automaticamente. Sendo assim estaremos utilizando leitura e gravação em alto nível com modo de acesso binário.

Por ser o arquivo uma unidade separada, o que o torna independente, pode ser criado, consultado e alterado por programas distintos, sendo uma estrutura fora do ambiente do programa. O número máximo de arquivos que podem ser abertos simultaneamente por um programa depende das considerações tomadas no projeto do compilador e das restrições do S.O. que geralmente é superior a 8 arquivos. Para isso é necessário que seja informado ao S.O. quem é o arquivo, onde as informações serão lidas e ou gravadas. 

OPERAÇÕES BÁSICAS COM ARQUIVO
Para utilizarmos a estrutura de dados do tipo arquivo fazemos o uso de operações básicas como: abrir, fechar, apagar, copiar e renomear.

ABRIR O ARQUIVO:-  Para podermos utilizar as informações contidas no arquivo ou para guardá-las nesse arquivo devemos primeiramente abrir o arquivo:
Quando solicitamos a abertura de um arquivo é necessária a declaração de uma estrutura do tipo FILE  que receberá um ponteiro para o arquivo que está sendo aberto. Para que o S.O. possa abrir o arquivo três informações devem ser fornecidas: o nome do arquivo,  o tipo de abertura  (se o arquivo está sendo lido ou gravado) e onde guardar as informações sobre o arquivo. Isso tudo é possível com a função fopen() que se encarrega de: preencher a estrutura FILE com as informações necessárias. O resultado dessa função será  retornar um ponteiro do tipo FILE que aponta para a localização na memória da estrutura FILE.

Nome do arquivo e tipo de abertura

Esta operação ocorre da seguinte forma:

S.O .

DISCO

PROGRAMA EM “C”

Ponteiro para a estrutura FILE

Forma Geral:-	struct nome_da_estrutura
				{      tipo  nome1;
				       tipo  nome2;
				};
			FILE *ponteiro;
			ponteiro=fopen(“D:nome.ext”,”modo”);

Os arquivos podem ser utilizados de vários modos diferentes conforme descrito na tabela abaixo:
MODO	SIGNIFICADO	
r	Abre um  arquivo texto para leitura. O arquivo deve existir.	
w	Cria um arquivo texto para escrita. Se o arquivo exitir será recriado por cima caso não exista será criado.	
a	Abre um arquivo texto para gravação.Se o arquivo existir os dados serão anexados no final do arquivo se não existir será criado um novo.	
r+	Abrir um arquivo texto para leitura e gravação. O arquivo tem que existir.	
w+	Abre um arquivo texto para leitura e gravação. Se o arquivo existir será recriado por cima. Se não existir será criado.	
a+	Abre um arquivo texto para atualização e para adicionar dados no fim do arquivo se ele existir se não cria-se um novo arquivo	
rb	Abre um arquivo binário para leitura. O arquivo deve existir.	
wb	Cria um arquivo binário para escrita. Se o arquivo exitir será recriado por cima caso não exista será criado.	
ab	Abre um arquivo binário para gravação.Se o arquivo existir os dados serão anexados no final do arquivo se não existir será criado um novo.	
rb+	Abre um arquivo binário para leitura e gravação. O arquivo deve existir e pode ser atualizado.	
wb+	Abrir um arquivo binário para leitura e gravação. Se o arquivo existir ele será destruído e reinicializado. Se não existir será criado.	
ab+	Abrir um arquivo binário para atualização e para adicionar dados ao fim do arquivo existente ou um novo arquivo será criado.	
	
Exemplo:
		struct aluno
		{ char ra[9];
		 char nome[20];
		 float media;
		};
		FILE *ARQ;
		ARQ=fopen (“A:curso.dat”,”ab+”);

Depois de estabelecer a linha de comunicação com o arquivo e o S.O. o próximo passo será ler ou gravar informações nesse arquivo.

FECHAR ARQUIVO:- Todo arquivo aberto deverá ser fechado para garantir a integridade dos dados armazenados, caso isso não ocorra  poderá haver perda de informações. A função para fechar um arquivo é fclose().
	Forma Geral:
fclose(ponteiro);
	onde: ponteiro é o nome da variável ponteiro da estrutura FILE.

APAGAR ARQUIVO:- Deleta um arquivo existente. Todo arquivo antes de ser apagado deve ser fechado.
	Forma Geral:
		remove(nome físico do arquivo);
	onde: nome dado ao arquivo de dados.
Esta função devolve zero caso seja bem sucedida e um valor diferente de zero caso contrário.
 	
RENOMEAR ARQUIVO:-  Permite mudar o nome do arquivo existente para um outro nome diferente. Antes de renomear o arquivo deve ser fechado.
Forma Geral:
		rename(nome físico do arquivo,novo nome físico do arquivo);
	onde: Nome dado ao arquivo de dados e  o novo nome que será dado
O comando rename() retorna zero se a operação ocorreu com sucesso.

OPERAÇÕES BÁSICAS COM REGISTRO DE UM ARQUIVO

Quando já temos um arquivo aberto, podemos tanto ler os registros já armazenados no arquivo como escrever (gravar) novos registros no arquivo.

LER REGISTRO DO ARQUIVO:-  quando lemos um registro de um arquivo estamos transferindo os dados do registro do arquivo, armazenados em memória secundária, para a memória principal do computador (memória RAM). Para isto utilizamos a seguinte instrução:
	Forma Geral:
		fread(&estrutura,sizeof(estrutura),1,ponteiro);
	Onde: &estrutura - é o endereço na memória onde os dados serão lidos;
		sizeof(estrutura) – operador que retorna o tamanho da estrutura;
		1: quantidade de estruturas a ser lida (normalmente 1);
 		ponteiro: o nome do ponteiro da estrutura FILE.
Normalmente a função fread() retorna o número de registros lidos, que deve ser igual ao terceiro argumento que é igual a 1. Se for final de arquivo o número que irá retornar será zero.
ESCREVER UM REGISTRO NO ARQUIVO (GRAVAR) :-  quando escrevemos (gravamos) um registro num arquivo, estamos transferindo os dados do registro, armazenados em memória principal, para a memória secundária  do computador (disquete, disco rígido, CD, etc). Utilizamos a seguinte instrução:
	Forma Geral:
		fwrite(&estrutura,sizeof(estrutura),1,ponteiro);
Onde:&estrutura-é o endereço na memória onde os dados serão armazenados;
	sizeof(estrutura) – operador que retorna o tamanho da estrutura;
		1: quantidade de estruturas a ser  gravada (normalmente 1);
	ponteiro: o nome do ponteiro da estrutura FILE.
 
ORGANIZAÇÃO DE ARQUIVOS

As operações realizadas com  registros em  uma estrutura de dados do tipo  arquivo podem ser resumidas em: inserção de um novo registro (inclusão), obtenção de um registro do arquivo (consulta), modificação dos dados armazenados no arquivo (alteração) ou remoção de um registro do arquivo (exclusão). Dependendo do tipo de problema estas operações poderão ocorrer em maior ou menor escala.

Neste caso é necessário que seja analisada qual é  a melhor forma de acessar esses  registros. Basicamente existem  duas formas  diferentes de acesso aos registros de um arquivo: o acesso seqüencial e o acesso direto (também conhecido como randômico). Existem outras formas de acesso que são   variações destas que não serão tratadas.

Acesso Seqüencial:  Quando desejamos ter acesso aos dados de um determinado registro mas não sabemos a localização desse registro no arquivo devemos vasculhar o arquivo desde o início  em busca  do registro desejado até o final do arquivo se necessário. Esta operação deverá ser repetida seqüencialmente, isto é, avançando pelos registros armazenados até que se encontre o registro procurado. Isto significa que para acessar um registro específico precisamos obedecer a ordem com que os registros foram armazenados no arquivo, o que implica em percorrer todos os registro que o antecedem.

Acesso Direto ou Randômico: Neste caso para acessarmos o registro desejado é necessário que saibamos a sua posição física (posição do registro no arquivo no instante da gravação). Dessa forma é possível se posicionar instantaneamente no registro desejado sem ter que percorrer todos os registros que o antecedem. Para isto, é necessário conhecer o  número da posição física do registro dentro do arquivo. A posição física de um registro é um número único, pois nunca dois registros diferentes poderão ter a mesma localização.

A seguir serão listados alguns comandos que permitem a manipulação dos registros nos arquivos de acesso seqüencial e direto.
 
COMANDOS E FUNÇÕES PARA MANIPULAÇÃO DE REGISTROS
Para posicionar o ponteiro de arquivo para o registro desejado temos:
	Forma Geral:
		fseek(ponteiro,sizeof(estrutura),deslocamento);
Onde: ponteiro: é o  nome do ponteiro da estrutura FILE.
	sizeof(estrutura) – operador que retorna o tamanho da estrutura;
		deslocamento: posição especificada para o ponteiro do arquivo;
O último argumento (do deslocamento) também é chamado de modo e pode utilizar três possibilidades de acordo com a tabela abaixo, para determinar de onde o tamanho do registro começará a ser medido:
DESCRIÇÃO	
Pode ser uma macro	MODO
Pode ser um número	
Começo do arquivo	SEEK_SET	0	
Posição corrente do ponteiro	SEEK_CUR	1	
Final do arquivo	SEEK_END	2	

Para indicar o final do arquivo usamos a função feof( ) que retorna um número inteiro enviado pelo S.O que indica final de arquivo.
	Forma Geral:
			feof(ponteiro);
	Onde: ponteiro é o nome da variável do tipo FILE;
No DOS a função feof() retorna –1 caso seja final de arquivo e 0 caso contrário.
	Exemplo:
		while ( !feof(ponteiro))
			fread(&estrutura,sizeof(estrutura),1,ponteiro);

Para posicionar o ponteiro de arquivo no início do arquivo, isto é, no 1º registro temos:
	Forma Geral:
			rewind(ponteiro);
	Onde: Ponteiro é o nome da variável do tipo FILE.

A função ftell()  retorna um número inteiro longo que representa o número de bytes do começo do arquivo até a posição atual. 
	Forma Geral:
		ftell(ponteiro);
	Onde: Ponteiro é o nome da variável do tipo FILE.
Se o número que retornou dessa função for dividido pelo tamanho da estrutura teremos o número da posição física do registro.

Exemplo: O programa abaixo faz a inclusão, consulta (por acesso seqüencial e acesso direto), a alteração, a exclusão e a reorganização de um arquivo que contem o modelo, a marca e o preço de um veículo.
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

struct veiculo {
   char modelo[20];
   char marca[20];
   float  preco;
};

FILE *parq;  //variavel ponteiro de arquivo
veiculo reg;

void menu();
void abre_arquivo1();
void abre_arquivo2();
void inclusao();
void consulta_s();
void consulta_d();
void alteracao();
void exclusao();
void reorganizar();
void tela1();
void tela2();
char resposta();

void main()
{
  abre_arquivo1();
  menu();
  fclose(parq);
}
/********************ABERTURA DE ARQUIVO***********************/;

void abre_arquivo1()  // abertura para inclusao
{
  parq=fopen("b:t3.dad","ab+");       //devolve o ponteiro do arquivo
  if (parq==NULL)
  { printf("Ocorreu um erro o arquivo nao pode ser aberto\n");
    delay(1000);
    exit(1);     //volta para o editor do turbo C ou para o S.O.
  }
}
void abre_arquivo2()  //abertura para alteracao e exclusao
{
  parq=fopen("b:t3.dad","rb+");       //devolve o ponteiro do arquivo
  if (parq==NULL)
  { printf("Ocorreu um erro o arquivo nao pode ser aberto\n");
    delay(1000);
    exit(1);     //volta para o editor do turbo C ou para o S.O.
  }
}

/**************************MENU**********************/;
void menu()
{ int op;
do{
   clrscr();
   gotoxy(20,2);printf("<<< M E N U    D E   O P C O E S >>>");
   gotoxy(30,6);printf("1 - INCLUSAO ");
   gotoxy(30,8);printf("2 - CONSULTA SEQUENCIAL");
   gotoxy(30,10);printf("3 - CONSULTA DIRETA");
   gotoxy(30,12);printf("4 - ALTERACAO");
   gotoxy(30,14);printf("5 - EXCLUSAO");
   gotoxy(30,16);printf("6 - FIM ");
   gotoxy(25,18);printf("Digite a opcao <1-6> ?");
   do
   { gotoxy(47,18);clreol();scanf("%d",&op);
   } while (op<1 || op>6);
   if (op!=6)
    {
     switch (op)
      {  case 1:inclusao();break;
	 case 2:consulta_s();break;
	 case 3:consulta_d();break;
	 case 4:alteracao();break;
	 case 5:exclusao();break;
      }
    }
}while (op!=6);
}

/**************************INCLUSAO**********************/;

void inclusao()
{ char op;
  int x;
  long N;
  fseek(parq,sizeof(reg),SEEK_END);
  N=(ftell(parq)/sizeof(reg)-1); //-1 porque comecou do zero
 do {

   tela1();
   getchar();
   gotoxy(10,6);printf("O NéMERO DO REGISTRO : %ld",N);
   gotoxy(40,8);gets(reg.modelo);
   gotoxy(40,10);gets(reg.marca);
   gotoxy(40,12);scanf("%f",&reg.preco);
   fseek(parq,N*sizeof(reg),SEEK_CUR);
   fwrite(&reg,sizeof(reg),1,parq);
   op=resposta();    //chamada a uma funcao resposta
   N++;
 }while(op!='N');

}

/**************************CONSULTA ACESSO SEQUENCIAL****************/;

void consulta_s()
{ int num,lin=8;
  tela2();
  rewind(parq);  // posiciona no inicio do arquivo
  fread(&reg,sizeof(reg),1,parq);
  while (!feof(parq))
  {
   gotoxy(10,lin);printf("%s",reg.modelo);
   gotoxy(40,lin);printf("%s",reg.marca);
   gotoxy(60,lin);printf("%10.2f",reg.preco);
   fread(&reg,sizeof(reg),1,parq);
   lin++;
   }
   getch();
}

/**************************CONSULTA ACESSO DIRETO*****************/;
void consulta_d()
{ int num;
  long tam;

  char op;
  fseek(parq,sizeof(reg),SEEK_END);
  tam=(ftell(parq)/sizeof(reg))-2; // -2 porque come‡a do zero e o SEEK_END da o n£mero do proximo registro
 do{
  tela1();
  gotoxy(10,6);printf("QUAL REGISTRO DESEJA CONSULTAR ?");
  do{
    gotoxy(45,6);clreol();scanf("%d",&num);
    }while (num<0 || num>tam);
  fseek(parq,num*sizeof(reg),SEEK_SET);
  fread(&reg,sizeof(reg),1,parq);
  gotoxy(40,8);printf("%s",reg.modelo);
  gotoxy(40,10);printf("%s",reg.marca);
  gotoxy(40,12);printf("%10.2f",reg.preco);
  op=resposta();
 }while(op!='N');
}

/**************************ALTERACAO ACESSO DIRETO******************/;

void alteracao()
{ int num;
  long tam;
  char op, resp[20]="";
  fclose(parq);
  abre_arquivo2();
  fseek(parq,sizeof(reg),SEEK_END);
  tam=(ftell(parq)/sizeof(reg))-2;

 do{
  tela1();
  gotoxy(10,6);printf("QUAL REGISTRO DESEJA ALTERAR ?");
  do{
    gotoxy(45,6);clreol();scanf("%d",&num);
    }while (num<0 || num>tam);
  fseek(parq,num*sizeof(reg),SEEK_SET);
  fread(&reg,sizeof(reg),1,parq);
  gotoxy(40,8);printf("%s",reg.modelo);
  gotoxy(40,10);printf("%s",reg.marca);
  gotoxy(40,12);printf("%10.2f",reg.preco);
  getchar();
  gotoxy(40,8);gets(resp);  //variavel para receber a alteracao
  if (strcmp(resp,"") !=0)
     {  strcpy(reg.modelo,resp);
	gotoxy(40,8);clreol();printf("%s",reg.modelo);
     }
  gotoxy(40,10);gets(resp);
  if (strcmp(resp,"") !=0)
     {  strcpy(reg.marca,resp);
	gotoxy(40,10);clreol();printf("%s",reg.marca);
     }
  do{
  gotoxy(40,12);gets(resp);
  if (strcmp(resp,"") !=0)
    { reg.preco=atof(resp);  //conversao de uma string em um float
      gotoxy(40,12);clreol();printf("%8.2f",reg.preco);
    }
    }while (reg.preco <=0);
  fseek(parq,num*sizeof(reg),SEEK_SET);
  fwrite(&reg,sizeof(reg),1,parq);
  op=resposta();
 }while(op!='N');
 fclose(parq);
 abre_arquivo1();
}

/**************************EXCLUSAO LOGICA - ACESSO DIRETO**********/;

void exclusao()
{ int num,cont=0;
  long tam;
  char op;

  fclose(parq);
  abre_arquivo2();
  fseek(parq,sizeof(reg),SEEK_END);
  tam=(ftell(parq)/sizeof(reg))-2;
 do{
  tela1();
  gotoxy(10,6);printf("QUAL REGISTRO DESEJA CONSULTAR ?");
  do{
    gotoxy(45,6);clreol();scanf("%d",&num);
    }while (num<0 || num>tam);
  fseek(parq,num*sizeof(reg),SEEK_SET);
  fread(&reg,sizeof(reg),1,parq);
  if (strcmp(reg.modelo,"***") == 0)
   { gotoxy(20,22);printf("Registro ja excluido !!");
     delay(1000);
   }
   else
    {
     gotoxy(40,8);printf("%s",reg.modelo);
     gotoxy(40,10);printf("%s",reg.marca);
     gotoxy(40,12);printf("%10.2f",reg.preco);
     gotoxy(40,19);printf("Confirma Exclusao ?");
     op=resposta();
     if (op=='S')
      {  strcpy(reg.modelo,"***");
	 fseek(parq,num*sizeof(reg),SEEK_SET);
	 fwrite(&reg,sizeof(reg),1,parq);
	 cont++;
	 gotoxy(40,19);printf("Registro Excluido !!");delay(1000);
      }
     }
  gotoxy(40,19);clreol();
  op=resposta();
 }while(op!='N');
  fclose(parq);
  abre_arquivo1();
  //********************* reorganizar - exclusao fisica *****************
  if (cont > 0) reorganizar(); // so reorganiza se tiver registros excluidos
}

void reorganizar()
{
  FILE *parq2;
  parq2=fopen("b:t3.bak","wb+");   //devolve o ponteiro do arquivo
  fclose(parq);
  abre_arquivo2();
  rewind(parq);
  while (! feof(parq))
    {
      if (fread(&reg,sizeof(reg),1,parq) >=1) // retorna 1 quando leu registro e 0 casocontrario
       if (strcmp(reg.modelo,"***") !=0)
	     fwrite(&reg,sizeof(reg),1,parq2);
    }
  fclose(parq);
  fclose(parq2);
  remove("b:t3.dad");
  rename("b:t3.bak","b:t3.dad");
  abre_arquivo1();
  }

/**************************TELAS**********************/;
void tela2()
{
  clrscr();
  gotoxy(30,3); printf("CADASTRO DE VEICULOS ");
  gotoxy(10,5);printf("MODELO \t\t\t MARCA \t\t\t  PRECO R$\n");
}

void tela1()
{
  clrscr();
  gotoxy(40,2);printf("CADASTRO DE VEICULOS");
  gotoxy(10,8);printf(" MODELO............: ");
  gotoxy(10,10);printf(" MARCA.............: ");
  gotoxy(10,12);printf(" PRECO.............: R$");
}

/**************************FUNCAO RESPOSTA**********************/;
char resposta()
{  char op;
   gotoxy(40,20);printf("Deseja Continuar <S/N> ?");
   do{
     gotoxy(65,20);clreol();scanf("%c",&op);
     op=toupper(op);
   }while (op!='N' && op !='S');
   return(op);
}