©1999 - Adriano Joaquim de Oliveira Cruz

Entrada e Saída de Dados por Arquivos

----------------------------------
  1. Introdução
  2. Fluxos de Dados e Arquivos
    1. Fluxo de Texto
    2. Fluxo Binário
    3. Arquivos
  3. Funções de Entrada e Saída
  4. Início e Fim
    1. Abrindo um Arquivo
    2. Fechando um Arquivo
    3. Fim de Arquivo
    4. Volta ao Início
  5. Lendo e Escrevendo Caracteres
  6. Lendo e Escrevendo Cadeias de Caracteres
  7. Lendo e Escrevendo Arquivos Binários
  8. Entrada e Saída Formatada
  9. Exercícios
------------------------------------------------------------------------

Introdução

Em C não existem comandos de Entrada e Saída, sendo estas tarefas executadas por funções especialmente criadas para esta finalidade e armazenadas em bibliotecas específicas.

------------------------------------------------------------------------

Fluxos de Dados

Para isolar os programadores dos problemas de manipular os vários tipos de dispositivos de armazenamento e seus diferentes formatos a linguagem C utiliza o conceito de fluxo (stream) de dados. Todos os diferentes sistemas de arquivos se comportam da mesma maneira quando manipulados como um fluxo contínuo de dados. Dados podem ser manipulados em dois diferentes tipos de fluxos: fluxos de texto e fluxos binários.


Fluxos de Texto

Um fluxo de texto é composto por uma seqüência de caracteres, que pode ou não ser dividida em linhas terminadas por um caracter de final de linha. Um detalhe que deve ser considerado é que na última linha não é obrigatório o caracter de fim de linha.

Nem sempre a tradução entre a representação do caracter no fluxo de texto e no sistema de arquivos do computador hospedeiro é um para um. Por exemplo, entre UNIX e DOS há uma diferença na representação de final de linha que causa problemas na impressão de arquivos. Em UNIX um final de linha é representado pelo caracter de alimentação de linha. Em DOS um final de linha é representado pelo par retorno de carro/alimentação de linha. Deste modo quando um arquivo gerado em UNIX vai para uma impressora que espera final de linha no modo DOS surge o que é comumente chamado de efeito escada. A impressão continua na linha seguinte mas sem voltar para o início da linha porque em UNIX o caracter de retorno de carro não é inserido no fluxo de texto.

Até agora temos trabalhado com os fluxos de dados padrão: stdin, para entrada de dados e stdout para saída de dados. 


Fluxo Binário

Um fluxo binário é composto por uma seqüência de bytes lidos, sem tradução, diretamente do dispositivo externo. Não ocorre nenhuma tradução e existe uma correspondência um para um entre os dados do dispositivo e os que estão no fluxo.


Arquivos

Arquivo pode ser qualquer dispositivo de Entrada e Saída como por exemplo: impressora, teclado, disquete, disco rígido, etc.

 Programas vêem os arquivos através de fluxos. Para que um determinado arquivo seja associado a um determinado fluxo é necessário que o arquivo seja aberto. Após esta operação o programa pode utilizar os dados armazenados no arquivo.

 Operações comuns em arquivos são:

Obviamente algumas dessas funções não se aplicam a todos os tipos de dispositivos. Por exemplo, para uma impressora não é possível usar a função que reposiciona o arquivo no ínicio. Um arquivo em disco permite acesso aleatório enquanto um teclado não.

 Ao final das operações necessárias o programa deve fechar o arquivo. Ao final da execução de um programa todos os arquivos associados são fechados automaticamente e os conteúdos dos buffers são descarregados para o dispositivo externo. Caso o arquivo seja de entrada o conteúdo do buffer é esvaziado.

------------------------------------------------------------------------

Funções de Entrada e Saída

As funções de Entrada e Saída normalmente utilizadas pelos programadores estão armazenadas na biblioteca stdio.h. As funções mais comuns estão mostradas na tabela 10.1 a seguir.
 
Função Descrição
fopen() Abre um arquivo
putc(), fputc() Escreve um caracter em um arquivo
getc(), fgetc() Lê um caracter de um arquivo
fprintf() Equivalente a printf(), usando stream
sscanf() Equivalente a scanf(), usando string 
fscanf() Equivalente a scanf(), usando stream 
fseek() Posiciona o arquivo em um ponto específico
rewind() Posiciona o arquivo no início
feof() Retorna VERDADE se chegou ao fim do arquivo
ferror() Verifica a ocorrência de erro
fflush() Descarrega o buffer associado com o arquivo
fread() Leitura de dados no modo binário
fwrite() Escrita de dados no modo binário

