ASPER
UNIBRATEC

Gabarito da Lista 3

Aula 6: Estruturas de controle de fluxo


Exercício 1:
Enunciado:

Escreva um programa que pede para o usuário entrar um número correspondente a um
dia da semana e que então apresente na tela o nome do dia. utilizando o comando
switch.'.


Solução:
#include <stdio.h>
int main()
{
int dia;

printf("\n\nEntre com o numero do dia da semana: ");
scanf("%d", &dia);
switch(dia)
{
case 1:
printf(" Dia = domingo");
break;

case 2:
printf(" Dia = segunda-feira");
break;
case 3:
printf(" Dia = terca-feira");
break;
case 4:
printf(" Dia = quarta-feira");
break;

case 5:
printf(" Dia = quinta-feira");
break;
case 6:
printf(" Dia = sexta-feira");
break;
case 7:
printf(" Dia = sabado");
break;
default:
printf(" Voce deve digitar um numero entre 1 e 7!!! --> Dia invalido!");
}
return 0;
}

Exercício 2:
Enunciado:

Faça um programa que inverta uma string: leia a string com gets e armazene-a
invertida em outra string. Use o comando for para varrer a string até o seu
final.


Solução:
Neste exercício existem alguns detalhes interessantes. Primeiramente, é
necessário determinar-se o tamanho da string. Isto é feito através de um
primeiro for. Algumas pessoas não conseguiram chegar ao resultado por causa de
um pequeno detalhe na 'linha em destaque'. Lembre-se sempre que se você tem um
string de 10 posições, o seu índice pode variar de 0 a 9, e o '\0' vai estar na
posição 9. Logo, você deve inverter a posição 8 com a 0, 7 com a 1, e assim por
diante. É por isto que a expressão fica:
copia[i] = str[compstr-i-1]
Não podemos também deixar de colocar o '\0' no final da nova string.
#include <stdio.h>
#define MAX 31
int main()
{
char str[MAX], copia[MAX];
int i, compstr;
printf("\n\nEntre com uma string (max 30 caracteres): ");
gets(str);
/* Determina o comprimento da string atraves
de um for sem conteudo : ao final dele, compstr
contem a posicao do '\0' da string*/
for(compstr=0; str[compstr]; compstr++);

/* Inverte a string */
for(i=0; str[i]; i++)
{
copia[i] = str[compstr-i-1]; /* Linha em destaque */
}
copia[i] = '\0'; /* coloca um
finalizador na string */
printf("\n\nString Invertida: %s\n", copia);
return 0;
}


Exercício 3:
Enunciado:

Refaça o programa da página anterior. Use o comando while para fechar o loop.


Solução:
Como o comando while não tem o incremento próprio, precisamos fazê-lo dentro do
seu loop. Outra observação importante é a necessidade de se inicializar a
variável com i = 0.
Entao temos:
#include <stdio.h>
#define MAX 31
int main()
{
char str[MAX], copia[MAX];
int i = 0, compstr;
printf("\n\nEntre com uma palavra (max 30 caracteres): ");
gets(str);
/* Determina o comprimento da string atraves
de um for sem conteudo : ao final dele, compstr
contem a posicao do '\0' da string*/
for(compstr=0; str[compstr]; compstr++);
while (str[i] != '\0')
{
copia[i] = str[compstr-i-1]; /* Linha em destaque */
i++;
}
copia[i] = '\0';
printf("\n\nString Invertida: %s\n", copia);
return 0;
}


Exercício 4:
Enunciado:

Refaça o exercício da página c410.html utilizando o laço do-while para controlar
o fluxo.


Solução:
É preciso inicializar a variável contador, para garantir o resultado desejado. O
incremento também tem que ser feito explicitamente.
#include <stdio.h>
int main()
{
int index = 0, contador = 0;
char letras[5] = "Joao";
do
{
printf("\n%c",letras[index]);
if (( contador % 5 ) == 4) /* Se o resto da divisão == 4, entao incrementa
*/
(index == 4)? index=0: ++index;
contador ++;
} while (contador < 1000);
return 0;
}


Exercício 5:
Enunciado:

Escreva um programa que peça ao usuário que digite três números inteiros,
correspondentes a dia , mês e ano. Teste os números recebidos, e em caso de
haver algum inválido, repita a leitura até conseguir valores que estejam na
faixa correta (dias entre 1 e 31, mês entre 1 e 12 e ano entre 1900 e 2100).
Verifique se o mês e o número de dias batem (incluindo verificação de anos
bissextos). Se estiver tudo certo imprima o número que aquele dia corresponde no
ano. Comente seu programa.
Obs: Um ano é bissexto se for divisível por 4 e não for divisível por 100,
exceto para os anos divisíveis por 400, que também são bissextos.


