Programação — MEEC — 2º Semestre
1o Exame — 11 de Junho de 2011
Duração: 3h00
1. (5.0 valores)
1.a) (4.0 valores)
O código seguinte tem erros e como tal não faz o que aparece descrito no comentário. Identifique
cada um dos erros sintácticos e lógicos indicando a linha onde ocorre.
Identifique os erros e sugira uma correcção possível para cada um.
Pressuponha que foram feitos todos os includes necessários.
Identifique o erro indicando as suas consequências, e JUSTIFIQUE TODAS CORRECÇÕES
1) /* Programa que lê do teclado uma string e conta o
2)
número de dígitos aí presentes*/
3) int main(){
4)
int linha[100];
5)
int I;
6)
int c;
7)
8)
printf("Escreva uma frase\n");
9)
fgets(linha, 1024, stdin);
10)
11) while(i<100){
12)
if(linha(i) >0 && linha(i) < 9){
13)
c = c+1;
14)
i=i+1;
15) }
16) printf("foram lidos o $d digitos",c);
17) exit(0);
18)}
•
•
•
•
•
•
•
•
Linha 4 – a declaração da linha deve usar o tipo char. Uma string é um vector de caracteres e
não de inteiros.
Linha 4 – o comprimento da string é muito pequeno: o fgets pode ler até 1024 caracteres. Ou se
aumenta o comprimento da string ou se reduz o valor no fgets
Linha 5 – durante o programa usa-se a variável i minúsculo e não I maiúsculo. Ou se altera a
declaracção da variável (na linha 5 ou se muda no código i para I) .
Linha 10 - é necessário inicializar a variável c, caso contrário o contador não fica com o
resutado certo (a variável b pode conter “ lixo”).
Linha 10 - é necessário inicializar a variável i, caso não se acede às posições correctas do
vector (a variável i pode conter “ lixo”)
Linha 11 – Não se pode percorrer o vector até à última posição (100 ou 1024) é necessario
terminar na último caracter lido (i< strlen(linha) ou linha[i] != '\0')
Linha 12 – o acesso às posições de um vector não é representado por parenteses curvos mas
sim rectos. Daria erro de compilação.
Linha 12 – é necessário usar a plicas à volta do 0 e do 9. Assim estamos a comparar com os
inteiros, mas quer-se comparar com os caracteres '0' e '9'.
•
•
•
Linha 12 – as comparações que se usam < e > devem ser substituídas por <= e >=. Se tal não
acontecer os dígitos '0' e '9' não são contabilizados.
Linha 13/14 – falta uma chaveta entre c = c+1; e i=i+1; . A ausência de chaveta provoca um
erro de compilação, visto haver mais chavetas { do que } .Só queremos a instrução c = c+1;
dentro do if.
Linha 16 – dentro do printf usa-se %d ( e não $d) para indicar que se deseja escrever um
inteiro. Se não se resolvesse esta questão, não seria impresso o valor de c, mas sim $d.
/* Programa que lê do teclado uma string e conta o
número de dígitos aí presentes*/
int main(){
char linha[1024];
int i;
int c;
1)
2)
3)
4)
5)
6)
7)
8)
9)
10)
11)
12)
13)
14)
15)
16)
17)
18)
19)
printf("Escreva uma frase\n");
fgets(linha, 1024, stdin);
c = 0; i = 0;
while(i< strlen(linha)){
if(linha[i] >= '0' && linha[i] <= '9'){
c = c+1;
}
i=i+1;
}
printf("foram lidos o %d digitos",c);
exit(0);
}
1.b)(1.0 valores)
Observe o seguinte troço de código. Identifique e explique o seu problema. Sugira uma solução.
int main(){
char linha[1024];
char palavra1[20];
...
sscanf(linha, "%s %s", palavra1);
...
}
•
•
O comprimento da linha é muito superior ao comprimento da palavra 1. Se a primeira palavra
escrita tiver mais de 20 caracteres é possível que outras variáveis sejam corrompidas
O sscanf tem dois %s mas apenas uma variável onde vão ser armazenados os valores. Ou se
retira um %s ou se adiciona uma variável dentro do scanf.
2. (4.5 valores)
2.a) (2.0 valores)
Desenvolva uma função que recebe como argumento um vector de 100 inteiros, calcula a sua
média e desvio padrão.
O cabeçalho dessa função deve ser
 void media_desvio(int vect[100], float * media, float * desvio);
A fórmula genérica para o desvio padrão é:
 desvio=