Tabela 10.1 Funções de Entrada e Saída

Para ter acesso aos dados em um arquivo é necessário a definição de um ponteiro do tipo especial FILE. Este tipo também está definido na biblioteca stdio.h. Um ponteiro deste tipo permite que o programa tenha acesso a uma estrutura que armazena informações importantes sobre o arquivo. Para definir uma variável deste tipo o programa deve conter a seguinte declaração

FILE *arq;

onde arq é o ponteiro que será usado para executar as operações no arquivo.

------------------------------------------------------------------------

Início e Fim

As operações mostradas a seguir mostram operações que devem ser realizadas antes e depois de usar um arquivo (fopen() e fclose()). As outras duas funções server para que o usuário possa detectar o fim de um arquivo ou voltar para seu início.


Abrindo um Arquivo

Antes de qualquer operação ser executada com o arquivo, ele deve ser aberto. Esta operação associa um fluxo de dados a um arquivo. Um arquivo pode ser aberto de diversas maneiras: leitura, escrita, leitura/escrita, adicão de texto, etc. A função utilizada para abrir o arquivo é chamada fopen() e tem o seguinte protótipo:
 


FILE *fopen (const char *parq, const char *modo)

onde parq é um ponteiro de arquivo para o arquivo a ser manipulado e modo é um ponteiro para uma cadeia de caracteres que define a maneira como o arquivo vai ser aberto. Este ponteiro não deve ser modificado e a função retorna um ponteiro nulo (NULL) se o arquivo não puder ser aberto. A tabela 10.2 lista os diversos modos que podem ser usados para abrir um arquivo.

Modo Descrição
r Abre um arquivo texto para leitura
w Cria um arquivo texto para escrita
a Adiciona texto ao fim de um arquivo texto
rb Abre um arquivo binário para leitura
wb Abre um arquivo binário para escrita
ab Anexa a um arquivo binário
r+ Abre um arquivo texto para leitura/escrita
w+ Cria um arquivo texto para leitura/escrita
a+ Cria ou anexa a um arquivo texto para leitura/escrita
r+b Abre um arquivo binário para leitura/escrita
r+b Cria um arquivo binário para leitura/escrita
a+b Anexa a um arquivo binário para leitura/escrita

Tabela 10.2 Modos de abertura de arquivos

Observar que se um arquivo for aberto com permissão de escrita todo o sue conteúdo anterior será apagado. Caso o arquivo não exista ele será criado.

A maneira mais comum de abrir um arquivo está ilustrado no exemplo abaixo:
 
 

    FILE *pa;

    if (( pa = fopen ("arquivo.txt", "w")) == NULL ) {
        printf("Desculpe, o arquivo nao pode ser aberto.");
        exit(1);
    }
Abrir um arquivo que já existe para escrita, implica em apagar todo o conteúdo anterior do arquivo e a preparação do arquivo para receber dados a partir de seu ponto inicial. Se o programador deseja acrescentar dados ao final de um arquivo já existente o modo de abertura deve ser a.
 
 


Fechando um Arquivo

Um arquivo aberto por meio da função fopen() deve ser fechado com a função fclose() cujo protótipo é

int fclose (FILE *parq);

onde parq é um ponteiro de arquivo para o arquivo que deve ser fechado. Um valor zero de retorno significa que a operação foi executada com êxito, qualquer outro valor implica em erro.

 A operação fclose() implica em escrita no arquivo de qualquer dado que ainda não tenha sido escrito. Este ponto é importante de ser considerado porque em UNIX uma operação de escrita em um arquivo não ocorre imediatamente a emissão da ordem de escrita. O sistema operacional pode executar a ordem no momento que achar mais conveniente.


Fim de Arquivo

A função feof() indica que um arquivo chegou ao seu final. A pergunta que pode surgir é a seguinte - Se já existe o valor EOF para indicar o final de arquivo por que precisamos de uma função extra do tipo feof()?

 O problema é que EOF é um valor inteiro e ao ler arquivos binários este valor pode ser lido como parte do arquivo e não por ser o final do arquivo. A função feof() serve para indicar que o final de um arquivo binário foi encontrado. Naturalmente esta função pode ser aplicada também a arquivos texto. O protótipo da função é o seguinte:
 