Solução:
Este já é um programa mais trabalhoso e exige um pouco mais de paciência e
atenção. Apresentam-se algumas possíveis soluções para o problema. A primeira
versão foi apresentada pelo Henrique Vianna na lista do curso do segundo
semestre de 1998. Como ela está muito bem feita, entrou no nosso gabarito. A
segunda versão e uma versão básica e não se garante a consistência completa da
data (entre , por exemplo, com o dia 30 de fevereiro de 1999 e o programa vai
aceitar!!). Além disto, ela faz uso de vetores, que é o assunto da próxima aula.
Assim, você so deve estudá-la se quiser adiantar o assunto. A terceira versão já
e mais avançada, realiza a leitura e testa a consistência da data em um mesmo
loop. Mas a filosofia das duas versões é a mesma: O programa testa a validade
dos dados assim que os lê, para só entao processar. A terceira versão também faz
o uso do comando goto, o que pode ser evitado, pois o mesmo efeito teria sido
alcançado usando-se uma estrutura de controle de fluxo qualquer.

Versão 1:
Esta versão foi apresentada na lista do segundo semestre de 1998 pelo Henrique
Avila Viana, da Universidade Federal de Pelotas
#include <stdio.h>
int dia_do_ano (int dia, int mes, int ano) {
int ano_bissexto, data_valida = 0; // Usadas como variaveis booleanas
int total_dias = 0;
/* Na atribuicao abaixo, se as condicoes forem satisfeitas, a variavel
recebera' um valor maior do que 0. Esta variavel sera' usada para
testes booleanos, mais abaixo... */

ano_bissexto = ( ((ano % 4 == 0) && (ano % 100 > 0)) || (ano % 400 == 0) );
if (dia >= 1 && dia <= 31 && mes >= 1 && mes <= 12 &&
ano >= 1900 && ano <= 2100) // Todos os dados nas faixas validas?
if (mes == 1 || mes == 3 || mes == 5 || mes == 7 ||
mes == 8 || mes == 10 || mes == 12)
data_valida = (dia <= 31); // Estes meses tem 31 dias
else
if (mes == 2) // Fevereiro e' um caso a parte...
if (ano_bissexto) // Se o ano for bissexto
data_valida = (dia <= 29); // o dia pode ir ate' 29
else
data_valida = (dia <= 28); // Senao, so' ate' 28
else
data_valida = (dia <= 30); // Se chegou aqui, e' um mes de 30 dias

if (data_valida) {

/* O switch abaixo totaliza os dias decorridos dos meses anteriores
ao digitado. Notem a ordem decrescente dos meses e a falta do
comando "break" nos cases, fazendo com que todos os meses anteriores
sejam somados... */

switch (mes) {
case 12: total_dias += 30; // do mes de novembro
case 11: total_dias += 31; // do mes de outubro
case 10: total_dias += 30; // do mes de setembro
case 9: total_dias += 31; // do mes de agosto
case 8: total_dias += 31; // do mes de julho
case 7: total_dias += 30; // do mes de junho
case 6: total_dias += 31; // do mes de maio
case 5: total_dias += 30; // do mes de abril
case 4: total_dias += 31; // do mes de marco
case 3: total_dias += ano_bissexto?29:28; // do mes de fevereiro
case 2: total_dias += 31; // do mes de janeiro
}

total_dias += dia; // Agora adicionamos os dias decorridos no mes atual
}

return (total_dias); // E retornamos o valor; retorna 0 se data invalida
}

/* ***********************************************************************
Funcao principal - faz a leitura da data a partir do teclado, chama a
nossa funcao dia_do_ano e mostra o resultado.
***********************************************************************
*/
int main() {
int d, m, a, dias = 0;

while (!dias) {
printf("Entre com dia, mes e ano no formato dd/mm/aaaa: ");
fflush (NULL);
scanf("%d/%d/%d", &d, &m, &a);

dias = dia_do_ano(d,m,a);

if (!dias)
printf ("Data invalida! Tente novamente..\n\n");
}

printf ("\n\nEsta data representa o %do. dia de %d.\n", dias, a);
return 0;
}