√
n
1
∑ ( x −media )2
n−1 i=1 i
#define MAX_VECT 10
float media_vect (int v[MAX_VECT]){
float sum= 0;
int i = 0;
for (i = 0; i <MAX_VECT; i++){
sum = sum+ v[i];
}
return sum / MAX_VECT;
}
void media_desvio(int vect[MAX_VECT], float * media, float * desvio){
float desv, med;
int i;
med = media_vect(vect);
desv = 0;
for (i = 0; i < MAX_VECT; i++){
desv = desv + pow(med- vect[i], 2);
}
desv = desv/(MAX_VECT-1);
*desvio = sqrt(desv);
*media = med;
}
2.b) (2.5 valores)
Desenvolva um programa que lê 100 inteiros a partir do ficheiro chamado dados.dat e calcula,
usando a função anterior, a média desses valores.
Em cada linha do ficheiro deve aparecer um inteiro. Se a linha não tiver um inteiro, deverá ser
ignorada e impressa uma mensagem de erro. Se a linha tiver mais caracteres para além do inteiro
deverá unicamente ser impressa uma mensagem de aviso ( número será posteriormente utilizado).
Se o ficheiro contiver mais de 100 inteiros, deverá ser impressa uma mensagem de aviso e
calculada a média dos 100 primeiros. Se o ficheiro contiver menos de 100 inteiros deverá ser impressa
uma mensagem de erro e sair (sem calcular a média).
int main(){
FILE * fp;
char linha [1024];
int cont_linhas = 0;
int valor;
char caracter_lixo;
int vect[MAX_VECT];
float media, desvio;
int n;
fp = fopen("dados.txt", "r");
if(fp == NULL){
printf("ficheio inexistente\n");
exit(0);
}
while( fgets(linha, 1024, fp)!= NULL){
n = sscanf(linha, "%d %c", & valor, & caracter_lixo);
if( n == 1){
if(cont_linhas < MAX_VECT)
vect[cont_linhas] = valor;
cont_linhas ++;
}
if( n > 1){
printf(" linha com lixo no fim!\n");
if(cont_linhas < MAX_VECT)
vect[cont_linhas] = valor;
cont_linhas ++;
}
if( n == 0){
printf(" linha sem inteiro!\n");
}
}
if(cont_linhas < MAX_VECT){
printf("ficheiro com menos que %d linhas correctas!(so %d)\n",
MAX_VECT, cont_linhas);
}else{
if(cont_linhas > MAX_VECT){
printf("ficheiro com mais que %d linhas correctas!(so %d)\n",
MAX_VECT, cont_linhas);
}
media_desvio(vect, &media, &desvio);
printf("media %f \ndsvio %f\n", media, desvio);
}
exit(0);
}
3. (5.0 valores)
3.a) (0.5 valores)
Defina o tipo quadrado, que permite guardar a informação de quadrados: coordenada do centro e
comprimento do lado.
typedef struct quadrado{
float x, y;
float largura;
} quadrado;
ou
typedef struct coord{
float x, y;
} coord;
typedef strcut quadrado{
coord centro;
float largura;
}
ou
struct quadrado{
float x, y;
float largura;
}
3.b) (0.5 valores)
Defina uma função que recebe como argumento um quadrado e retorna a sua área.
float area_quadrado(quadrado q){
return q.largura * q.largura;
}
3.c) (1.0 valores)
Defina uma função que recebe como argumento um quadrado e um ponto e retorna verdadeiro se
esse ponto se encontrar dentro do quadrado e falso caso contrário.
Pressuponha que os lados dos quadrados são paralelos aos eixos x e y.
int dentro_quadrado(quadrado q, float p_x, float p_y){
if(p_x > q.x+q.largura/2 || p_x > q.x-q.largura/2)
return 0;
if(p_y > q.y+q.largura/2 || p_y > q.y-q.largura/2)
return 0;
return 1;
}
ou
int dentro_quadrado(quadrado q, float p_x, float p_y){
if(p_x > q.x+largura/2 && p_x < q.x-largura/2 &&
p_y < q.y+largura/2 && p_y < q.y-largura/2)
return 1;
else
return 0;
}
3.d) (1.5 valores)
Desenvolva uma função que recebe como argumento dois quadrados e retorna verdadeiro se esse
quadrados se interceptarem e falso caso contrário.
Pressuponha que os lados dos quadrados são paralelos aos eixos x e y.
int intersecta(quadrado q1, quadrado q2){
if(abs(q1.x -q2.x) > (q1.largura + q2.largura)/2){
return 0;
}
if(abs(q1.y -q2.y) > (q1.largura + q2.largura)/2){
return 0;
}
return 1;
}
ou
int intersecta(quadrado q1,
if(q1.x - q1.largura/2
q1.x + q1.largura/2
return 0;
if(q1.y - q1.largura/2
q1.y + q1.largura/2
return 0;
return 1;
}
quadrado q2){
> q2.x + q2.largura/2 ||
< q2.x - q2.largura/2)
> q2.y + q2.largura/2 ||
< q2.y - q2.largura/2)
3.e) (1.5 valores)
Defina uma função que recebe como argumento um vector de 100 quadrados e calcula quantos
desses quadrados se interceptam entre si.
Pressuponha que os lados dos quadrados são paralelos aos eixos x e y.
int cont_intercep(quadrado vect[100]){
int i, j;
int contador = 0;
for (i = 0 ; i< 100; i++){
for (j = i+1 ; i< 100; j++){
if( intersecta( vect[i],vect[j]) ){
contador ++;
}
}
}
return contador;
}
4. (5.5 valores)
Nas repartições de finanças usam-se sistemas de senhas em papel para ordenar os utentes.
Pretende-se substituir estes sistemas por um mais avançado em que, quando chega à repartição, o
utente apenas inseres o seu nome e selecciona os serviços pretendidos, sendo posteriormente chamado
por um altifalante.
Este sistema utiliza uma fila de utentes, ordenada por ordem de chegada, contendo, para além do
nome, o serviço que pretende usar.
Os serviços são numerados entre 1 e 6.
A fila contém todos os utentes, independentemente do serviço pelo qual estão à espera.
4.a) (0.5 valores)
Declare os tipos necessários ao armazenamento da fila de espera de utentes.
typedef struct utente{
char nome [100];
int servico;
struct utente *proximo;
}utente;
4.b) (1.0 valores)
Desenvolva a função que permite inserir na fila de espera um novo utente: nome e serviço
pretendido. Esta função não lê nenhuma informação do teclado.
utente * insere_utente(utente * fila, char * nome, int servico){
utente * aux;
utente * novo;
novo = malloc(sizeof(utente));
if(novo == NULL){
printf("ERRO\n");
exit(-1);
}
strcpy(novo->nome, nome);
novo->servico = servico;
novo->proximo = NULL;
if(fila == NULL){
return novo;
}
aux = fila;
while(aux->proximo != NULL){
aux = aux-> proximo;
}
aux->proximo = novo;
return fila;
}
4.c) (1.0 valores)
Desenvolva a função que permite interagir com o utente na altura da sua entrada na repartição:
leitura do nome, leitura dos vários serviços pretendidos e inserção na fila. Esta função recebe como
argumento a fila. Esta pode ser passada por referência ou retornada no fim.
Esta função lê do teclado o nome do utente e os vários serviços pretendidos.
utente * entrada_utente(utente * fila){
char nome[100];
char linha[100];
int i;
printf("Nome do utente: ");
fgets(nome, 100, stdin);
for(i= 1; i<= 6; i++){
printf("pretende servico %d? (sim/nao): ", i);
fgets(linha, 100, stdin);
if(strcmp(linha, "sim\n") == 0){
fila = insere_utente(fila, nome, i);
}
}
return fila;
}
4.d) (1.0 valores)
Desenvolva a função que permite “chamar” o próximo utente a ser atendido. Esta função recebe
como argumento a fila e o número do serviço. Depois de encontrar na fila o próximo utente a ser
atendido, imprime o seu nome no écran e retira-o da fila.
utente * chama_utente(utente * fila, int servico){
utente * prox;
utente * ant;
if(fila == NULL){
return fila;
}
if(fila->servico == servico){
prox = fila;
fila = fila->proximo;
printf("PROXIMO UTENTE: %s\nSERVICO: %d\n",
prox->nome, prox->servico);
free(prox);
return fila;
}
ant = fila;
prox = fila->proximo;
while(prox != NULL && prox->servico != servico){
prox = prox->proximo;
ant = ant->proximo;
}
if(prox!= NULL){
ant->proximo = prox->proximo;
printf("PROXIMO UTENTE: %s\nSERVICO: %d\n", prox->nome,
prox->servico);
free(prox);
}
return fila;
}
4.e) (1.0 valores)
Desenvolva a função que imprime o número de utentes em espera para cada serviço.
void estatistica (utente * fila){
int i, cont;
utente * aux;
for (i = 1; i <=6; i++){
cont = 0;
aux = fila;
while( aux != NULL){
if(aux->servico == i){
cont ++;
}
aux = aux-> proximo;
}
printf("SERVICO %d - UTENTES EM ESPERA %d\n", i, cont);
}
}
4.f) (1.0 valores)
Quando um utente está a ser atendido e é chamado por outro serviço, perde a vez visto o sistema
não o conseguir pôr em espera.
Descreva textualmente quais as alterações que seria necessário realizar, para que o sistema
conseguisse colocar um utilizador em espera, sendo posteriormente chamado quando deixasse de ser
atendido.
Indique:
 Alterações ao tipo de dados
 Funções adicionais que seriam necessárias
 Alterações às funções já implementadas
•
•
•
•
As estruturas que armazenam os utentes em fila de espera necessitam de um atributo adicional
(chamado estado) que indica se esse utente está a ser atendido ou não. Seria um booleano que
seria inicializado a Falso.
Quando é chamado um utente para um servicó (função da alínea 4.d seria necessário verificar
se o próximo utente para o serviço pretendido) estava nesse momento a ser ratendido noutro
serviço (estado a Verdadeiro). Em caso positivo, chamar-se-ia o utente seguinte na fila.
Quando um utente é chamado para um serviço é necessário actualizar o estado desse utente na
fila, mudando o campo estado para verdadeiro.
Após ser atendido o estado do utente passa a falso, podendo ser chamado para outros serviços
Download

Programação — MEEC — 2º Semestre