int feof(FILE *parq)


Volta ao Início

A função rewind() recoloca o indicador de posição de arquivo no inicio do arquivo. Uma operação semelhante ao que fazemos em uma fita cassete de música ou vídeo. O protótipo da função é o seguinte:
 


void rewind(FILE *parq)

É importante observar que o arquivo deve estar aberto em um modo que permita a execução das operações desejadas. Por exemplo, um arquivo aberto somente para escrita e em seguida rebobinado para o início, não irá permitir outra operação que não seja escrita.

-------------------

Lendo e Escrevendo Caracteres

As operações mais simples em arquivos são a leitura e escrita de caracteres. Para ler um caracter de um arquivo que foi previamente aberto pode se usar as funções getc() e fgetc(), que são equivalentes. O protótipo de fgetc é:
 


int fgetc (FILE *parq);

As funções getc() e fgetc() são equivalentes e muitos compiladores implementam getc() como uma macro do seguinte modo:

#define getc(parq) fgetc(parq)

A função lê o caracter como um unsigned char mas retorna o valor como um inteiro, onde o byte mais significativo vale zero. A função devolve o código EOF ao chegar ao final do arquivo. O valor EOF também é um inteiro válido e portanto ao usar arquivos binários é necessário que a função feof() seja utilizada para verificar o final do arquivo.

 Para escrever caracteres há duas funções definidas putc() e fputc(). O protótipo da função fputc é o seguinte:
 


int fputc(int ch, FILE *parq)

onde parq é um ponteiro de arquivo para o arquivo que foi previamente aberto por meio da função fopen() e ch e o caracter a ser escrito.

O programa c10le.c mostrado abaixo ilustra um exemplo onde um arquivo é criado para leitura e escrita. Em seguida um conjunto de caracteres lido do teclado é escrito no arquivo. Neste exemplo a leitura termina quando o usuário digita o caracter <ctl>D, que indica final de arquivo pelo teclado em Unix (naquele outro sistema acho que é <ctl-Z>). O próximo passo é a leitura do arquivo que é iniciada após uma chamada a função rewind(), fazendo com que o indicador de posição do arquivo volte a apontar para seu início.
 
 

/*      Programa: c10lec.c
        Descricao: Escreve e em seguida le caracteres de um arquivo. */

#include<stdio.h>
#include<stdlib.h>
int main (void ) {
    int c;
    FILE *pa;
    char *nome = "texto.txt";
    /* Abre o arquivo para leitura e escrita */
    if (( pa = fopen(nome, "w+")) == NULL) {
        printf("\n\nNao foi possivel abrir o arquivo.\n");
        exit(1);
    }
    /* Cada caracter digitado ser gravado no arquivo */
    c = getchar();
    while (!feof(stdin)) {
        fputc(c, pa);
        c = getchar();
    }
    rewind(pa);  /* volta ao inicio do arquivo */
    printf("\nTerminei de escrever, agora vou ler.\n");
    c = fgetc(pa);
    while (!feof(pa)) {
        putchar(c);
        c = fgetc(pa);
    }
    fclose(pa);
    getchar(); /* Espera o usuario digitar alguma coisa */
}

Uma outra alternativa mostrada em c10l.c mostra um exemplo onde o arquivo é criado para escrita em seguida é fechado e reaberto para leitura ficando automaticamente posicionado no início para a leitura.
/*      Programa: c10lec.c
        Descricao: Escreve e em seguida le caracteres de um arquivo. Nao usa rewind. */


#include<stdio.h>
#include<stdlib.h>
int main (void ) {
     int c;
    FILE *pa;
    char *nome = "texto.txt";

    if (( pa = fopen(nome, "w+")) == NULL) {
        printf("\n\nNao foi possivel abrir o arquivo para escrita.\n");
        exit(1);
    }
    /* Cada caracter digitado ser gravado no arquivo */
    c = getchar();
    while (!feof(stdin)) {
        fputc(c, pa);
        c = getchar();
    }
    fclose(pa);
    printf("\nTerminei de escrever, agora vou ler.\n");
    if (( pa = fopen(nome, "r")) == NULL) {
        printf("\n\nNao foi possivel abrir o arquivo para leitura.\n");
        exit(1);
    }
    c = fgetc(pa);
    while (!feof(pa)) {
        putchar(c);
        c = fgetc(pa);
    }
    fclose(pa);
    getchar();
}
------------------