Versão 2: consistência da data não está boa (aceita datas erradas, como o dia 30
de fevereiro ...). Além disto, faz uso de vetores ...:
/* -------------------------------------------------------- */
/* CONTADOR DE DIAS: Versão 2 ---------------------------- */
#include <stdio.h>
int main()
{
int dia, mes, ano, i; /* Variaveis.. */
int ndias;
int meses[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
printf("\n\n ----Contador de dias----- \n");
/* Leitura da data */
do
{
printf("\nDia: ");
scanf("%d", &dia);
} while ((dia > 31) || (dia < 1));
do
{
printf("\nMes: ");
scanf("%d", &mes);
} while ((mes > 12) || (mes < 1));
do
{
printf("\nAno: ");
scanf("%d", &ano);
} while ((ano < 1900) || (ano > 2100));
/* E isto garante que a data seja valida */
/* Agora, ao processamento ------------------------------------ */
/* Primeiro inicializamos ndias. Em seguida, somamos os dias */
/* do mes corrente e por fim somamos os dias dos meses passados */
ndias = 0;
/* Descobrindo se o ano e bissexto */
/* Caso seja, iremos somar um dia na soma final, mas somente se */
/* o mes corrente for posterior ao mes de fevereiro.. */
if ( ((ano%4) == 0) && ((ano%100) != 0) || (ano%400 == 0)) /* Se e bissexto */
if (mes > 2) ndias += 1; /* Se já passou o mes de fevereiro */
/* Computa os dias do mes corrente */
ndias += dia;
/* O mes corrente já foi contado. Portanto o contador vai ate mes-1 */
for (i=0; i< (mes-1); i++)
ndias += meses[i];
printf("\nDia Numero: %ld", ndias);
}

Versão 3: Melhora a consistência da data, mas inda faz uso de vetores:
/* -------------------------------------------------------- */
/* CONTADOR DE DIAS: Versão 3 ---------------------------- */
#include <stdio.h>
int main()
{
int dia, mes, ano, i;
long int ndias;
int meses[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
printf("\n\n ----Contador de dias----- \n");
/* Leitura da data
Lê ate que a data seja valida */
le_data: /* Rotulo usado para o comando goto */
do
{
printf("\nEntre com a data no formato DD/MM/AA: ");
scanf("%d/%d/%d", &dia, &mes, &ano);
} while (((dia > 31) || (dia < 1)) ||
((mes > 12) || (mes < 1)) ||
((ano < 1900) || (ano > 2100)) );
/* Verificando se o ano e bissexto */
/* Caso seja, o mes de fevereiro ganha mais um dia.. */
if ( ((ano%4) == 0) && ((ano%100) != 0) || (ano%400 == 0))
meses[1] += 1;
/* Verifica a consistencia da data. Caso inconsistente volta a le_data */
if (dia > meses[mes-1]) /* DATA INCONSISTENTE!! */
{
printf("\n DATA INCONSISTENTE! \n ");
meses[1] = 28; /* Desfaz a soma de um dia no mes de fevereiro */
goto le_data;
}
/* E isto garante que a data seja valida */
/* Agora, ao processamento -----------------------*/
ndias = 0;
/* Computa os dias do mes corrente */
ndias += dia;
for (i=0; i< (mes-1); i++) /* O mes corrente já foi contado (mes-1)*/
ndias += meses[i];
printf("\nDia Numero: %ld", ndias);
}

Exercício de Fixação:
Enunciado:

Faça um programa de conversão de base numérica. O programa deverá apresentar uma
tela de entrada com as seguintes opções:
< Conversao de base >
1: decimal para hexadecimal
2: hexadecimal para decimal
3: decimal para octal
4: octal para decimal
5: Encerra
Informe sua opcao:
A partir da opção escolhida, o programa deverá pedir o número na base escolhida,
lê-lo e apresentá-lo na base desejada. Em seguida, o programa deve perguntar ao
usuário se ele deseja retornar ao menu principal ou finalizar o programa. O
problema pode ser estendido a outras bases, de acordo com o interesse do aluno.

OBS: existem duas formas de implementar o programa, uma mais simples e outra
mais complicada: na mais simples, podem ser utilizados os caracteres de
formatação de leitura no scanf e de escrita no printf (ver página
http://ead1.eee.ufmg.br/cursos/C/aulas/c940.html); na mais complicada, você
deverá
fazer as operações matemáticas. Sugiro a implementação pela via mais simples ...


Solução:
A seguir é apresentada uma solução. Esta é a forma de implementar que utiliza os
caracteres de formatação na entrada e saída. Existem outros caminhos para se
chegar à solução.
/*------------------------------------------------------------------*/
/* Programa de conversao de bases ----------------------------------*/
/* Versão 1 --------------------------------------------------------*/
#include <stdio.h>
int main()
{
int entrada, opcao = 0;
char opcao_c;
/* Loop principal do programa --------------------------------------*/
while (opcao != 5)
{
printf("\n\n");
/* Imprime a tela */
printf("\n\n\t< Conversao de base >");
printf("\n 1: decimal para hexadecimal");
printf("\n 2: hexadecimal para decimal");
printf("\n 3: decimal para octal");
printf("\n 4: octal para decimal");
printf("\n 5: Encerra");
printf("\n\n\t\tOpcao: ");
scanf("%d", &opcao);
if ((opcao > 4)||(opcao <1))
continue; /* Opcao invalida ou saida */
/* Volta ao inicio do loop */
printf("\nEntre com o numero: ");
switch (opcao)
{
case 1:
scanf("%d", &entrada);
printf("Numero convertido: %x", entrada);
break;
case 2:
scanf("%x", &entrada);
printf("Numero convertido: %d", entrada);
break;
case 3:
scanf("%d", &entrada);
printf("Numero convertido: %o", entrada);
break;
case 4:
scanf("%o", &entrada);
printf("Numero convertido: %d", entrada);
break;
}
}
return 0;
}