Exercicios Resolvidos Varios
Exercicios Resolvidos Varios
Exercicios Resolvidos Varios
Programação Imperativa
Aula 20
2 Sumário
Ficheiros de texto
3 Ficheiros de texto
Um ficheiro de texto não é mais do que uma sequência de caracteres
que ficam armazenados no disco do computador. Essa sequência de
caracteres é terminada com um caracter especial denominado fim-de-
ficheiro.
main()
{
FILE *in, *out;
int a, b;
/* leitura e escrita */
fscanf( in, "%d", &a );
fscanf( in, "%d", &b );
fprintf( out, "Este ficheiro foi criado pelo programa em C.\n"
);
fprintf( out, "%d\n", a*a );
fprintf( out, "%d\n", b*b );
/* fecha os ficheiros */
fclose( in );
fclose( out );
}
main()
{
FILE *in, *out;
char c;
c = fgetc( in );
while( c != EOF )
{
fputc( toupper(c), out );
c = fgetc( in );
}
fclose( in );
fclose( out );
}
6 Outro exemplo
Vamos supor que temos um ficheiro chamado nomes.txt cujo conteúdo
são nomes de pessoas, um nome por linha. Pretende-se fazer um
programa que leia esses nomes para um array de nomes. Aqui vai
uma tentativa,
#include <stdio.h>
#include <stdlib.h>
vogais = 0;
for( i=0; i< strlen(s); i++ )
if( eh_vogal(s[i]) )
vogais++;
return vogais;
}
main()
{
FILE *f;
int i;
int ultimo;
char nomes[100][30];
f = fopen("nomes.txt", "r");
if( f == NULL )
erro("...");
i = 0;
while( fgets(nomes[i], 30, f) != NULL && (i<100) )
{
ultimo = strlen( nomes[i] );
nomes[i][ultimo-1] = '\0'; /* para mandar fora o '\n'
*/
printf("%s %d\n", nomes[i], conta_vogais(nomes[i]) );
i++;
}
fclose( f );
}
A linguagem C trata os arquivos como uma sequência de bytes. Esta sequência pode ser
manipulada de várias formas e para tanto, existem funções em C para criar, ler e escrever
o conteúdo de arquivos independente de quais sejam os dados armazenados.
Lembrando que o ponteiro deve ser a mesma variável ponteiro associada ao comando de
abertura de arquivo.
Tipos de abertura de arquivos
r: Permissão de abertura somente para leitura. É necessário que o arquivo já esteja
presente no disco.
w: Permissão de abertura para escrita (gravação). Este código cria o arquivo caso ele não
exista, e caso o mesmo exista ele recria o arquivo novamente fazendo com que o
conteúdo seja perdido. Portanto devemos tomar muito cuidado ao usar esse tipo de
abertura.
a: Permissão para abrir um arquivo texto para escrita(gravação), permite acrescentar
novos dados ao final do arquivo. Caso não exista, ele será criado.
Exemplo de criação de arquivos.
1. #include <stdio.h>
2. #include <stdlib.h>
3.
4. int main(void)
5. {
6. // criando a variável ponteiro para o arquivo
7. FILE *pont_arq;
8.
9. //abrindo o arquivo
10. pont_arq = fopen("arquivo.txt", "a");
11.
12. // fechando arquivo
13. fclose(pont_arq);
14.
15. //mensagem para o usuário
16. printf("O arquivo foi criado com sucesso!");
17.
18. system("pause");
19. return(0);
20. }
Tela de execução
Tela de execução do exemplo criação de arquivo
Problemas na abertura de arquivos
Na prática, nem sempre é possível abrir um arquivo. Podem ocorrer algumas situações
que impedem essa abertura, por exemplo:
Você está tentando abrir um arquivo no modo de leitura, mas o arquivo não existe;
Você não tem permissão para ler ou gravar no arquivo;
O arquivo está bloqueado por estar sendo usado por outro programa.
Quando o arquivo não pode ser aberto a função fopen retorna o valor NULL.
É altamente recomendável criar um trecho de código a fim de verificar se a abertura
ocorreu com sucesso ou não.
Exemplo:
if (pont_arq == NULL)
{
printf("ERRO! O arquivo não foi aberto!\n");
}
else
{
printf("O arquivo foi aberto com sucesso!");
}
1. #include <stdio.h>
2. #include <stdlib.h>
3. int main(void)
4. {
5. FILE *pont_arq; // cria variável ponteiro para o arquivo
6. char palavra[20]; // variável do tipo string
7.
8. //abrindo o arquivo com tipo de abertura w
9. pont_arq = fopen("arquivo_palavra.txt", "w");
10.
11. //testando se o arquivo foi realmente criado
12. if(pont_arq == NULL)
13. {
14. printf("Erro na abertura do arquivo!");
15. return 1;
16. }
17.
18. printf("Escreva uma palavra para testar gravacao de arquivo: ");
19. scanf("%s", palavra);
20.
21. //usando fprintf para armazenar a string no arquivo
22. fprintf(pont_arq, "%s", palavra);
23.
24. //usando fclose para fechar o arquivo
25. fclose(pont_arq);
26.
27. printf("Dados gravados com sucesso!");
28.
29. getch();
30. return(0);
31. }
Tela de execução
do
{
//faz a leitura do caracter no arquivo apontado por pont_arq
c = getc(pont_arq);
}while (c != EOF);
1. //Leitura de arquivo
2. #include <stdio.h>
3. #include <stdlib.h>
4.
5. int main(void)
6. {
7. FILE *pont_arq;
8. char texto_str[20];
9.
10. //abrindo o arquivo_frase em modo "somente leitura"
11. pont_arq = fopen("arquivo_palavra.txt", "r");
12.
13. //enquanto não for fim de arquivo o looping será executado
14. //e será impresso o texto
15. while(fgets(texto_str, 20, pont_arq) != NULL)
16. printf("%s", texto_str);
17.
18. //fechando o arquivo
19. fclose(pont_arq);
20.
21. getch();
22. return(0);
23. }
Tela de execução
Tela de execução do exemplo leitura de arquivo
Até a próxima!
1. abrir o arquivo;
2. ler e/ou gravar os dados desejados;
3. fechar o arquivo.
Em C, todas as operações realizadas com arquivos envolvem seu identificador de fluxo,
que é uma variável do tipo FILE * (sobre o qual não cabe agora falar). Para declarar um
identificador de fluxo, faça como se fosse uma variável normal:
O nome do arquivo deve ser uma string ou com o caminho completo (por
exemplo, /usr/share/appname/app.conf ou C:\Documentos\nomes.txt) ou o
caminho em relação ao diretório atual (nomes.txt, ../app.conf) do arquivo que se
deseja abrir ou criar.
O modo de acesso é uma string que contém uma seqüência de caracteres que dizem
se o arquivo será aberto para gravação ou leitura. Depois de aberto o arquivo, você só
poderá executar os tipos de ação previstos pelo modo de acesso: não poderá ler de
um arquivo que foi aberto somente para escrita, por exemplo. Os modos de acesso
estão descritos na tabela a seguir.
Modo Significado
Abre o arquivo para escrita no final do arquivo. Não apaga o conteúdo pré-
a
existente. (O a vem do inglês append, adicionar, apender)
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen ("README", "w");
if (fp == NULL) {
printf ("Houve um erro ao abrir o arquivo.\n");
return 1;
}
printf ("Arquivo README criado com sucesso.\n");
fclose (fp);
return 0;
}
Esta função envolve os conceitos de ponteiro e vetor, que só serão abordados mais
tarde.
A função fwrite() funciona como a sua companheira fread(), porém escreve no arquivo.
Seu protótipo é:
A função retorna o número de itens escritos. Este valor será igual a count a menos que
ocorra algum erro. O exemplo abaixo ilustra o uso de fwrite e fread para gravar e
posteriormente ler uma variável float em um arquivo binário.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *pf;
float pi = 3.1415;
float pilido;
if((pf = fopen("arquivo.bin", "wb")) == NULL) /* Abre arquivo
binário para escrita */
{
printf("Erro na abertura do arquivo");
exit(1);
}
if(fwrite(&pi, sizeof(float), 1,pf) != 1) /* Escreve a
variável pi */
printf("Erro na escrita do arquivo");
fclose(pf); /* Fecha o
arquivo */
if((pf = fopen("arquivo.bin", "rb")) == NULL) /* Abre o arquivo
novamente para leitura */
{
printf("Erro na abertura do arquivo");
exit(1);
}
if(fread(&pilido, sizeof(float), 1,pf) != 1) /* Le em pilido o
valor da variável armazenada anteriormente */
printf("Erro na leitura do arquivo");
printf("\nO valor de PI, lido do arquivo e': %f", pilido);
fclose(pf);
return 0;
}
Nota-se o uso do operador sizeof, que retorna o tamanho em bytes da variável ou do tipo
de dados.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char string[100];
int i;
fp = fopen("arquivo.txt","w"); /* Arquivo ASCII, para
escrita */
if(!fp)
{
printf( "Erro na abertura do arquivo");
exit(0);
}
printf("Entre com a string a ser gravada no arquivo:");
gets(string);
for(i=0; string[i]; i++) fputc(string[i], fp); /* Grava a string,
caractere a caractere */
fclose(fp);
return 0;
}
Depois de executar este programa, verifique o conteúdo do arquivo arquivo.txt (você pode
usar qualquer editor de textos). Você verá que a string que você digitou está armazenada
nele.
Este módulo tem a seguinte tarefa pendente: criar exemplos de uso das funções
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fl;
int c;
fclose(fl);
return EXIT_SUCCESS;
}
Ao chamar a função fgets(), você deve fornecer o ponteiro para a string onde os dados
lidos devem ser guardados, além do tamanho máximo dos dados a serem lidos (para
que a memória reservada à string não seja ultrapassada).
Para se ler uma string num arquivo podemos usar fgets() cujo protótipo é:
A função recebe 3 argumentos: a string a ser lida, o limite máximo de caracteres a serem
lidos e o ponteiro para FILE, que está associado ao arquivo de onde a string será lida. A
função lê a string até que um caracter de nova linha seja lido ou tamanho-1 caracteres
tenham sido lidos. Se o caracter de nova linha ('\n') for lido, ele fará parte da string, o que
não acontecia com gets.
A função fgets é semelhante à função gets(), porém, além dela poder fazer a leitura a partir
de um arquivo de dados e incluir o caracter de nova linha na string, ela ainda especifica o
tamanho máximo da string de entrada. Como vimos, a função gets não tinha este controle,
o que poderia acarretar erros de "estouro de buffer". Portanto, levando em conta que o
ponteiro fp pode ser substituído por stdin, como vimos acima, uma alternativa ao uso de
gets é usar a seguinte construção:
Essa função envolve os conceitos de ponteiro e vetor, que só serão abordados mais
tarde.
Podemos escrever e ler blocos de dados. Para tanto, temos as funções fread() e fwrite(). O
protótipo de fread() é:
numero_de_bytes*count
A função retorna o número de unidades efetivamente lidas. Este número pode ser menor
que count quando o fim do arquivo for encontrado ou ocorrer algum erro.
Quando o arquivo for aberto para dados binários, fread pode ler qualquer tipo de dados.
Tendo-se definido a partir de onde irá se contar, numbytes determina quantos bytes de
deslocamento serão dados na posição atual.
Outra forma de se verificar se o final do arquivo foi atingido é comparar o caractere lido por
getc com EOF. O programa a seguir abre um arquivo já existente e o lê, caracter por
caracter, até que o final do arquivo seja atingido. Os caracteres lidos são apresentados na
tela:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char c;
fp = fopen("arquivo.txt","r"); /* Arquivo ASCII, para leitura */
if(!fp)
{
printf( "Erro na abertura do arquivo");
exit(0);
}
while((c = getc(fp) ) != EOF) /* Enquanto não chegar ao final
do arquivo */
printf("%c", c); /* imprime o caracter lido */
fclose(fp);
return 0;
}
Verifique o exemplo.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *p;
char c, str[30], frase[80] = "Este e um arquivo chamado: ";
int i;
printf("\n\n Entre com um nome para o arquivo:\n");
gets(str); /* Le um nome para o
arquivo a ser aberto: */
if (!(p = fopen(str,"w"))) /* Caso ocorra algum erro na
abertura do arquivo..*/
{
printf("Erro! Impossivel abrir o arquivo!\n");
exit(1); /* o programa aborta automaticamente */
}
strcat(frase, str);
for (i=0; frase[i]; i++)
putc(frase[i],p);
fclose(p); /* Se nao houve erro,imprime no
arquivo e o fecha ...*/
p = fopen(str,"r"); /* Abre novamente para leitura
*/
c = getc(p); /* Le o primeiro caracter */
while (!feof(p)) /* Enquanto não se chegar no
final do arquivo */
{
printf("%c",c); /* Imprime o caracter na tela */
c = getc(p); /* Le um novo caracter no arquivo */
}
fclose(p); /* Fecha o arquivo */
}
Função Explicação
A função retorna zero, se nenhum erro ocorreu e um número diferente de zero se algum
erro ocorreu durante o acesso ao arquivo. se torna muito útil quando queremos verificar se
cada acesso a um arquivo teve sucesso, de modo que consigamos garantir a integridade
dos nossos dados. Na maioria dos casos, se um arquivo pode ser aberto, ele pode ser lido
ou gravado.
Porém, existem situações em que isto não ocorre. Por exemplo, pode acabar o espaço em
disco enquanto gravamos, ou o disco pode estar com problemas e não conseguimos ler,
etc. Uma função que pode ser usada em conjunto com ferror() é a função perror() (print
error), cujo argumento é uma string que normalmente indica em que parte do programa o
problema ocorreu.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *pf;
char string[100];
if((pf = fopen("arquivo.txt","w")) ==NULL)
{
printf("\nNao consigo abrir o arquivo ! ");
exit(1);
}
do
{
printf("\nDigite uma nova string. Para terminar, digite <enter>:
");
gets(string);
fputs(string, pf);
putc('\n', pf);
if(ferror(pf))
{
perror("Erro na gravacao");
fclose(pf);
exit(1);
}
}while (strlen(string) > 0);
fclose(pf);
}
https://www.codingame.com/playgrounds/24988/programacao-c/exercicios-arquivos
3. Exercícios de Programação II e
respectivas resoluções
Observações
Note-se que:
Exercício 1
6.9.1 Alínea a)
Resolução
6.9.2 Alínea b)
Resolução
Entende-se por "texto" o que quer que seja escrito no teclado pelo utilizador
do programa até que seja premida a combinação de teclas equivalente a um
fim de ficheiro, que no MS-DOS é ctrl-z e em Unix é ctrl-d.
Algoritmo: idem...
Algoritmo passo-a-passo:
1. Abrir o ficheiro de saída.
2. Ler um caractere do teclado e guardá-lo no ficheiro de saída
enquanto não se atingir o fim das entradas de dados pelo
utilizador.
3. Fechar o ficheiro de saída.
Linguagem C: ex1b.c
Notas: Repare na semelhança entre as soluções dos três primeiros
exercícios (1.a), 1.b) e 1.c)).
6.9.3 Alínea c)
Resolução
Algoritmo: idem...
Algoritmo passo-a-passo:
1. Abrir o ficheiro de entrada.
2. Abrir o ficheiro de saída.
3. Ler um caractere do ficheiro de entrada, enquanto não se
atingir o fim do ficheiro, e guardá-lo no ficheiro de saída.
4. Fechar o ficheiro de entrada.
5. Fechar o ficheiro de saída.
Linguagem C: ex1c.c
6.9.4 Alínea d)
Resolução
6.9.5 Alínea e)
Comparar dois ficheiros de texto linha a linha e mostrar a primeira linha onde
eles diferem.
Resolução
6.9.6 Alínea f)
Resolução
6.9.7 Alínea g)
Resolução
6.9.8 Alínea h)
Resolução
Linguagem C: ex1h.c
Notas:
1. Não sendo especificada qualquer condição de paragem no
enunciado, arbitrou-se parar se for premida a combinação de
teclas que assinala o fim do ficheiro, ou sempre que um valor
inválido for introduzido.
2. São de notar as particularidades das especificações de
conversão da função printf() utilizadas:
%4d -- imprime um inteiro de modo a ocupar pelo menos
quatro caracteres, acrescentando espaços à esquerda se
necessário, isto é, justificando o número à direita.
%-*.*s -- a construção n.m, em que n e m são números
indica que a cadeia de caracteres depois de impressa
deve ocupar pelo menos n caracteres e que não devem
ser impressos mais do que m caracteres da cadeia;
sempre que m ou n forem substituídos por * (que é o
caso) o valor correspondente será lido do próximo
argumento de printf() (no caso a macro NOME_MAX); o
caractere - indica que a cadeia de caracteres deverá ser
justificada à esquerda, e não `a direita.
3. Note-se ainda que a leitura do nome se faz por intermédio
de fgets(), tendo-se no entanto o cuidado de eliminar todos os
caracteres espúrios introduzidos pelo utilizador (até ao fim-de-
linha) de modo a evitar a sua interpretação errónea aquando da
leitura da nota do teste. Observe-se o tamanho da matriz nome,
com espaço para os 25 caracteres do nome e para o
terminador '\0'.
4. A utilização de macros e do caractere * na especificação de
conversão do nome (na chamada à função printf()) permitem
mudar o tamanho máximo dos nomes alterando uma única
linha do programa!
6.9.9 Alínea i)
Mostrar no terminal o conteúdo de ficheiros de texto gerados pelo programa
da alínea anterior.
Resolução
Linguagem C: ex1i.c
Notas: São de notar as particularidades das especificações de
conversão da função fscanf() utilizadas. Em particular, a especificação
de conversão %nc lê os próximos n caracteres da entrada para uma
cadeia de caracteres. Note ainda que, neste caso, a conversão está
"mascarada" em "%d %" NOMECAD "c %d %d": acontece que qualquer
compilador ANSI-C tem obrigação de concatenar numa só qualquer
sequência de cadeias de caracteres constantes, resultando pois "%d
%25c %d %d" conforme desejado. A vantagem da utilização da
macro NOMECAD está em concentrar em duas linhas a informação a
alterar para mudar o tamanho máximo dos nomes a utilizar (a
utilização do caractere * em fscanf() tem um significado totalmente
diferente do que possuia para printf(), daí a necessidade deste
"truque").
6.9.10 Alínea j)
Resolução
Linguagem C: ex1j.c
Notas: Como se pode verificar, é perfeitamente possível escrever num
ficheiro binário uma matriz bidimensional toda duma só vez.
6.9.11 Alínea k)
Resolução
Linguagem C: ex1k.c
Exercício 2
Faça um programa para gerir uma base de dados associada aos utentes de um
parque de estacionamento universitário. Admite-se um máximo de 50 utentes
armazenados sob a forma de uma matriz. Cada utente é descrito pelos
seguintes campos:
A estrutura do programa principal, que faz uso das funções acima, fica ao
critério do aluno, e deverá ser preparada antes das funções. Este assunto, tal
como o resto do enunciado, deve ser pensado com antecedência.
6.10.1 Resolução
Linguagem C: ex2.c
Notas:
1. Não se controlam repetições de nomes e/ou códigos (fica como
exercício adicional...).
2. Alterou-se o enunciado no que diz respeito às funções de leitura
e escrita de ficheiros: têm apenas um argumento, pois
perguntam elas próprias o nome dos ficheiros respectivos.
3. Note-se a utilização da variável alterado em main(), para
garantir que o utilizador do programa não deita a perder uma
sessão de manipulação duma base de dados.
4. Notem-se também os valores devolvidos pelas funções.
5. Finalmente, note-se que a função mataLinha() se destina a
descartar todos os caracteres até ao próximo fim-de-linha,
tendo um efeito semelhante à chamada fflush(stdin) quando
se usa o Turbo-C. Esta utilização de fflush() com um canal
aberto para leitura (no caso stdin) tem resultados indefinidos,
de acordo com a norma ANSI-C, pelo que torna os programas
não "transportáveis", ou seja, com comportamento variável
consoante o compilador e/ou sistema operativo utilizado.
Exercício 3
em que campo indica o campo pelo qual a ordenação é feita, podendo tomar os
valores nome ou codigo.
6.11.1 Resolução
Linguagem C: ex3.c
Notas:
1. Admite-se que os ficheiros têm o mesmo formato utilizado no
exercício 2, isto é, uma linha por cada campo. Este formato
simplifica a leitura. Repare-se na utilização dum espaço em
branco no formato passado à função scanf(): "%d%d ". Este
espaço serve para que a função scanf() elimine os espaços em
branco, incluindo fins-de-linha, depois de ler a categoria e o
código, de modo a estes não afectarem a leitura do próximo
nome.
2. Repare-se que o algoritmo de ordenação utilizado é o de
"ordenação por permutação" (em inglês "bubble sort"),
diferente, e mais eficiente, que o utilizado no livro. Deve-se ter
em conta que este algoritmo, embora interessante, é muito
ineficiente (número de comparações proporcional, em média, a
NxN, sendo N o número de elementos a ordenar), não sendo
por isso recomendável a sua utilização (entre os algoritmos
mais eficientes encontra-se a "ordenação rápida" - em inglês
"quick sort" - cujo número de comparações é proporcional, em
média, a Nxlog(N)).
3. Note-se que, na função ordenaUtentes(), existem dois
algoritmos de ordenação idênticos, um ordenando por código e
outro por nome. Tal deve-se a que a utilização de um teste
adicional (ao campo pelo qual ordenar) dentro dos ciclos de
ordenação contribuiria fortemente para tornar a ordenação
mais lenta. Muito embora neste caso esta preocupação seja
exagerada, em programas exigindo a ordenação de um número
de elementos muito grande estas medidas simples podem levar
facilmente a um aumento considerável da velocidade de
execução.
4. Note-se finalmente na flexibilidade do programa face ao
número de argumentos. Admitindo que o programa se
chama ordena:
ordena
lê os dados do teclado e escreve-os, ordenados pelo nome, no ecrã.
ordena entrada
Exercício 4
Listas e recursividade:
6.12.1 Alínea a)
1. leitura de ficheiro
2. escrita de ficheiro
3. inserção de utentes
4. remoção de utentes
5. listagem dos utentes
6.12.2 Alínea b)
Resolução
Linguagem C: ex4b.c
Notas: A "moral" a retirar deste exercício é que, ainda que muitas
vezes as funções recursivas correspondam à concretização mais
evidente de um determinado algoritmo, geralmente também é
verdade que conduzem a realizações muito ineficientes, como pode
ser verificado correndo o programa apresentado como solução do
exercício.
6.12.3 Alínea c)
por exemplo:
int buscaNome(void *dadosgen, void *nomegen)
{
Utente *dados = dadosgen;
char *nome = nomegen;
Notas: não esquecer, nas alíneas a) e c), que a memória afectada deve ser
desafectada quando deixa de ser necessária.
Exercício 5
6.13.1 Introdução
Sumário
que é equivalente a
int func(int);
e
/* Ficheiro b.c */
extern int i;
Note-se que este último facto torna possível esconder totalmente, do utilizador
de um determinado módulo de funções, os seus pormenores de realização.
Suponha-se, por exemplo, um módulo de processamento de listas. Os
respectivos ficheiros listas.h (ficheiro de cabeçalho, do inglês header file)
e listas.c poderiam ser:
/* listas.h */
/*
* Declaracao (sentido estrito) da estrutura struct ListaStr e
* definicao do tipo Lista!
*/
typedef struct ListaStr Lista;
/* Declaracoes, sentido estrito, de funcoes de interface... */
Lista *Lcria(void);
...
e
/* listas.c */
/*
* A inclusao do ficheiro de cabecalho .h no ficheiro .c do
* proprio modulo permite:
* 1. Ter acesso `a definicao do tipo Lista.
* 2. Garantir coerencia entre as declaracoes das funcoes no
* ficheiro .h e a sua definicao no ficheiro .c.
*/
#include "listas.h"
/* Declaracao da estrutura ElementoStr e definicao do
tipo Elemento: */
typedef struct ElementoStr Elemento;
/* Definicao da estrutura ElementoStr: */
struct ElementoStr
{
void *dados;
Elemento *seguinte;
};
/* Definicao da estrutura struct ListaStr (declarada em
listas.h): */
struct ListaStr
{
unsigned long numero;
Elemento *inicio;
}
/* Definicao das funcoes: */
Lista *Lcria(void)
{
...
}
...
Categoria, âmbito, classe ou permanência e validade de objectos e nomes
em C
Categoria de objectos
Outro conceito importante diz respeito ao âmbito (ou skope em inglês) dos
nomes declarados, i.e., em que zonas dum ficheiro em C são visíveis esses
nomes. As regras são bastante simples:
Observe-se:
1 int a;
2 int f3(int);
3 int f1(int b)
4 {
5 int c;
6 int f2(int);
7 for(c = 0; b > 0; b--)
8 {
9 static int d = 1;
10 c += f2(d);
11 }
12 return c;
13 }
14 int e;
15 int f2(int f)
16 {
17 return f3(f);
18 }
19 int f3(int g)
20 {
21 return 1;
22 }
Automáticas
São variáveis locais (i.e., definidas dentro duma função) que têm
existência (i.e., um espaço de memória afectado) apenas durante a
execução da função em que foram definidas. O seu valor, como é
óbvio, perde-se entre chamadas sucessivas à função.
Estáticas
São variáveis que têm existência desde o início até ao fim do
programa.
As variáveis globais são sempre estáticas. As variáveis locais são automáticas
por omissão e são estáticas caso a sua definição seja precedida do
qualificador static.
Interna
Para variáveis e funções acessíveis apenas dentro do ficheiro onde são
definidas.
Externa
Para variáveis e funções acessíveis em todo o programa (qualquer que
seja o ficheiro).
As variáveis locais (ver definição acima) têm sempre validade apenas interna.
As variáveis ou funções globais têm, por omissão, validade externa. No
entanto, a sua validade pode ser interna desde que a sua definição seja
precedida do qualificador static. 3
e
/* Ficheiro b.c */
#include <stdio.h>
#include <stdlib.h>
#include "a.h"
int main(void)
{
globalExterna = -1;
printf("funcaoExterna(3) = %d\n", funcaoExterna(3));
return EXIT_SUCCESS;
}
Como é óbvio, a utilização dos objectos externos fora do ficheiro onde são
definidos implica a sua declaração, o que é conseguido, neste caso, por
intermédio da inclusão do ficheiro de cabeçalho a.h. Note-se que se utilizou o
qualificador extern apenas para a declaração das variáveis, tendo-se omitido,
por desnecessário, esse qualificador na declaração das funções.
6.13.2 Alínea a)
Altere o programa produzido no exercício 4.b) de modo a que o número de
chamadas da versão recursiva da função possa ser contabilizado. Para isso,
utilize uma variável local à função (que terá de ser, obviamente, estática).
Essa variável deve ser anulada sempre que se chamar a função com o
argumento -1. O número de chamadas à função deverá ser devolvido pela
função sempre que for chamada com o argumento -2.
Resolução
Linguagem C: ex5a.c
Notas: repare que se utiliza
printf("F(%d) = %lu\n", n, fibonacciRec(n));
printf("chamadas = %lu\n", fibonacciRec(-2));
e não
printf("F(%d) = %lu\nchamadas = %lu\n", n,
fibonacciRec(n), fibonacciRec(-2));
6.13.3 Alínea b)
Resolução
Linguagem C: ex5b.c
6.13.4 Alínea c)
Coloque as funções de cálculo da sucessão de Fibonacci num módulo
separado, de nome sucessao.c, com o respectivo ficheiro de
cabeçalho sucessao.h. Utilize nomes e tipos apropriados para as funções e
seus parâmetros, por exemplo unsigned long SUCfibonacci(int n) e unsigned
long SUCfibonacciRec(int n).
Resolução
6.13.5 Alínea d)
Resolução
6.13.6 Alínea e)
Tente evitar a dupla inclusão, tal como descrita atrás, do ficheiro sucessao.h,
recorrendo para isso às seguintes directivas do pré-processador:
Resolução
6.13.7 Alínea f)
Linguagem C: uteis.h
Exercício 6
Utilize as funções:
6.14.1 Resolução
Exercício 7
6.15.1 Alínea a)
esvazia a pilha p.
size_t PMquantos(PilhaM *p)
Resolução
6.15.2 Alínea b)
Semelhante à alínea a), mas agora serão filas (o primeiro a entrar é o primeiro
a sair), e não pilhas.
Note que a função void *FMtira(FilaM *f) retira o elemento que se encontra
há mais tempo na fila f!
Repare que neste caso poderá usar os indíces de modo a que "dêem a volta",
evitando-se assim a renormalização da matriz sempre que se retira um
elemento.
Resolução
6.15.3 Alínea c)
esvazia a pilha p.
unsigned long Pquantos(Pilha *p)
Repare que neste caso não se especifica qualquer dimensão máxima para a
pilha aquando da sua criação. Note-se ainda que não existe, como é óbvio,
qualquer função para verificar se a pilha está cheia.
Resolução
Linguagem C: pilhas.c e pilhas.h.
6.15.4 Alínea d)
Note que a função void *Ftira(Fila *f) retira o elemento que se encontra
há mais tempo na fila f!
Resolução
Exercício 8
Note que as variáveis a que este enunciado se refere não são variáveis da
linguagem C, mas sim objectos guardados pelo programa e definidos pelo seu
utilizador.
6.16.1 Resolução
http://home.iscte-iul.pt/~mms/courses/oop/1995-1996/aulas-praticas/exercicios.html
https://www.kelvinsantiago.com.br/exercicios-resolvidos-em-linguagem-c-lista-d/
Linguagem C
Fonte: Wikipedia
Exercício 1
1 /*
3 * Criado: 19/07/2013
4 */
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(){
11
12 int vetor[9], i;
13
15
16 scanf("%d",&vetor[i]);
17 printf("%d\n",vetor[i]);
18 }
19 return 0;
20 }
Exercício 2
1 /*
3 * Criado: 23/07/2013
4 */
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(){
11
13
15
16 scanf("%d",&numero);
17
18 if (posicao == 0){
19 vetor[posicao] = numero;
20 printf("%d\n",vetor[posicao]);
21 posicao++;
22 }
23
24 else{
25
27
29 vetor[posicao] = numero;
30 printf("%d\n",vetor[posicao]);
31 posicao++;
32 }
33 }
34 }
35 return 0;
36 }
Exercício 3
1 /*
3 * Criado: 23/07/2013
4 */
5
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(void){
11
13
14 scanf("%d",&numero);
15
17
18 if (contador == 0){
19 vetor[contador] = numero;
20 contador++;
21 }
22
23 else{
24 vetor[contador] = numero;
25 contador++;
26 }
27
28 scanf("%d",&numero);
29 }
30
31 if (numero == 999){
32 contador--;
33 }
34
36
37 printf("%d\n",vetor[contador]);
38 contador--;
39 }
40 return 0;
41 }
Exercício 4
1 /*
3 * Criado: 23/07/2013
4 */
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(void){
11
13
15
17
18 scanf("%d",&matriz[linha][coluna]);
19 }
20
21 }
22
24
25 for(coluna = 2; coluna >=0; coluna--){
26 if ( linha == coluna){
27 printf("%d\n",matriz[linha][coluna]);
28 }
29 }
30 }
31
32 return 0;
33 }
Exercício 5
1 /*
3 * Criado: 23/07/2013
4 */
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(void){
11
13
15
16 scanf("%d",&vetor[contagem]);
17
18 }
19
21
22 scanf("%d",&verificanumero);
23
25
26 if (verificanumero == vetor[contagem]){
28 contemcerto++;
29 }
30
31 }
32 if(contemcerto == 0){
34 }
35
36 contagemverifica++;
37 contemcerto = 0;
38 }
39
40 return 0;
41 }
Exercício 6
3 * Criado: 23/07/2013
4 */
6 #include<math.h>
7 #include<stdio.h>
8 #include<string.h>
10 int main(void){
11
12 int contador = 0;
13 float vetor[3],nota = 0 ;
14
15 scanf("%f",¬a);
16
18
19 vetor[contador] = nota;
20 contador++;
21
22 if (contador == 2){
23
25 printf("%.2f\n",vetor[contador]);
26
28 printf("APROVADO\n");
29 }
30 else{
31 printf("REPROVADO\n");
32 }
33 contador = 0;
34 }
35 scanf("%f",¬a);
36
37 }
38 return 0;
39 }
Exercício 7
2 * Criado: 24 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
12
14
16
18
19 calculo = (numero % contador_verificar);
20
21 if (calculo == 0){
22 numeroprimo++;
23 }
24 }
25 if (numeroprimo == 2){
26 vetor[contador_vetor] = numero;
27 printf("%d\n",vetor[contador_vetor]);
28 contador_vetor++;
29
30 }
31 numeroprimo = 0;
32 }
33
34 return 0;
35 }
Exercício 8
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
9
10 int main(void)
11 {
13
15
16 scanf("%d",&vetor[contador]);
17
18 if (vetor[contador] % 2 != 0){
19 somaimpares += vetor[contador];
20 }
21 }
22
23 printf("%d\n",somaimpares);
24 return 0;
25 }
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
12 int matriz1[3][3], matriz2[3][3], matrizmult[3][3], linha, coluna, i, j, k;
13
17 scanf("%d",&matriz1[linha][coluna]);
18 }
19 }
20
24 scanf("%d",&matriz2[linha][coluna]);
25 }
26 }
27
29
32 matrizmult[i][j]= 0;
33 }
34 }
35
41 }
42 }
43 }
44
49 printf("%d\n",matrizmult[linha][coluna]);
50 }
51 else{
52 printf("%d ",matrizmult[linha][coluna]);
53 }
54 }
55 }
56 return 0;
57 }
Exercício 9
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
13
14 // Lendo valores do primeiro vetor e verificando maior numero :DD
16 scanf("%d",&vetor1[contador]);
17
18 if (maiornumero == 0){
19 maiornumero = vetor1[contador];
20 }
22 maiornumero = vetor1[contador];
23 }
24 }
25
29 printf("%d\n",vetor2[contador]);
30 }
31
32 return 0;
33 }
Exercício 10
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
13
15
16 scanf("%d",&vetorA[contador]);
17 }
18
20
21 scanf("%d",&vetorB[contador]);
22 }
23
26
27 if (vetorA[contador] == vetorB[contadorb]){
28
29 if (igualdades == vetorA[contador]){
30
31 }
32
33 else{
34 igualdades = vetorA[contador];
35 printf("%d\n",vetorA[contador]);
36 }
37 }
38 }
39 }
40
41 return 0;
42 }
Exercício 11
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
13
15
16 scanf("%d",&vetorA[contador]);
17 }
18
20
21 scanf("%d",&vetorB[contador]);
22 }
23
26
27 if (vetorA[contador] == vetorB[contadorb]){
28
29 if (igualdades == vetorA[contador]){
30
31 }
32
33 else{
34 igualdades = vetorA[contador];
35 printf("%d\n",vetorA[contador]);
36 }
37 }
38 }
39 }
40
41 return 0;
42 }
Exercício 12
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
13
14 scanf("%d",&numero);
16
18 vetor[contador] = divisores;
19 contador++;
20 numerodivisores++;
21 }
22 }
23
25 printf("%d\n",vetor[contador]);
26 }
27
28 return 0;
29 }
Exercício 13
1 #include<stdio.h>
2 #include<string.h>
4 int main()
5 {
6 char palavra[50];
7 int i;
9 scanf("%s",palavra);
10
12
13 printf("%d\n",i);
14 return 0;
15 }
Exercício 14
2 * Criado: 25 / 07 / 2013
3 *
4 */
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
10 int main(void)
11 {
12 char palavra[20];
14
15 scanf("%s",palavra);
16
18
24
printf("%d\n",numVogais);
25
26
return 0;
27
}
_____________________________________________________________________________
_______
https://www.ime.usp.br/~macmulti/exercicios/vetores/
Solução em C
o cartão gabarito;
o número de alunos da turma;
o cartão de respostas para cada aluno, contendo o seu número e suas
respostas.
Solução em C
Solução em Pascal
Solução em C
Solução em Pascal
6. (COMP 89) Dados dois strings (um contendo uma frase e outro
contendo uma palavra), determine o número de vezes que a palavra
ocorre na frase.
Exemplo:
Para a palavra ANA e a frase :
ANA E MARIANA GOSTAM DE BANANA (2)
Temos que a palavra ocorre 4 vezes na frase.
Solução em Pascal
Exemplo: n = 8
Seqüência: -1.7, 3.0, 0.0, 1.5, 0.0, -1.7, 2.3, -1,7
Saída: -1.7 ocorre 3 vezes
3.0 ocorre 1 vez
0.0 ocorre 2 vezes
1.5 ocorre 1 vez
2.3 ocorre 1 vez
Solução em C
Solução em Pascal
Solução em Pascal
Exemplo: n = 8,
1ª seqüência 8 2 4 3 4 2 5 1
2ª seqüência + 3 3 7 5 2 3 3 7
1 1 6 1 8 6 5 8 8
Solução em Pascal
,
e entre cada duas frações consecutivas
,
introduzimos a fração:
16. (QUIM 84) Dada uma seqüência x1, x2, ..., xk de números inteiros,
verifique se existem dois segmentos consecutivos iguais nesta
seqüência, isto é, se existem i e m tais que:
Solução em C
Solução em Pascal
printf("Digite n: ");
scanf("%d", &n);
printf("n = %d\n", n);
printf("Digite uma sequencia de %d numeros.\n", n);
for (i = 0; i < n; i++) {
scanf("%d", &a[i]);
printf("%d ", a[i]);
}
printf("\n");
inic = 0;
fim = n - 1;
aux = a[inic];
while (inic < fim) {
para = 0;
while ((inic < fim) && !para) {
if (a[fim] <= aux)
para = 1;
else
fim = fim - 1;
}
if (para) {
a[inic] = a[fim];
inic = inic + 1;
para = 0;
while ((inic < fim) && !para) {
if (a[inic] <= aux)
inic = inic + 1;
else
para = 1;
}
if (para) {
a[fim] = a[inic];
fim = fim - 1;
}
}
for (i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
a[inic] = aux;
for (i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
Dados:
7
10 3 6 12 13 7 15
Resultado da Simulação