Mudanças entre as edições de "Funções - Programação 1 - Engenharia"
Linha 363: | Linha 363: | ||
<ol> | <ol> | ||
<li> | <li> | ||
− | Elaborar uma função que imprime uma mensagem: | + | Elaborar uma função que imprime uma mensagem:<br /> |
− | ATENÇÃO: CUIDADO COM O CORONA!!! | + | ATENÇÃO: CUIDADO COM O CORONA!!!<br /> |
Customize a função para que ela repita a mensagem N vezes, onde N é passado como parâmetro. | Customize a função para que ela repita a mensagem N vezes, onde N é passado como parâmetro. | ||
</li> | </li> |
Edição das 09h00min de 30 de abril de 2020
FUNÇÕES no C
Programa C: Um conjunto de funções
Um programa em C basicamente é um conjunto de funções. Uma função pode ser vista como um subprograma para o qual podemos repassar dados de entrada através de parâmetros e receber os resultados através do retorno da função.
Normalmente, um programa bem comportado em C possui pelo menos uma função: a função main(). Esta função é chamada no início da execução do programa. A primeira instrução da função main() é a primeira instrução executada pelo programa (pelo menos do ponto de vista do programador). Da mesma forma, a última instrução desta função é a última instrução a ser chamada.
Um programa normalmente vai apresentar um conjunto de funções. Por exemplo:
#include <stdio.h>
void func4()
{
printf("Esta é a função func4()\n");
}
void func3()
{
printf("Esta é a função func3()\n");
func4();
}
void func2()
{
printf("Esta é a função func2()\n");
}
void func1()
{
printf("Esta é a função func1()\n");
func2();
func3();
}
int main()
{
printf("Esta é a primeira instrução da função main()\n");
func1();
printf("Esta é a última instrução da função main()\n");
return 0;
}
A sequência de chamada de funções pode ser ilustrada da forma:
EXERCÍCIO: Compile e execute o programa acima. Verifique a ordem de impressão das mensagens e compare com as chamadas das funções.
NOTA: Uma função pode ser chamada várias vezes no programa. É O REAPROVEITAMENTO DE CÓDIGO...
Definição, declaração e chamada de Funções
NOTAR que existem 3 momentos diferentes de uso de funções:
- Definição de função: é quando se constrói a função explicitando o seu nome, tipo de retorno, parâmetros e o seu corpo (instruções e variáveis locais;
- Declaração da Função: é somente uma declaração contendo o nome da função, tipo de retorno e parâmetros. O corpo da função NÂO é explicitado pois supõe-se que ela foi definida em algum outro lugar;
- Chamada (invocação) da Função: quando se usa a função, chamando-a pelo seu nome e passando os parâmetros (ATUAIS) que se deseja.
Por que usar Funções
- Quebrar grandes problemas em pequenos problemas. Criar código para resolver cada pequeno problema e confiná-lo em funções:
- uma função cujo objetivo é calcular o seno de um ângulo passado como parâmetro e retornar o seno calculado.
- uma função que desenha um quadrado dado o tamanho do lado. Neste caso ela nem precisa retornar valor.
- Facilita a divisão de tarefas em um grande projeto. O desenvolvedor X desenvolve a função seno, o desenvolvedor Y desenvolve a função coseno;
- Facilita o teste de software: a função pode ser testada exaustivamente antes de ser disponibilizada para uso;
- Deixa o código mais claro e mais otimizado: se eu quero computar o seno eu não preciso reproduzir o algoritmo que computa o seno, simplesmente chamo a função.
CONSELHO: SEMPRE que receber um problema a ser resolvido, tente quebrá-lo em subproblemas com "funcionalidades" bem definidas. Pense seriamente rm tratar cada subproblema como uma ou mais funções. Liste os possíveis parâmetros e o retorno destas funções. Agrupe as funções em módulos (serão arquivos furutamente).
Exercício: Implementar uma função que simula a jogada de dois dados e retorna a soma destes dois dados. Esta função poderia ser usada num jogo de adivinhação contra o computador.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* definição da função soma de dados
Sinopse: Esta função ....
Parâmetros de Entrada: não tem
Saída: soma da jogada randômica de 2 dados
Autor: ....
Versão:
*/
int soma_dois_dados()
{
int dado1, dado2, soma;
dado1 = rand() % 6 + 1;
dado2 = rand() % 6 + 1;
soma = dado1 + dado2;
return soma;
}
int main ()
{
int teste;
/* iniciar semente: */
srand ( time(NULL) );
teste = soma_N_dados();
printf("Valor da jogada de dados é %d\n", teste);
return 0;
}
Passando parâmetros e recebendo valores de retorno
Uma função normalmente resolve um determinado problema para um determinado conjunto de dados e produz uma saída. Estes dados podem ser passados como parâmetros e a saída pode ser retornada pela função.
Exemplo: Uma função media_nums() que retorna a média de 3 números reais passados como parâmetros
#include <stdio.h>
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
main()
{
float media, aux1, aux2, aux3;
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media = media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros é %f\n", media);
}
Deve ser observado que:
- após o nome da função, entre parênteses, são fornecidos os três parâmetros com os seus respectivos tipos. Os valores (conteúdos das variáveis) aux1, aux2 e aux3 são copiados para as variáveis num1, num2 e num3 da função media_nums().
- a função media_nums() retorna um valor do tipo float (informado antes do nome da função) que é o valor da variável media_local. Este valor é copiado para a variável media da função main()
- as variáveis num1, num2 e num3 bem como a variável media_local possuem escopo LOCAL, ou seja, são "vistas" somente pela função media_nums();
- as variáveis media, aux1, aux2 e aux3 também possuem escopo LOCAL, ou seja são "vistas" somente pela função main();
NOTE que o formato de declaração de uma função é
tipo_retorno nome_funcao( lista_de_parametros ) { declaracao_variaveis_locais instruções }
Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função. Existem situações que poderemos relaxar esta afirmação.
Um pouco mais sobre parâmetros
O termo argumento ou parâmetro real (atual) é usado para referenciar os valores que estão sendo passados na CHAMADA da função. Os parâmetros formais referem-se aos parâmetros listados na função. É comum, no entanto, usar os termos argumentos e parâmetros como sinônimos e identificados pelo contexto em que estão sendo usados.
A passagem de parâmetros POR VALOR diz respeito a copiar o valor do argumento na CHAMADA da função para a variável associada ao parâmetro na função. Mais tarde falaremos na passagem de parâmetro POR REFERÊNCIA. Por ora, usaremos a passagem POR VALOR.
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. Eles podem ser uma expressão qualquer (uma expressão SEMPRE resulta em um VALOR).
Exemplo de chamadas para a função media_nums():
main()
{
float media, x,y,z;
x = 5.7;
y = 9.8;
/* exemplo de chamada 1 */
media = media_nums(4.8,x,y*3);
/* exemplo de chamada 2 */
media = media_nums (x+y,y*y+5,(x+y)/2);
}
Deve ser observado que:
- na chamada 1 do exemplo, os parâmetros são uma CONSTANTE, o valor de x, e o valor de y*3. Note que o compilador deve gerar código para resolver estas expressões antes de INVOCAR a função!.
- na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA.
Funções Definidas pelo Usuário X Funções da Biblioteca
- Existem funções que já foram implementadas e disponibilizadas através de uma biblioteca.
- Exemplo: printf(), rand() etc;
- Para usar corretamente estas funções devemos incluir a sua declaração no ínicio do programa (arquivo). Uma forma simples é incluir um arquivo cabeçalho contendo estas declarações (ex: #include <stdio.h>)
- As funções implementadas pelo usuário são àquelas voltadas a aplicação específica que ele está trabalhando.
- Exemplo: uma função para sortear a soma de dois dados. Toda vez que precisar de uma soma de dois dados lançados randomicamente, bastará chamar esta função.
EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de dois dados lançados randomicamente.
Perguntas a serem respondidas antes de começar a implementação:
- Qual é a funcionalidade desta função? Qual o objetivo dela?
- Esta função tem parâmetros? Em que situação ela poderia ter parâmetros?
- A função retorna valor? Que tipo?
- Liste possíveis variações desta função.
- somar o lançamento de N dados;
- criar um dado de N faces...
Variáveis GLOBAIS e variáveis LOCAIS
Se variáveis são declaradas dentro de uma função, então a visibilidade (ESCOPO) destas variáveis é LOCAL. Nenhuma outra função tem acesso a estas variáveis. Na realidade, o ESCOPO da variáivel LOCAL é o bloco (entre chaves) em que ela foi declarada.
Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções. Seja o exemplo anterior modiificado:
#include <stdio.h>
float media; /* Variável GLOBAL */
void media_nums(float num1, float num2, float num3)
{
media = (num1 + num2 + num3)/3;
return;
}
main()
{
float aux1, aux2, aux3; /* Variáveis LOCAIS */
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros é %f\n", media);
}
Neste exemplo, a variável media é declarada como GLOBAL. Ela é MODIFICADA diretamente pela função media_nums() e impressa pela função main()
NOTE que como a função media_nums() não retorna valor então declaramos seu tipo de retorno como void que significa aqui NADA ou VAZIO.
NOTE também que MESMO que a função retorne um valor, não é obrigatório colocá-la no lado direito do sinal de atribuição.
Na realidade, uma função pode ser chamada dentro de qualquer expressão. Por exemplo, para o caso em que a função media_nums() retorna um valor, ela poderia ser usada como:
#include <stdio.h>
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
main()
{
float media, aux1, aux2, aux3;
printf("\nEntre com numero 1: ");
scanf ("%f",&aux1);
printf("\nEntre com numero 2: ");
scanf ("%f",&aux2);
printf("\nEntre com numero 3: ");
scanf ("%f",&aux3);
media = media_nums(aux1, aux2, aux3);
printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3));
}
Um parênteses sobre nome de variáveis
Um nome de variável pode conter letras, dígitos e o underscore(sublinhado). Ela DEVE iniciar com um underscore ou uma letra. Letras maúsculas e minúsculas podem ser usadas e são distinguidas (o C é CASE SENSITIVE)
Variáveis LOCAIS e GLOBAIS podem ter o mesmo nome. A variável LOCAL terá preferência no uso.
Exercício: Execute o programa abaixo e verifique as saídas.
#include <stdio.h>
int i=1; /* GLOBAL */
func()
{
int i=100; /* LOCAL */
i=i+1; /* incrementa LOCAL */
printf( "Valor de i = %d na função func()\n", i );
}
main()
{
i=i+1; /* incrementa GLOBAL */
func();
printf( "Valor de i = %d \n", i );
}
NOTA: não é recomendado o uso de variáveis com o mesmo nome.
Iniciando variáveis na declaração
Tanto as variáveis LOCAIS como as GLOBAIS podem ser inicializadas na declaração.
Exemplo:
int alfa=1;
main()
{
float beta=1.5;
printf("Valor de alfa = %d e valor de beta = %f\n", alfa, beta);
}
NOTA: variáveis LOCAIS não são iniciadas automaticamente: cabe ao programador iniciá-la corretamente.
NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero. Mas mantenha-se informado sobre o sistema que está trabalhando... Em sistemas embarcados pode não ser verdade!
Exercícios
-
Elaborar uma função que imprime uma mensagem:
ATENÇÃO: CUIDADO COM O CORONA!!!
Customize a função para que ela repita a mensagem N vezes, onde N é passado como parâmetro. -
Elaborar uma função "linha_vazada()" para desenhar uma linha da forma:
XXbbbbbbbbbbbXX
O caracter b apenas indica espaço em branco. Qual seria o tipo de retorno desta função?
Quais parâmetros ela tem? Propor uma versão customizada que proporcione receber como parâmetros a largura
total da linha (número de espaços em branco) mas mantendo sempre os lados com XX. -
Elaborar um programa contendo uma função da forma:
float area_retang (float lado1 , float lado2)
Solução #include <stdio.h> /* Função de Cálculo da Aŕea de um retângulo */ /* Parâmetros de entrada: lados do retângulo */ /* retorno: valor da área */ float area_retang(float lado1, float lado2) { float area; area = lado1 * lado2; return area; } main() { float area; float l1, l2; /* entrada de dados */ printf("entre com lado 1\n"); scanf ("%f", &l1); printf("entre com lado 2\n"); scanf ("%f", &l2); /* chamada da função */ area = area_retang(l1,l2); printf("valor da area do retanguloa = %0.2f\n", area); }
A função recebe os lados de um retângulo e retorna a área do mesmo.
-
Elaborar um programa contendo uma função da forma:
float area_circ (float raio)
A função recebe o raio de um círculo e retorna a área da mesma.
Solução #include <stdio.h> float area_circ(float raio) { float area;/* Variáveis LOCAIS */ area = (raio*raio)*3.1415; return area; } main() { float aux1, area; /* Variáveis LOCAIS */ printf("Entre com o raio\n"); scanf ("%f",&aux1); area = area_circ(aux1); printf ("A area do circulo é %f\n", area); }
-
Elaborar um programa contendo uma função da forma:
float dif_area_circ (float raio1, float raio2)
A função recebe o raio de dois círculos e retorna a diferença da área entre eles. Reaproveitar o exercício anterior.Solução - Exercício 03 #include <stdio.h> #define PI 3.1415 float area_circ (float raio) { float area; area = PI*raio*raio; return (area); } float dif_area_circ (float raio1, float raio2) { float a1, a2, area; a1 = area_circ(raio1); a2 = area_circ(raio2); return (a1-a2); } main() { float dif; float r1, r2, area; /* entrada de raio 1 */ printf("entre com raio 1\n"); scanf ("%f", &r1); printf("entre com raio2 \n"); scanf ("%f", &r2); area = dif_area_circ(r1, r2); printf("valor da diferença = %0.2f\n", area); }
-
Elaborar uma função que recebe dois números inteiros. A função retorna a soma de todos os números entre eles (inclusive).
Solução - Exercício 04 #include <stdio.h> /* a função calcula a soma de todos inteiros entre num1 e num2 inclusive */ int soma_int(int num1, int num2) { int i, soma_acumulada = 0; if (num1>num2) { i=num2; num2=num1; num1=i; } for (i=num1;i<=num2;i++) soma_acumulada = soma_acumulada + i; return soma_acumulada; } main() { int i,x,y, soma_acumulada; printf("Entre com o primeiro número da faixa \n"); scanf ("%d", &x); printf("Entre com o segundo número da faixa \n"); scanf ("%d", &y); soma_acumulada = soma_int(x,y); printf("soma acumulada entre %d e %d é %d\n", x,y,soma_acumulada); }
-
Elaborar um programa em C correspondente aos fluxogramas abaixo. Trata-se de um procedimento para calcular o fatorial de um número inteiro passado como parâmetro para uma função.
A função fatorial é definida por:
Neste fluxograma, o subprograma denominado CalcFatorial recebe um valor no parâmetro N (implicitamente inteiro) e retorna o valor calculado do fatorial. O fluxograma principal invoca duas vezes o subrograma. O retorno é armazenado nas variáveis NUM1 e NUM3. Quando um subprograma retorna um valor, ele é chamado de função. Para manter coerência com o C chamaremos qualquer subrprograma de função (independente de retornar valor).
Solução - Exercício 05 #include <stdio.h> float calc_fatorial(int num) { int i=1; float fat=1;/* Variaveis LOCAIS */ while(i<=num){ fat = fat*i; i++; } return fat; } main() { float num1, num2, num3; /* Variáveis LOCAIS */ num1 = calc_fatorial(5); num2 = 4; num3 = calc_fatorial(num2*3); printf ("num1: %f\n", num1); printf ("num2: %f\n", num2); printf ("num3: %f\n", num3); }
-
Faça uma função para entrar com dois números inteiros pelo teclado e retornar a soma dos fatoriais destes números. Reutilize a função anterior.
Solução - Exercício 06 -
Faça uma função para calcular o módulo de um número complexo passado na forma retangular. O protótipo da função tem o seguinte aspecto:
float mod_complexo(float x, float y)
Solução - Exercício 07 #include <stdio.h> #include <math.h> float mod_complexo(float x,float y) { float modulo;/* Variaveis LOCAIS */ modulo = sqrt( ((x*x) + (y*y)) ); // Funcao sqrt lembrar de utilizar math.h return modulo; } main() { float num1, num2, result;/* Variaveis LOCAIS */ printf("Entre com a parte real:\n"); scanf("%f",&num1); printf("Entre com a parte imaginaria:\n"); scanf("%f",&num2); result = mod_complexo(num1,num2); printf("Modulo do numero complexo: %f\n",result); }