Lendo e Escrevendo Cadeias de Caracteres

As funções fgets() e fputs() servem para ler e escrever cadeias de caracteres em arquivos. i Os protótipos das funções são:


int fputs(char *str, FILE *parq);

int fgets(char *str, int comp, FILE *parq);

A função fputs() escreve a cadeia de caracteres apontada por str no fluxo apontado por parq e o código correspondente à EOF será retornado se ocorrer um erro.

 A função fgets() lê uma cadeia de caracteres do fluxo especificado até que um caracter de nova linha seja encontrado ou comp-1 caracteres sejam lidos. Observar que diferentemente de gets() o caracter de nova linha encontrado passa a fazer parte da cadeia que recebe um caracter nulo ao seu final. Caso ocorra um erro na leitura da cadeia o ponteiro str recebe o valor NULL

 O exemplo c10les.c, listado abaixo, mostra um exemplo de uso das funções para ler e escrever cadeias de caracteres em um arquivo.

/*      Programa: c10les.c
        Descricao: Escreve e em seguida le cadeias de um arquivo. */

#include<stdio.h>
#include<stdlib.h>
#define MAX 80
int main (void ) {
                   char linha[MAX];
                   FILE *pa;
                   char *nome = "texto.txt";
                   /* Abre o arquivo para leitura e escrita */
                   if (( pa = fopen(nome, "w+")) == NULL) {
                                           printf("\n\nNao foi possivel abrir o arquivo.\n");
                                           exit(1);
                   }
                   /* Cada linha digitada sera gravada no arquivo */
                   gets(linha);
                   while (!feof(stdin)) {
                                           strcat(linha, "\n");
                                           fputs(linha, pa);
                                           gets(linha);
                   }
                   rewind(pa);       /* volta ao inicio do arquivo */
                   printf("\nTerminei de escrever, agora vou ler.\n");
                   fgets(linha, MAX, pa);
                   while (!feof(pa)) {
                                           printf("%s",linha);
                                           fgets(linha, MAX, pa);
                   }
                   fclose(pa);
                   getchar(); /* Espera o usuario digitar alguma coisa */
}
-----------------------

Lendo e Escrevendo Arquivos Binários

As funções fread e fwrite são empregadas para leitura e escrita de dados em modo binário. Os protótipos das funções são:

size_t fread (void *ptr, size_t size, size_t nmemb, FILE *parq);

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *parq);


A função freadnmemb objetos, cada um com size bytes de comprimento do fluxo apontado por stream e os coloca na localização apontada por ptr. fread retorna o número de itens que foram lidos com sucesso. Caso ocorra um erro, ou o fim do arquivo foi atingido o valor de retorno é menor do que nmemb ou zero. Esta função não distingue entre um fim de arquivo e erro, portanto é aconselhavel o uso de feof() ou ferror() para determinar que erro ocorreu.

A função fwrite escreve nmemb elementos de dados, cada um com size bytes de comprimento, para o fluxo apontado por stream obtendo-os da localização apontada por ptr. fwrite retorna o número de itens que foram lidos com sucesso. Caso ocorra um erro, ou o fim do arquivo foi atingido o valor de retorno é menor do que nmemb ou zero.

O programa c10leb.c mostrado abaixo ilustra como podemos escrever e ler dados de diferentes tipos em arquivos. Como um dos parâmetros da funçã é o número de bytes do dado a ser lido, é recomendado o uso de sizeof.


int main (void ) {
  int inum=10;
  float fnum=2.5;
  double pi=3.141516;
  char c='Z';
  FILE *pa;
  char *nome = "texto.txt";

  if (( pa = fopen(nome, "w+b")) == NULL) {
    printf("\n\nNao foi possivel abrir o arquivo para escrita.\n");
    exit(1);
  }
  fwrite(&inum, sizeof(int), 1, pa);
  fwrite(&fnum, sizeof(float), 1, pa);
  fwrite(&pi, sizeof(double), 1, pa);
  fwrite(&c, sizeof(char), 1, pa);

  rewind(pa);

  fread(&inum, sizeof(int), 1, pa);
  fread(&fnum, sizeof(float), 1, pa);
  fread(&pi, sizeof(double), 1, pa);
  fread(&c, sizeof(char), 1, pa);

  printf("%d, %f, %lf, %c\n", inum, fnum, pi, c);

  fclose(pa);
  exit(0);
}

