Exame de Programa¸
c˜
ao Estruturada (A) — 2006.06.16
UMA RESOLUC
¸ ˜
AO (VERS ˜
AO A)
1.
Resposta:
static int indicevogal(int c) { switch(c) {
case ’A’:
case ’a’: return 0; case ’E’:
case ’e’: return 1; case ’I’:
case ’i’: return 2; case ’O’:
case ’o’: return 3; case ’U’:
case ’u’: return 4; default: return -1; }
}
void frequencia(char *nomefin) { int c, n, i;
struct { char vog; int num; } freqabs[5] =
{{’A’,0}, {’E’,0}, {’I’,0}, {’O’,0}, {’U’,0}}; FILE *fp = fopen(nomefin,"r");
if (fp == NULL) {
printf("Erro na abertura do ficheiro %s\n", nomefin); exit(1);
} n = 0;
while ((c = fgetc(fp)) != EOF) {
if ((i = indicevogal(c)) != -1) freqabs[i].num++; n++;
}
fclose(fp); if (n != 0) {
for (i=0; i<5; i++)
printf("%c: %3.0f\045\n",freqabs[i].vog,(100.0*freqabs[i].num)/n); }
}
RESPOSTA ALTERNATIVA:
void frequencia(char *nomefin) { int freq[256]={0}, n, c;
char vogal[5]={’a’,’e’,’i’,’o’,’u’}; FILE *fp = fopen(nomefin,"r"); if (fp == NULL) {
printf("Erro na abertura do ficheiro %s\n", nomefin); exit(1);
n = 0;
while ((c = fgetc(fp)) != EOF) { freq[c]++; n++; } fclose(fp);
if (n != 0) {
for (c=0; c<5; c++)
printf("%c: %3.0f%%\n",vogal[c],(100.0*freq[(unsigned int)vogal[c]])/n); } } 2.
Resposta:
#ifndef FRAC_H #define FRAC_H #include <stdio.h>typedef struct { int num, den; } FRAC; FRAC converter(int);
int zero(FRAC); // retorna 0 se n~ao for void imprimefrac(FRAC); FRAC soma(FRAC,FRAC); FRAC diferenca(FRAC,FRAC); FRAC produto(FRAC,FRAC); FRAC quociente(FRAC,FRAC); #endif 3.
Resposta:
#define DIGITO(D) ((D) >= ’0’ && (D) <= ’9’) FRAC avalia(struct arv *expr)
{ // assume expr != NULL e ´arvore bem constru´ıda FRAC x, y;
if (DIGITO(VALOR(expr))) return converter(VALOR(expr)-’0’); x = avalia(ESQUERDA(expr));
y = avalia(DIREITA(expr)); switch (VALOR(expr)) {
case ’*’: return produto(x,y); case ’+’: return soma(x,y); case ’-’: return diferenca(x,y);
default: if (zero(y)) { printf("ERRO divisao por 0\n"); exit(1); } return quociente(x,y);
} }
4.
Resposta:
O conte´udo de main.c #include <stdio.h> #include <stdlib.h> #include "frac.h"
#include "binarvores.h" #include "expressoes.h" int main()
{ struct arv *expr; char seq[30]; scanf("%s",seq);
expr = constroi_arv_expr(seq); // sup~oe-se definida em expressoes.h if (expr != NULL) { imprimefrac(avalia(expr)); putchar(’\n’); } return 0;
}
O conte´udo de expressoes.h #ifndef EXPRESSOES_H #define EXPRESSOES_H #include <stdio.h> #include <stdlib.h> #include "frac.h" #include "binarvores.h" FRAC avalia(struct arv *);
struct arv *constroi_arv_expr(char *); void imprime_expr(struct arv *); #endif
O ficheiro expressoes.c come¸caria por include "expressoes.h" e teria a seguir o c´odigo das fun¸c˜oes avalia, constroi_arv_expr e imprime_expr, bem como de fun¸c˜oes ou macros auxiliares, que venham a ser definidas para as implementar (como por exemplo, DIGITO(P)). O ficheiro binarvores.h teria essencialmente o que se descreve no enunciado e em binarvores.c estaria o c´odigo das fun¸c˜oes declaradas em binarvores.h (e doutras auxiliares que eventual-mente sejam definidas para as implementar).
——————————————————– FACULTATIVOPor exemplo, em binarvores.h teria #ifndef BINARVORES_H
#define BINARVORES_H #include <stdlib.h> struct arv {
char v;
struct arv *esq, *dir; };
#define VALOR(P) ((P) -> v); #define ESQUERDA(P) ((P) -> esq); #define DIREITA(P) ((P) -> dir);
struct arv *cria_no_arv(char val,struct arv *esquerdo,struct arv *direito); struct arv *remove_no_arv(struct arv *raiz,struct arv *no);
#endif
e em binarvores.c teria #include "binarvores.h" e a implementa¸c˜ao de cria_no_arv e de remove_no_arv.
Teria ainda o ficheiro frac.c onde colocaria #include "frac.h" e o c´odigo das fun¸c˜oes converter, . . . ,produto, quociente declaradas em frac.h.
O conte´udo do ficheiro Makefile era:
progr: binarvores.o expressoes.o main.o frac.o
gcc -o progr binarvores.o expressoes.o main.o frac.o frac.o: frac.c frac.h
gcc -c frac.c
binarvores.o: binarvores.c binarvores.h gcc -c binarvores.c
expressoes.o: frac.h binarvores.h expressoes.h expressoes.c gcc -c expressoes.c
main.o: frac.h binarvores.h expressoes.h main.c gcc -c main.c
clean:
rm *.o prog
5. (a)
Resposta:
typedef struct no {int prox; struct no *prox;} GRUPO, *PTR_GRUPO;
(b)
Resposta:
int i = grupos[’G’-’A’] -> pos;
Coloca em i o ´ındice da posi¸c˜ao que o primeiro elemento do grupo definido pela inicial G ocupa em alunos.
printf("%c\n", alunos[i][11]);
Imprime o caracter G (primeiro caracter do nome do aluno atr´as referido). printf("%s\n", &alunos[i][11]);
Imprime o nome do aluno que est´a na primeira posi¸c˜ao do grupo G. PTR_GRUPO lst = grupos[’G’-’A’];
Coloca em lst o endere¸co do primeiro n´o da lista que define o grupo G. printf("%s\n", alunos[lst -> prox ->pos]);
Imprime a informa¸c˜ao dispon´ıvel sobre o aluno que est´a na segunda posi¸c˜ao no grupo G. (c)
Resposta:
static void ordena(char *alunos[],int nalunos,struct no *grupos[26]) { int i;
agrupa(alunos,nalunos,grupos); for (i=0; i<26; i++)
grupos[i] = ordenaGrupo(grupos[i],alunos); }
(d)
Resposta:
void ordena_imprime(char *alunos[],int nalunos) { int i;
PTR_GRUPO grupos[26], aux; ordena(alunos,nalunos,grupos); for(i=0; i<26; i++) {
aux = grupos[i]; while(aux != NULL) {
printf("%s\n", alunos[aux -> pos]); aux = aux -> prox;
} } }
(e)
Resposta:
static void agrupa(char *alunos[],int nalunos, PTR_GRUPO grupos[26]) { int i;
for (i=0; i < 26; i++) grupos[i] = NULL; for (i=0; i < nalunos; i++)
grupos[Alunos[i][11]-’A’] = cria_no(i,grupos[Alunos[i][11]-’A’]); }
static PTR_GRUPO cria_no(int i, PTR_GRUPO g) { PTR_GRUPO novo = malloc(sizeof(GRUPO));
if (novo != NULL) { novo -> pos = i; novo -> prox = g; return novo; }
printf("Sem memoria\n"); exit(1); }
(f)
Resposta:
Por adapta¸c˜ao do algoritmo quicksort dado na disciplina. static PTR_GRUPO ordenaGrupo(PTR_GRUPO lstg,char *alunos[]) { PTR_GRUPO lmenor, lmaior_ig;if (lstg == NULL) return NULL;
parte(lstg -> prox, lstg -> pos, &lmenor, &lmaior_ig,alunos); lmenor = ordenaGrupo(lmenor,alunos);
lmaior_ig = ordenaGrupo(lmaior_ig,alunos); lstg -> prox = lmaior_ig;
return concatena(lmenor,lstg); }
static void parte(PTR_GRUPO g,int i,PTR_GRUPO *lm,PTR_GRUPO *lMi,char *als[]) { *lm = *lMi = NULL; PTR_GRUPO aux; while(g != NULL) { aux = g -> prox; if (ordena_par(als[g->pos],als[i]) < 0) { g -> prox = *lm; *lm = g;
} else { g -> prox = *lMi; *lMi = g;} g = aux;
} }
PTR_GRUPO concatena(PTR_GRUPO lst1, PTR_GRUPO lst2) { if (lst1 == NULL) return lst2;
if (lst2 == NULL) return lst1;
lst1 -> prox = concatena(lst1 ->prox, lst2); return lst1;
}
(g)
Resposta:
Colocar #include <string.h> no cabe¸calho do m´odulo. // #define POR_NOMES#ifdef POR_NOMES
int ordena_par(char *x,char *y) { // por nomes (crescente)
return strcmp(x+11,y+11); // ou return strcmp(&x[11],&y[11]); }
#else
int ordena_par(char *x,char *y) { // por codigos (decrescente) int rescomp; x[10] = y[10] = ’\0’; rescomp = strcmp(x,y); x[10] = y[10] = ’ ’; return -rescomp; } #endif
As duas vers˜oes ficam protegidas da forma indicada atr´as por directivas para o pr´e-processador: #ifdef POR_NOMES ... #else ... #endif. Se for retirado o coment´ario de // #define POR_NOMES e compilado o programa, a ordena¸c˜ao ser´a por ordem lexi-cogr´afica crescente de nomes. Caso contr´ario, ´e por ordem decrescente de c´odigos. Em alternativa, para evitar recompilar o programa e/ou para poder efectuar ordena¸c˜oes por v´arios crit´erios no mesmo programa, poder-se-ia ter colocado mais um parˆametro nas fun¸c˜oes ordenaGrupo, parte, ordena e ordena_imprime, para passar a ter (um apontador para) a fun¸c˜ao de ordena¸c˜ao como parˆametro dessas fun¸c˜oes. Por exemplo,
void ordena_imprime(char *alunos[],int nalunos,int (*ordlin)(char*, char*)) A fun¸c˜ao parte passaria a ser declarada por
static void parte(PTR_GRUPO g,int i,PTR_GRUPO *lm,PTR_GRUPO *lMi, char *als[], int (*ordlin)(char*, char*)) e, na sua defini¸c˜ao, substituiriamos a instru¸c˜ao
if (ordena_par(als[g->pos],als[i]) < 0) { por
if (ordlin(als[g->pos],als[i]) < 0) {
Deste modo, ´e poss´ıvel definir v´arios crit´erios para ordenar duas linhas (implementados por fun¸c˜oes com nomes distintos) e especificar em cada chamada de ordena_imprime qual a fun¸c˜ao que far´a a ordena¸c˜ao de duas linhas. Por exemplo, se as fun¸c˜oes que implementam os dois crit´erios acima tratados passassem a ser designadas por ordena1 e ordena2, podiamos chamar consecutivamente:
ordena_imprime(alunos,nalunos,ordena1); ordena_imprime(alunos,nalunos,ordena2);