• No results found

Exequias de Carlos II y proclamación de Felipe V

2. Estamento nobiliario

2.2.3. Exequias de Carlos II y proclamación de Felipe V

Uma outra possível utilização de funções é para substituir uma sequência de instruções que se repete em várias partes do programa. Por exemplo, o exemplo 3 da seção 3.4 apresentava um programa para ordenar três números:

/* Programa para ordenar tres numeros dados*/ #include <stdio.h>

main() {

float x, y, z, Aux;

printf("Digite os tres numeros"); scanf("%f %f %f", &x, &y, &z);

printf("Numeros dados: %f , %f , %f \n", x, y, z);

if ((x > y) || (x > z)) /* verifica se x não é o menor */

if (y < z) /* neste caso y é o menor */

{

Aux = x; /* troca os conteúdos de x e de y */

x = y; y = Aux; }

else /* neste caso z é o menor */

{

Aux = x; /* troca os conteúdos de x e de z */

x = z; z = Aux; }

if (y > z) /* verifica se z e y ainda não estão ordenados */

{

Aux = y; /* troca o conteúdo de y e de z */

y = z; z = Aux; }

printf("Numeros ordenados: %f , %f , %f \n", x, y, z); }

Observe que uma sequência de comandos com o mesmo objetivo (trocar os conteúdos de duas variáveis) se repete. Num caso como este poderíamos escrever uma função que realizasse aquela ação pretendida e, então, esta função seria utilizada para substituir a sequência referida.

Por enquanto temos o seguinte problema. Se definirmos a função void Troca(float x, float y)

{ float Aux; Aux = x; x = y; y = Aux; }

e a executarmos passando as variáveis a e b, apenas os conteúdos de a e de b serão passados para x e para y e a troca realizada pela função só afeta os conteúdos de x e de y, não modificando os conteúdos de a e de b que é o que se pretendia. Ou seja, a função Troca recebe apenas os "valores" de a e de b e as ações realizadas pela função interfere apenas nos parâmetros x e y, não alterando nada em relação aos argumentos a e b. Neste caso, dizemos que os parâmetros foram passados por valor.

O sistema Turbo C++ 3.0 oferece a possibilidade de que a execução de uma função altere conteúdos de variáveis “não locais”. Para isto, no protótipo da função os parâmetros devem ser precedidos de &. Neste caso, os argumentos para ativação da função têm que ser variáveis e qualquer alteração no conteúdo do parâmetro se reflete no conteúdo da variável argumento. Diz-se então que a passagem dos parâmetros é feita por referência.

Com este tipo de passagem de parâmetro, o programa acima poderia ser escrito da seguinte

forma:

/* Programa para ordenar tres numeros dados*/ #include <stdio.h>

{ float Aux; Aux = a; a = b; b = Aux; } main() { float x, y, z, Aux;

printf("Digite os tres numeros"); scanf("%f %f %f", &x, &y, &z);

printf("Numeros dados: %f , %f , %f \n", x, y, z); if ((x > y) || (x > z)) if (y < z) Troca(x, y); else Troca(x, z); if (y > z) Troca(y, z); printf("Numeros ordenados: %f , %f , %f \n", x, y, z); }

A passagem de parâmetro por referência permite que entrada de dados seja feita através de uma função. Isto pode ser útil, por exemplo, em programas multitarefas em que o número de entradas pode variar de acordo com a tarefa pretendida. Para exemplificar apresentaremos um programa para tratar números complexos. Naturalmente, um programa com este objetivo deve estar apto a somar e multiplicar complexos, casos em que a entrada será dois números complexos, e a determinar o módulo e a forma polar de um complexo, quando entrada será apenas de um número. Além de exemplificar a entrada de dados através de uma função, o programa abaixo exemplifica um programa multitarefa “completo”.

/*Programa para álgebra dos números complexos*/ #include <stdio.h>

#include <math.h>

void LeComplexo(float &a, float &b) {

puts("Digite a parte real <enter> parte imaginaria"); scanf("%f %f", &a, &b);

}

float Modulo(float a, float b) {

return sqrt(a*a + b*b); }

void Polar(float a, float b, float &c, float &d) {

c = Modulo(a, b); d = asin(b/c); }

void Soma(float a, float b, float c, float d, float &e, float &f) {

e = a + c; f = b + d; }

void Produto(float a, float b, float c, float d, float &e, float &f) {

f = a*d + b*c; }

void Menu() {

puts("1-Modulo \n 2- Forma polar \n 3-Soma \n 4-Produto \n 5-Encerra \n Digite sua opcao: "); } main() { float x, y, z, w, t, u; int Opc; Menu(); scanf("%d", &Opc); switch (Opc) { case 1: LeComplexo(x, y); z = Modulo(x, y); printf("|%.2f + %.2fi| = %.2f", x, y, z); break; case 2: LeComplexo(x, y); Polar(x, y, z, w);

printf("%.2f + %.2fi = %.2f(cos%.2f + isen%.2f)", x, y, z, w, w); break;

case 3:

LeComplexo(x, y); LeComplexo(z, w); Soma(x, y, z, w, t, u);

printf("(%.2f + %.2fi) + (%.2f + %.2fi) = %.2f + %.2fi", x, y, z, w, t, u); break;

case 4:

LeComplexo(x, y); LeComplexo(z, w); Produto(x, y, z, w, t, u);

printf("(%.2f + %.2fi) + (%.2f + %.2fi) = %.2f + %.2fi", x, y, z, w, t, u); break;

} }