Uma das principais aplicações destas funções é a leitura e escrita de estruturas criadas pelos usuários. A gravação em binário da estrutura permite que o programador ao escrever ou ler do arquivo se preocupe somente com a estrutura como um todo e não com cada elemento que a compõe.

O programa c10bin.c mostrado abaixo ilustra como podemos escrever e ler estruturas.

#include<stdio.h>
#include<stdlib.h>

#define MAX 4

int main () {

     FILE *pa;
     char nome[40];
     char linha[80];

     struct pessoa {
            char nome[40];
            int ano;
     } turma [MAX], back[MAX];

     int i;

     for (i=0; i<MAX; i++) {
         puts("Nome ? ");
         fgets(turma[i].nome, 40, stdin);
         puts("Ano  ? "); fgets(linha, 80, stdin);
         sscanf(linha, "%d", &turma[i].ano);
     }

     puts ("\nImprimindo\n");
     for (i=0; i<MAX; i++) {
         printf("Nome = %s\n", turma[i].nome);
         printf("Ano  = %d\n\n", turma[i].ano);
     }

     puts("\nGravando\n");
     puts("Qual o nome do arquivo?"); fgets(nome, 40, stdin);

     if (( pa = fopen(nome, "w+b")) == NULL ) {
        puts("Arquivo nao pode ser aberto");
        exit(1);
     }

     for (i=0; i<MAX; i++) {
         if (fwrite( &turma[i], sizeof (struct pessoa), 1, pa) != 1)
            puts("Erro na escrita.");
     }

     rewind(pa);

     for (i=0; i<MAX; i++) {
         if (fread( &back[i], sizeof (struct pessoa), 1, pa) != 1) {
            puts("Erro na escrita.");
            if (feof(pa)) break;
            puts("Erro na leitura.");
         }
     }

     puts("Imprimindo o vetor lido.");

     for (i=0; i<MAX; i++) {
         printf("Nome = %s\n", back[i].nome);
         printf("Ano  = %d\n\n", back[i].ano);
     }
     exit(0);
}


-------------------------------

Entrada e Saída Formatada

As funções fprintf() e fscanf() são equivalentes as funções printf() e scanf() usadas até agora, sendo a única modificação o fato de que elas trabalham com fluxos de dados (arquivos). Os protótipos das duas funções são os seguintes:


int fprintf(FILE *parq, const char *formatacao, ...);

int fscanf(FILE *parq, const char *formatacao, ...);

onde parq é um ponteiro de arquivo recebido após uma chamada a fopen().

Embora estas duas funções, por sua semelhança com printf() e scanf(), sejam maneiras convenientes de escrecer e ler dados de arquivos, elas têm a desvantagem de serem mais lentas do que uso de arquivos binários, os quais serão mostradas mais a frente. A perda de tempo é devido ao fato dos dados serem gravados em ASCII, o que obriga a uma conversão dos dados a cada operação realizada.

Em alguns casos o fato dos dados serem gravados em ASCII pode ser considerado um vantagem que se sobrepõe a desvantagem da redução de velocidade. Dados gravados em ASCII podem ser facilmente verificados pelos usuários, o que não acontece com dados em binário.

O exemplo c10sp.c, listado abaixo, mostra um exemplo de uso destas funções para ler e escrever vários tipos de dados em um arquivo.

#include<stdio.h>
#include<stdlib.h>
#define MAX 20
int main (void ) {
      char palavra[MAX];
      int i;
      float f;
      FILE *pa;
      char *nome = "format.txt";

      /* Abre o arquivo para leitura e escrita */
      if (( pa = fopen(nome, "w+")) == NULL) {
        printf("\n\nNao foi possivel abrir o arquivo.\n");
        exit(1);
      }
      puts ("Entre com uma palavra."); scanf ("%s", palavra);
      puts ("Entre com um numero inteiro."); scanf("%d", &i);
      puts ("Entre com um numero flutuante."); scanf("%f", &f);
      /* Escreve os dados no arquivo */
      fprintf(pa, "%s %d %f", palavra, i, f);

      rewind(pa);       /* volta ao inicio do arquivo */
      printf("\nTerminei de escrever, agora vou ler.\n");
      fscanf(pa, "%s %d %f", palavra, &i, &f);
      printf("Palavra lida: %s\n", palavra);
      printf("Inteiro lido: %d\n", i);
      printf("Float             lido: %f\n", f);
      fclose(pa);
      getchar(); /* Espera o usuario digitar alguma coisa */
      exit(0);
}
--------------------------

