Gabarito de Lista de Exercícios
Solução:
#include <stdio.h>
#include <math.h> /* Para as funcoes de raiz e potencia
*/
struct ponto
{
int x;
int y;
};
void le_ponto(struct ponto *p, char *);
float dist(struct ponto p1, struct ponto p2);
void main(void)
{
struct ponto p1, p2;
printf("\nDistancia entre os pontos:\n");
le_ponto(&p1, "primeiro");
le_ponto(&p2, "segundo");
printf("\n\nDistancia entre os pontos: %5.2f\n", dist(p1, p2));
}
void le_ponto(struct ponto *p, char *s)
{
int x, y;
printf("Digite a posicao do %s ponto (x,y): ", s);
scanf("%d%d", &x, &y);
p->x = x;
p->y = y;
}
float dist(struct ponto p1, struct ponto p2)
{
float s1, s2;
s1 = pow(p1.x-p2.x, 2); /* Funcao pow(x,y) retorna
x^y */
s2 = pow(p1.y-p2.y, 2);
return sqrt( s1 + s2); /* Funcao sqr(x)
retorna a
raiz quadrada de x */
}
Solução:
#include <stdio.h>
#include <math.h>
typedef struct _ponto /* Aqui usa-se typedef para dar o nome
*/
{
/* desejado ao tipo */
int x;
int y;
} ponto;
typedef struct _retangulo /* Idem anterior */
{
ponto sup_esq;
ponto inf_dir;
} retangulo;
void le_ponto(ponto *p, char *);
float diagonal(retangulo r);
int area(retangulo r);
void arestas(retangulo r);
void main(void)
{
retangulo r;
printf("\nPontos do retangulo:\n");
le_ponto(&(r.sup_esq), "primeiro");
le_ponto(&(r.inf_dir), "segundo");
printf("\n\nDiagonal do retangulo: %5.2f\n", diagonal(r));
printf("\nArea do retangulo: %d", area(r));
arestas(r);
}
void le_ponto(ponto *p, char *s)
{
int x, y;
printf("Digite a posicao do %s ponto (x,y): ", s);
scanf("%d%d", &x, &y);
p->x = x;
p->y = y;
}
float diagonal(retangulo r)
{
float s1, s2;
s1 = pow(r.sup_esq.x - r.inf_dir.x, 2);
s2 = pow(r.sup_esq.y - r.inf_dir.y, 2);
return sqrt( s1 + s2);
}
int area(retangulo r)
{
return ((r.sup_esq.x - r.inf_dir.x) * (r.sup_esq.y - r.inf_dir.y));
}
void arestas(retangulo r)
{
printf("\nArestas:");
printf("\nAresta 1: %d", abs(r.sup_esq.x-r.inf_dir.x));
printf("\nAresta 2: %d", abs(r.sup_esq.y-r.inf_dir.y));
}
Comentários:
A função abs(x) retorna o módulo (valor
absoluto) de x. Está na biblioteca <math.h>.
Exercício 2:
Use as estruturas declaradas no exemplo da pagina cB10.html
(ficha_pessoal e tipo_endereco). Faça um programa que controle um
arquivo, contendo informações
sobre pessoas. O programa deverá incluir novos nomes no arquivo,
ler e alterar nomes que estejam armazenados.
Solução:
#include <stdio.h>
#include <string.h>
/* -------- Definicao dos tipos a serem usados */
typedef struct tipo_endereco /* Tipo tEndereco:
*/
{
/* Dados relativos ao endereco */
char rua [50];
int numero;
char bairro [20];
char cidade [30];
char sigla_estado [4];
long int CEP;
} tEndereco;
typedef struct ficha_pessoal /* Tipo tPessoal:
*/
{ /* Dados
da pessoa */
char nome [50];
/* A ficha da pessoa sera */
char telefone[20];
/* uma variavel do tipo tPessoal */
tEndereco endereco;
} tPessoal;
typedef struct _lista
/* Tipo tLista: */
{ /* Armazena
uma lista de fichas. */
tPessoal *fichas;
/* *Nao* e uma implementacao */
int tamanho;
/* de uma lista encadeada */
} tLista;
/* ----------- Prototipos das funcoes */
tLista ad_reg(tLista);
void find(tLista);
void altera(tLista);
tLista le_arquivo(FILE *);
void salva(FILE *, tLista);
void le_reg(tPessoal *);
void le_str(char *s, int n, FILE *arq);
void imprime(tPessoal);
/* ----------------------------------------------------------
Programa principal
----------------------------------------------------------
*/
void main(void)
{
char n_arq[30]; /* Nome do arquivo a ser manipulado
*/
FILE *fonte; /* Arquivo a ser
manipulado */
int opcao; /* Opcao
escolhida no Menu */
tLista lista; /* Lista de registros
(ver definicao de tLista */
char c;
/* Utilidade geral */
printf("\n\n Gerenciador de dados: Versao 1.0");
printf("\n --------------------------------");
/* --> Le o nome da lista com a qual vai trabalhar */
do
{
printf("\n\n Entre com o nome do arquivo de dados: ");
gets(n_arq);
fonte = fopen(n_arq, "r");
}
while (fonte == NULL);
/* --> Le o arquivo e guarda na memoria */
lista = le_arquivo(fonte);
fclose(fonte);
if (lista.fichas == NULL)
{
printf("\nErro! Nao e possivel ler e armazenar a lista!!");
exit(0);
}
/* --> Comeca o loop principal */
do
{
printf("\n\n 1 - Insere novo registro");
printf("\n 2 - Procura registro gravado");
printf("\n 3 - Altera registro");
printf("\n 0 - Abandona a execucao");
printf("\n\n Entre com sua opcao: ");
scanf("%d%c", &opcao, &c);
/* Le a opcao */
switch(opcao)
{
case 1:
lista =
ad_reg(lista);
break;
case 2:
find(lista);
break;
case 3:
altera(lista);
break;
}
}
while (opcao != 0);
/* --> Salva arquivo na saida */
if ((fonte = fopen(n_arq, "w")) != NULL)
{
salva(fonte, lista);
fclose(fonte);
}
else
printf("\n\nERRO! Alteracoes nao foram salvas!!\n");
}
/* ---------------------------------------------------------
Definicao das funcoes:
---------------------------------------------------------
*/
/* ---------------------------------------------------------
Funcao ad_reg: Adiciona um registro a lista
Para tanto, ela cria uma segunda lista com o novo
registro
no topo e os demais sao copiados nas posicoes seguintes.
*/
tLista ad_reg(tLista lista)
{
tPessoal ficha;
tLista nova_lista;
int i;
/* Le o novo registro */
printf("\n\n---------Inserir Registro:");
le_reg(&ficha);
/* Primeiro aloca a memoria necessaria para a nova lista... */
nova_lista.tamanho = lista.tamanho + 1;
if ((nova_lista.fichas = (tPessoal *) calloc(nova_lista.tamanho,
sizeof(tPessoal))) == NULL)
{
printf("\n\nProblemas de memoria: Impossivel acrescentar
o registro..\n");
return lista;
}
/* Copia o novo registro... */
memcpy(&(nova_lista.fichas[0]), &ficha, sizeof(tPessoal));
/* Copia os registros antigos... */
for( i=1; i<nova_lista.tamanho; i++)
memcpy(&(nova_lista.fichas[i]), &(lista.fichas[i-1]),
sizeof(tPessoal));
/* Libera a memoria da primeira lista.. */
free(lista.fichas);
/* retorna a nova lista */
return nova_lista;
}
/* -------------------------------------------------------
Funcao find: Encontra uma expressao de procura na
lista.
A expressao sera comparada somente com o campo nome.
*/
void find(tLista lista)
{
int i, resp = -1;
char exp[50], *s;
/* Solicita a expressao de busca */
printf("\n\nDigite a expressao de busca: ");
gets(exp);
if ((s = strchr(exp, '\n')) != NULL) /* retira o \n se houver
*/
s[0] = '\0';
/* Varre a lista procurando a primeira ocorrencia da expressao */
for(i=0; i<lista.tamanho; i++)
if ((strstr(lista.fichas[i].nome, exp)) != NULL)
{
resp = i;
break;
}
if (resp < 0)
printf("\nExpressao nao encontrada.");
else
{
printf("\nExpressao encontrada no registro %d",
resp+1);
imprime(lista.fichas[resp]);
}
}
/* --------------------------------------------------------
Funcao altera: altera um registro baseado na sua posicao
na lista. Para fazer a alteracao, a pessoa devera
saber qual
posicao do registro na lista (pode ser conseguida
atraves da
funcao find, acionada pela opcao 1 do menu).
A funcao altera le o novo registro do teclado e o
substitui
na posicao desejada.
*/
void altera(tLista lista)
{
int n;
char c;
tPessoal aux;
printf("\nDigite o numero do registro que deseja alterar: ");
scanf("%d%c", &n, &c); /* Le o numero do registro
e o lixo do buffer */
/* Le o novo registro */
printf("\nDigite o novo registro:\n");
le_reg(&aux);
/* Atualiza na lista */
memcpy(&(lista.fichas[n-1]), &aux, sizeof(tPessoal));
printf("\nRegistro alterado.\n");
}
/* ---------------------------------------------------------
Funcao le_arquivo: Recebe um apontador para o arquivo
aberto
e retorna uma lista montada a partir do arquivo
*/
tLista le_arquivo(FILE *arq)
{
tLista l;
tPessoal ficha;
int i;
char c, *s;
/* Le o tamanho do arquivo (qtos registros possui) */
fscanf(arq,"%d", &(l.tamanho));
/* Aloca a memoria necessaria para armazenar o arquivo
em RAM e em seguida le registro por registro
*/
if ((l.fichas = (tPessoal *) calloc(l.tamanho, sizeof(tPessoal)))
!= NULL)
for (i=0; i<l.tamanho; i++)
{
/* Le cada ficha */
c = getc(arq); /* Para o cursor mudar
de linha no arquivo */
le_str(ficha.nome, 50, arq);
le_str(ficha.telefone, 20, arq);
le_str(ficha.endereco.rua, 50, arq);
fscanf(arq,"%d\n", &(ficha.endereco.numero));
le_str(ficha.endereco.bairro, 20, arq);
le_str(ficha.endereco.cidade, 30, arq);
le_str(ficha.endereco.sigla_estado, 3, arq);
fscanf(arq,"%d", &(ficha.endereco.CEP));
while ((c = getc(arq)) !='$'); /* Sincronismo!
*/
memcpy(&(l.fichas[i]), &ficha, sizeof(tPessoal));
if (feof(arq)) i = l.tamanho;
}
/* retorna a lista criada */
return l;
}
/* -----------------------------------------------------------
Funcao salva: salva a lista l no arquivo arq, observando
a
sintaxe necessaria para o arquivo de leitura. Ao final,
libera a memoria da lista
*/
void salva(FILE *arq, tLista l)
{
int i;
fprintf(arq,"%d\n", l.tamanho);
for (i = 0; i<l.tamanho; i++)
{
fprintf(arq,"%s\n", l.fichas[i].nome);
fprintf(arq,"%s\n", l.fichas[i].telefone);
fprintf(arq,"%s\n", l.fichas[i].endereco.rua);
fprintf(arq,"%d\n", l.fichas[i].endereco.numero);
fprintf(arq,"%s\n", l.fichas[i].endereco.bairro);
fprintf(arq,"%s\n", l.fichas[i].endereco.cidade);
fprintf(arq,"%s\n", l.fichas[i].endereco.sigla_estado);
fprintf(arq,"%d\n", l.fichas[i].endereco.CEP);
fprintf(arq,"$\n");
}
free(l.fichas);
}
/* -----------------------------------------------------------
Funcao le_reg: le um registro via teclado
*/
void le_reg(tPessoal *reg)
{
tPessoal ficha;
char c;
printf("\n\nNome: ");
gets(ficha.nome);
printf("Telefone: ");
gets(ficha.telefone);
printf("\nEndereco");
printf("\nRua: ");
gets(ficha.endereco.rua);
printf("Numero: ");
scanf("%d", &(ficha.endereco.numero));
scanf("%c", &c); /* Para absorver o \n que fica
no buffer */
printf("Bairro: ");
gets(ficha.endereco.bairro);
printf("Cidade: ");
gets(ficha.endereco.cidade);
printf("Sigla do Estado: ");
gets(ficha.endereco.sigla_estado);
printf("CEP: ");
scanf("%d", &(ficha.endereco.CEP));
scanf("&c", &c);
memcpy(reg, &ficha, sizeof(tPessoal));
}
/* ----------------------------------------------------------
Funcao le_str: le uma string em um arquivo e faz as
devidas correcoes.
Se a string lida possuir um final de linha ('\n'),
a funcao
o localiza e o retira
*/
void le_str(char *s, int n, FILE *arq)
{
fgets(s, n, arq);
if ((s = strchr(s, '\n')) != NULL)
s[0] = '\0';
}
/* ----------------------------------------------------------
Funcao imprime: Imprime Uma ficha na tela
*/
void imprime(tPessoal f)
{
printf("\n%s\n", f.nome);
printf("%s\n", f.telefone);
printf("%s\n", f.endereco.rua);
printf("%d\n", f.endereco.numero);
printf("%s\n", f.endereco.bairro);
printf("%s\n", f.endereco.cidade);
printf("%s\n", f.endereco.sigla_estado);
printf("%d\n\n", f.endereco.CEP);
}
Comentários:
Como diria um amigo meu: 'Que programão!'. Sem dúvida
este ficou o exercício mais completo e abrangente do nosso curso,
e creio que isto é o ideal para uma aula final como esta. Alguns
pontos que merecem especial atenção:
- Funções desconhecidas: Algumas funções
usadas neste programa nunca foram usadas em nosso curso: Deixa eu tentar
explicar cada uma:
+ strchr(char *s, char c): Esta função
retorna um apontador para a primeira ocorrência de c em s,
ou NULL caso não encontre.
+ strstr(char *s1, char *s2): Retorna um apontador
para a primeira ocorrência da cadeia s2 em s1, ou NULL,
se não encontrar.
- Como já mencionamos, o nível de complexidade de um
programa cresce a medida que ele cresce. Este programa tem em torno de
250 linhas, e já é um programa que precisa ser largamente
testado, para se dizer que funciona. Não houve tempo para testá-lo
muito bem (senão verificar se roda perfeitamente), portanto, não
confiem sua agenda telefônica nele. :-)
- Uma solução para este problema que sem dúvida
seria melhor que esta seria a utilização de uma estrutura
de dados chamada "lista encadeada", onde cada registro possui um apontador
para o próximo registro. Antes que alguem pergunte porque eu não
a usei, ja adianto que foi pelo simples fato de que este assunto fugiria
ao escopo do curso que tem por objetivo ser um curso básico de programação.
Como eu não poderia implementar algo aqui e não explicar,
resolvi usar esta estrutura tipo 'vetorial', se é que assim podemos
dizer, e contornar os problemas encontrados. Aos que usaram a lista encadeada,
também é uma solução muito boa (volto a dizer
- melhor), mas requer mais teoria de estrutura de dados, o que não
é pré-requisito de nosso curso.
Exercício 3:
Faça um exercício usando enumeração. Crie
uma enumeração de meses do ano, e a use para indexar um vetor
de nomes dos meses. Desta forma, apresente os nomes dos meses do ano na
tela.
Solução:
#include <stdio.h>
enum mes { JAN, FEV, MAR, ABR, MAI, JUN, JUL, AGO, SET, OUT, NOV,
DEZ };
void main()
{
enum mes index;
char *meses[12] = { "Janeiro", "Fevereiro", "Marco",
"Abril", "Maio", "Junho",
"Julho", "Agosto", "Setembro",
"Outubro", "Novembro", "Dezembro" };
for (index = JAN; index <= DEZ; index++)
printf("\n%s", meses[index]);
}
Exercício 4:
Refaça o exercício 1 usando alocação dinâmica
de memória. Use o comando typedef para definir os tipos ponto e
retângulo.
Solução:
#include <stdio.h>
#include <math.h>
typedef struct _ponto
{
int x;
int y;
} ponto;
typedef struct _retangulo
{
ponto sup_esq;
ponto inf_dir;
} retangulo;
ponto le_ponto(char *);
float diagonal(retangulo *);
int area(retangulo *);
void arestas(retangulo *);
void main(void)
{
retangulo *r;
if ((r = (retangulo *) malloc(sizeof(retangulo))) == NULL)
{
printf("\nMemoria insuficiente! Abortando\n");
exit(0);
}
printf("\nPontos do retangulo:\n");
r->sup_esq = le_ponto("primeiro");
r->inf_dir = le_ponto("segundo");
printf("\n\nDiagonal do retangulo: %5.2f\n", diagonal(r));
printf("\nArea do retangulo: %d", area(r));
arestas(r);
}
ponto le_ponto(char *s)
{
ponto p;
printf("Digite a posicao do %s ponto (x,y): ", s);
scanf("%d%d", &(p.x), &(p.y));
return p;
}
float diagonal(retangulo *r)
{
float s1, s2;
s1 = pow(r->sup_esq.x - r->inf_dir.x, 2);
s2 = pow(r->sup_esq.y - r->inf_dir.y, 2);
return sqrt( s1 + s2);
}
int area(retangulo *r)
{
return ((r->sup_esq.x - r->inf_dir.x) * (r->sup_esq.y - r->inf_dir.y));
}
void arestas(retangulo *r)
{
printf("\nArestas:");
printf("\nAresta 1: %d", abs(r->sup_esq.x-r->inf_dir.x));
printf("\nAresta 2: %d", abs(r->sup_esq.y-r->inf_dir.y));
}
Comentários:
O comando typedef já tinha sido usado no exercício
1 da lista. Assim sendo, a única mudança realizada foi a
inclusão da alocação dinâmica de memória.
Agora, r é um apontador para retângulo, e todas as
alterações no programa foram feitas para suportar isto.
Solução:
#include <stdio.h>
#include <math.h>
#define espaco_branco printf(" ");
#define espaco_cheio printf("#");
#define muda_linha printf("\n");
typedef struct _ponto
{
int x;
int y;
} ponto;
typedef struct _retangulo
{
ponto sup_esq;
ponto inf_dir;
} retangulo;
ponto le_ponto(char *);
float diagonal(retangulo *);
int area(retangulo *);
void arestas(retangulo *);
void resultados(retangulo *);
void main(void)
{
retangulo *r;
if ((r = (retangulo *) malloc(sizeof(retangulo))) == NULL)
{
printf("\nMemoria insuficiente! Abortando\n");
exit(0);
}
printf("\nPontos do retangulo:\n");
r->sup_esq = le_ponto("superior esquerdo");
r->inf_dir = le_ponto("inferior direito");
resultados(r);
}
ponto le_ponto(char *s)
{
ponto p;
printf("Digite a posicao do ponto %s (x,y): ", s);
scanf("%d%d", &(p.x), &(p.y));
return p;
}
float diagonal(retangulo *r)
{
float s1, s2;
s1 = pow(r->sup_esq.x - r->inf_dir.x, 2);
s2 = pow(r->sup_esq.y - r->inf_dir.y, 2);
return sqrt( s1 + s2);
}
int area(retangulo *r)
{
return ((r->sup_esq.x - r->inf_dir.x) * (r->sup_esq.y - r->inf_dir.y));
}
void arestas(retangulo *r)
{
printf("\n\n-----Arestas:");
printf("\n Aresta 1: %d", abs(r->sup_esq.x-r->inf_dir.x));
printf("\n Aresta 2: %d\n\n", abs(r->sup_esq.y-r->inf_dir.y));
}
void resultados(retangulo *r)
{
int i, j;
printf("\n\nDiagonal do retangulo: %5.2f\n\n", diagonal(r));
/* Assumindo que sup_esq.x < inf_dir.x
e que sup_esq.y < inf_dir.y
*/
for (i = r->sup_esq.y;
i < r->inf_dir.y; i++)
{
for (j=0; j<r->sup_esq.x; j++) espaco_branco;
for (j = r->sup_esq.x;
j < r->inf_dir.x; j++)
espaco_cheio;
muda_linha;
}
printf("\nArea do retangulo: %d", area(r));
arestas(r);
}
Comentários:
O programa é o mesmo da questão 4, excetuando-se uma
função criada para gerar a informação gráfica
(fazer o relatório). Um detalhe importante é que a função
pressupõe que os pontos estão corretamente ordenados, ou
seja, que o primeiro ponto tem coordenadas (tanto x quanto y)
menores que as do segundo
ponto. Note também que a leitura mudou em virtude disto.