O exemplo a seguir melhora sobremaneira a legibilidade do programa (parte dele) que determina o dia da semana de uma data posterior ao ano de 1600 dada apresentado no capítulo 3. Lá precisávamos determinar o número de dias decorridos entre 01/01/1600 e a data dada. Vimos que precisávamos determinar, entre outras coisas: o número de dias já decorridos no ano da data dada (para isto precisávamos determinar se tal ano era bissexto e o número de dias 31 já ocorridos) e a quantidade de anos bissextos entre 1600 e o ano da data dada. A boa técnica de programação sugere que cada ação parcial do programa seja executada por uma função.

Temos então a seguinte proposta para um programa que determine o número de dias dias decorridos entre duas datas dadas (este programa é utilizado em aposentadorias: pela legislação atual (novembro de 2008) um trabalhador de uma empresa privada adquire o direito de se aposentar quando completa 35 anos de serviço, sendo este cálculo a partir da soma do número de dias trabalhados nas (possivelmente) várias empresas nas quais o interessado trabalhou).

/*Programa para determinar o número de dias entre duas datas dadas*/ #include <conio.h>

#include <stdio.h> #include <conio.h>

/*Verifica se um ano é bissexto (retorno: Sim-1/Nao-0)*/ int EhBissexto(int Ano)

{

return ((Ano % 4 == 0) && ((Ano % 100 != 0) || (Ano % 400 == 0))); }

/*Retorna o número de dias 31 ocorridos até o mês dado*/ int NumDias31(int Mes)

{ if (Mes < 9) return Mes/2; else return (Mes + 1)/2; }

/*Retorna o número de dias de um ano até uma data dada*/ int NumDiasAteUmaData(int Dia, int Mes, int Ano) {

int NumDias;

//Numero de dias considerando todos os meses com 30 dias NumDias = 30*(Mes - 1);

//Acrescentando o número de dias 31 já ocorridos no ano e o número de dias do mês corrente NumDias = NumDias + NumDias31(Mes) + Dia;

//Retificando o número de dias de fevereiro (se ele já ocorreu) if (Mes > 2) if (EhBissexto(Ano)) NumDias = NumDias - 1; else NumDias = NumDias - 2; return NumDias; }

/*Retorna o número de dias de uma após uma data dada*/ int NumDiasAposUmaData(int Dia, int Mes, int Ano) {

if (EhBissexto(Ano))

return 367 - NumDiasAteUmaData(Dia, Mes, Ano); else

return 366 - NumDiasAteUmaData(Dia, Mes, Ano); }

/*Retorna o número de anos bissextos entre dois anos dados*/ int NumAnosBissextos(int Ano1, int Ano2)

{

int Aux, Mult4, Mult100, Mult400; Aux = Ano2 - 1;

Mult4 = (Aux - (Aux % 4) - Ano1 + (Ano1 % 4))/4;

Mult100 = (Aux - (Aux % 100) - Ano1 + (Ano1 % 100))/100; Mult400 = (Aux - (Aux % 400) - Ano1 + (Ano1 % 400))/400; return Mult4 - Mult100 + Mult400;

} main() {

int Dia1, Mes1, Ano1, Dia2, Mes2, Ano2, Anos, NumDias, DiasDoAnoFinal, DiasDoAnoInicial; clrscr();

printf("Data inicial (dd/mm/aaaa)\n");

scanf("%d/%d/%d", &Dia1, &Mes1, &Ano1); printf("Data final (dd/mm/aaaa)\n");

Anos = Ano2 - Ano1 - 1;

DiasDoAnoFinal = NumDiasAteUmaData(Dia2, Mes2, Ano2); DiasDoAnoInicial = NumDiasAposUmaData(Dia1, Mes1, Ano1);

NumDias = Anos*365 + DiasDoAnoFinal + DiasDoAnoInicial + NumAnosBissextos(Ano1, Ano2); printf("\nData inicial: %d/%d/%dData final: %d/%d/%d Numeros de dias: %d", Dia1, Mes1, Ano1, Dia2, Mes2, Ano2, NumDias);

getch(); }

Embora o help do Turbo C++ 3.0 afirme que em C a única passagem de parâmetro é por valor, conseguimos, no Turbo C 2.01, uma forma de passagem de parâmetros por referência. Para isto utilizaremos ponteiros que além de permitir esta forma de passagem de parâmetros tem outras aplicações importantes em programação em C e em C++.