Exercícios

  1. Escreva um programa que abra um arquivo texto e conte o número de caracteres presentes nele. Imprima o número de caracteres na tela.
    Solução: caracteres.c

  2. Considere um arquivo de dados do tipo texto com o seguinte conteúdo:
    3
    ZE SA
    8.5
    10.0
    ANTONIO SANTOS
    7.5
    8.5
    SEBASTIAO OLIVEIRA
    5.0
    6.0
    
    O arquivo acima é apenas um exemplo. Nestes arquivos de alunos a primeira linha contém o número de alunos no arquivo. As linhas seguintes contém os seguintes dados: Escreva um programa que imprima os nomes de todos os alunos que têm a média das duas notas menor que 7.0
    Solução: alunos.c

  3. Escreva um programa que grave os dados lidos no exercício anterior em um arquivo do tipo binário de acesso aleatório. O número que indica quantos alunos devem ser lidos (primeira linha do arquivo) não deve ser gravado no arquivo binário. Nesta questão os dados devem estar obrigatoriamente armazenados em um vetor de estruturas do seguinte tipo:
    typedef struc _aluno
    {
        char nome[81];
        float n1, n2;
    } ALUNO;
    

    Solução: alunosbin.c

  4. Escreva um programa que leia de um arquivo, cujo nome sera fornecido pelo usuario, um conjunto de numeros reais e armazena em um vetor. O tamanho máximo do vetor e dado pela constante TAM_MAX. A quantidade de numeros no arquivo varia entre 0 e TAM_MAX. O programa ao final calcula a media dos numeros lidos.
    Solução: LeNumeros.c

  5. Faça um programa que leia 10 caracteres e armazene em um arquivo 10 cópias de cada um. Exiba o conteúdo do arquivo.
    Solução: arquivo.c

  6. Crie uma função que receba duas strings como parâmetros, uma com um endereço de arquivo e outra com um texto qualquer, e adicione o texto no fim do arquivo.
    Solução: adiciona.c

  7. 3) Utilizando a função do exercício anterior faça um programa que gere 10 arquivos com o nome "Teste" e extensões "01", ..., "10". Cada um contendo o texto "Texto do arquivo [NÚMERO DO ARQUIVO]".
    Solução: gera_arq.c

  8. Escreva um programa para armazenar o telefone de 5 amigos atravez da estrutura
    
     struct pessoa{
         char nome[50];
         int idade;
         float altura;
         char telefone[10];
     } amigos[5];
    
    
    a ser preenchida pelo usuário antes do armazenamento de cada registro.
    Solução: telefone.c

  9. Faça um programa que leia os dados do arquivo gerado no exercício anterior e salve-os num novo arquivo utilizando uma saída formatada.

    FORMATO:
    --------
    [nome] tem [idade] anos e [altura] de altura.
    Tel.: [telefone].
    --------

    Solução: fprintf.c

  10. Escreva um programa que leia um arquivo texto contendo linhas de dados. Em cada linha do arquivo há o nome de um aluno e duas notas. Estes dados estão separados por ponto e vírgula. Existe um ponto e vírgula ao final de cada linha. O formato dos dados e o seguinte:

    ze sa; 10.0; 9.0;
    antonio silva: 9.0; 7.0;

    O programa deve ler estes dados e imprimir os valores lidos, a média das duas notas e se o aluno foi aprovado ou não (media >= 5). O formato de saida e:

    ze sa 10.0 8.0 9.0 aprovado
    antonio silva 9.0 7.0 8.0 aprovado

    Solução: expv.c



  11. Faça um programa que ao receber o nome de um arquivo, gere uma cópia deste.
    Solução: copia.c

  12. Escreva um programa que compare dois arquivos especificados pelo usuário e imprima sempre que os caracteres dos dois arquivos coincidirem. Por exemplo:
    arquivo1.c
    Olá, pessoal!
    arquivo2.c
    Oi, como vai?

    Neste caso, os caracteres na primeira e décima primeira posição são iguais nos dois arquivos. A saída do seu programa deve ser algo como:
    1 - O (79)
    11 - a (97)

    Os valores entre parenteses são os respectivos códigos ASCII dos caracteres.
    Solução: compara.c

----------------------------------------

Índice