Mudanças entre as edições de "Funções - Programação 1 - Engenharia"
(110 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
+ | = Objetivos da Aula = | ||
+ | |||
+ | *Conceituar funções, parâmetros e valor de retorno; | ||
+ | |||
+ | *Definir, declarar e chamar funções no C; | ||
+ | |||
+ | *Declarar protótipo de funções; | ||
+ | |||
+ | *Distinguir e saber criar variáveis locais e globais; | ||
+ | |||
+ | *Aplicar funções para resolver subproblemas de um grande problema; | ||
+ | |||
+ | *Noção de recursividade e o cuidado no uso... | ||
+ | |||
+ | = Referências Históricas = | ||
+ | |||
+ | *[https://en.wikipedia.org/wiki/Single-responsibility_principle O Princípio da Responsabilidade Única] | ||
+ | |||
+ | = Conceito de Função = | ||
+ | |||
+ | Uma função é um "bloco de código" que resolve um dado problema | ||
+ | específico, que possui um nome associado e | ||
+ | que pode ser chamado quando necessário. Ao final da função a linha de execução | ||
+ | retorna para quem chamou a função. | ||
+ | |||
+ | Exemplo: para calcular o seno de um ângulo chamamos uma função para resolver | ||
+ | o problema específico: "calcular um seno". Dados de entrada devem ser fornecidos, | ||
+ | no caso o ângulo. O dado de saída é o seno computado deste ângulo. | ||
+ | |||
+ | Notar que a função permite REAPROVEITAR o código. Não precisamos a todo momento | ||
+ | reescrever um código que computa o seno. Basta chamar a função. | ||
+ | |||
= FUNÇÕES no C = | = FUNÇÕES no C = | ||
− | |||
== Programa C: Um conjunto de funções == | == Programa C: Um conjunto de funções == | ||
Linha 63: | Linha 94: | ||
NOTAR que existem 3 momentos diferentes de uso 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; | + | *'''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; | + | *'''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. | + | *'''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== | ==Por que usar Funções== | ||
Linha 77: | Linha 108: | ||
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> | <blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> | ||
− | 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 | + | 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 fututamente). |
</blockquote> | </blockquote> | ||
+ | |||
+ | Exemplo: Implementar uma função que imprimi uma linha com 10 caracteres X lado a lado. Na sequência, melhorar a função e imprimir 5 linhas com 10 caracteres Y cada. | ||
+ | |||
+ | *[https://drive.google.com/file/d/1K_47tgAVwHrevh72oWNUAC73WalfzIwI/view?usp=sharing Vídeo Explicativo] | ||
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. | 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. | ||
Linha 96: | Linha 131: | ||
*/ | */ | ||
− | int | + | int somar_dois_dados() |
{ | { | ||
int dado1, dado2, soma; | int dado1, dado2, soma; | ||
Linha 113: | Linha 148: | ||
srand ( time(NULL) ); | srand ( time(NULL) ); | ||
− | teste = | + | teste = somar_dois_dados(); |
printf("Valor da jogada de dados é %d\n", teste); | printf("Valor da jogada de dados é %d\n", teste); | ||
return 0; | return 0; | ||
Linha 119: | Linha 154: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | ==Passando parâmetros e recebendo valores de retorno | + | ==Exemplo de Funções com menus Multiníveis em modo texto== |
+ | |||
+ | Considere uma aplicação que deve gerenciar salas e usuários de uma instituição. Ela deve permitir cadastrar salas e usuários para alguma finalidade. Teríamos que apresentar menus e submenus para esta facilidade. O código abaixo demonstra esta possibilidade. Note que o código somente apresenta os menus e o uso de funções para apresentar submenus e retornar ao menu principal. Ele não apresenta a lógica necessária para gerenciar usuários e salas. | ||
+ | |||
+ | Obs: Baseado nas discussões em [https://cboard.cprogramming.com/c-programming/64154-how-make-menu-c-dos.html cboard.cprogramming.com] | ||
+ | |||
+ | {{collapse top | Exemplo de menus e submenus usando funções para chamada de submenus}} | ||
+ | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
+ | #include <unistd.h> | ||
+ | #include <stdlib.h> | ||
+ | |||
+ | /* Autores: Professores PRG1 - IFSC -SJ */ | ||
+ | /******************************************/ | ||
+ | /* | ||
+ | Para fins didáticos estão concentradas aqui | ||
+ | todas as funções para exemplificar a elaboração | ||
+ | de menus em modo texto. | ||
+ | Em versões finais o código deve ser organizado em arquivos .h | ||
+ | e .c, agrupando as funções conforme a funcionalidade. | ||
+ | Por exemplo: em um arquivo salas.c colocar as funções | ||
+ | de gerenciamento de sala, com os protótipos no salas.h | ||
+ | */ | ||
+ | /******************************************/ | ||
+ | |||
+ | /******************************************/ | ||
+ | /* Protótipos de funções - colocar em .h */ | ||
+ | /******************************************/ | ||
+ | |||
+ | void gerenciar_usuarios(); | ||
+ | void gerenciar_salas(); | ||
+ | void adicionar_usuario(); | ||
+ | void remover_usuario(); | ||
+ | void adicionar_sala(); | ||
+ | void remover_sala(); | ||
+ | |||
+ | /******************************************/ | ||
+ | /* Variáveis Globais */ | ||
+ | /******************************************/ | ||
+ | |||
+ | /* a fazer */ | ||
+ | |||
+ | /******************************************/ | ||
+ | int main() | ||
+ | { | ||
+ | int opcao; | ||
+ | |||
+ | do { | ||
+ | system("clear"); | ||
+ | printf("**********************************\n"); | ||
+ | printf("Menu Nível 1\n\n"); | ||
+ | printf("1. Gererenciar Usuários\n"); | ||
+ | printf("2. Gerenciar Salas\n"); | ||
+ | printf("3. Sair\n"); | ||
+ | printf("**********************************\n"); | ||
+ | scanf("%d",&opcao); | ||
+ | switch (opcao) { | ||
+ | case 1: gerenciar_usuarios(); | ||
+ | break; | ||
+ | case 2: gerenciar_salas(); | ||
+ | break; | ||
+ | case 3: printf("Finalizando Programa...\n"); | ||
+ | break; | ||
+ | default: printf("Opção inexistente. Tente novamente...\n"); | ||
+ | sleep(1); /* tempo somente para fins de visualização */ | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | } while (opcao != 3); | ||
+ | } | ||
+ | |||
+ | /***************************************************/ | ||
+ | /* Esta funções deveriam estar em arquivo separado */ | ||
+ | /***************************************************/ | ||
+ | void gerenciar_usuarios() | ||
+ | { | ||
+ | int opcao; | ||
+ | |||
+ | do { | ||
+ | system("clear"); | ||
+ | printf("**********************************\n"); | ||
+ | printf("Menu Nível 2 - Gerenciar Usuários\n\n"); | ||
+ | printf("1. Adicionar Usuário\n"); | ||
+ | printf("2. Remover Usuário\n"); | ||
+ | printf("3. Sair do Gerenciar Usuários\n"); | ||
+ | printf("**********************************\n"); | ||
+ | scanf("%d",&opcao); | ||
+ | switch (opcao) { | ||
+ | case 1: adicionar_usuario(); | ||
+ | break; | ||
+ | case 2: remover_usuario(); | ||
+ | break; | ||
+ | case 3: printf("Finalizando Gerenciar Usuários...\n"); | ||
+ | sleep(1); /* tempo somente para fins de visualização */ | ||
+ | break; | ||
+ | default: printf("Opção inexistente. Tente novamente...\n"); | ||
+ | sleep(1); /* tempo somente para fins de visualização */ | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | } while (opcao != 3); | ||
+ | } | ||
+ | |||
+ | void adicionar_usuario() | ||
+ | { | ||
+ | /* aqui poderia ter um menu nível 3 */ | ||
+ | printf("adicionando usuário\n "); | ||
+ | sleep(1); | ||
+ | printf("usuário adicionado\n "); | ||
+ | sleep(1); | ||
+ | } | ||
+ | |||
+ | void remover_usuario() | ||
+ | { | ||
+ | /* aqui poderia ter um menu nível 3 */ | ||
+ | printf("removendo usuário\n "); | ||
+ | sleep(1); | ||
+ | printf("usuário removido\n "); | ||
+ | sleep(1); | ||
+ | } | ||
+ | |||
+ | |||
+ | /***************************************************/ | ||
+ | /* Esta funções deveriam estar em arquivo separado */ | ||
+ | /***************************************************/ | ||
+ | |||
+ | void gerenciar_salas() | ||
+ | { | ||
+ | int opcao; | ||
+ | |||
+ | do { | ||
+ | system("clear"); | ||
+ | printf("**********************************\n"); | ||
+ | printf("Menu Nível 2 - Gerenciar Salas\n\n"); | ||
+ | printf("1. Adicionar Sala\n"); | ||
+ | printf("2. Remover Sala\n"); | ||
+ | printf("3. Sair do Gerenciar Salas\n"); | ||
+ | printf("**********************************\n"); | ||
+ | scanf("%d",&opcao); | ||
+ | switch (opcao) { | ||
+ | case 1: adicionar_sala(); | ||
+ | break; | ||
+ | case 2: remover_sala(); | ||
+ | break; | ||
+ | case 3: printf("Finalizando Gerenciar Sala...\n"); | ||
+ | sleep(1); /* tempo somente para fins de visualização */ | ||
+ | break; | ||
+ | default: printf("Opção inexistente. Tente novamente...\n"); | ||
+ | sleep(1); /* tempo somente para fins de visualização */ | ||
+ | break; | ||
+ | } | ||
+ | |||
+ | } while (opcao != 3); | ||
+ | } | ||
+ | |||
+ | void adicionar_sala() | ||
+ | { | ||
+ | /* aqui poderia ter um menu nível 3 */ | ||
+ | printf("adicionando sala\n "); | ||
+ | sleep(1); | ||
+ | printf("sala adicionada\n "); | ||
+ | sleep(1); | ||
+ | } | ||
+ | |||
+ | void remover_sala() | ||
+ | { | ||
+ | /* aqui poderia ter um menu nível 3 */ | ||
+ | printf("removendo sala\n "); | ||
+ | sleep(1); | ||
+ | printf("sala removida\n "); | ||
+ | sleep(1); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | {{collapse bottom}} | ||
+ | |||
+ | =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. | 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 | + | Exemplo: Uma função ''media_nums''() que retorna a média de 3 números reais passados como parâmetros. Note que se trata de |
+ | um exemplo pois NÃO seria necessário uma função para esta finalidade. | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
Linha 136: | Linha 349: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float media, aux1, aux2, aux3; | float media, aux1, aux2, aux3; | ||
Linha 151: | Linha 364: | ||
media = media_nums(aux1, aux2, aux3); | media = media_nums(aux1, aux2, aux3); | ||
printf ("\nmedia dos 3 numeros é %f\n", media); | printf ("\nmedia dos 3 numeros é %f\n", media); | ||
+ | return 0; | ||
} | } | ||
Linha 165: | Linha 379: | ||
NOTE que o formato de declaração de uma função é | NOTE que o formato de declaração de uma função é | ||
− | tipo_retorno nome_funcao( lista_de_parametros ) | + | ''tipo_retorno'' '''nome_funcao'''( ''lista_de_parametros'' ) |
{ | { | ||
declaracao_variaveis_locais | declaracao_variaveis_locais | ||
− | + | lista_instruções | |
− | + | return; /* comando de retorno - pode ou não retornar valor - pode ser omitido */ | |
} | } | ||
− | 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. | + | Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função (logo após a abertura do bloco com '{'. Existem situações que poderemos relaxar esta afirmação. |
+ | |||
+ | U ponto a ser observado é a questão do retorno de uma função. Se a função não retorna um valor então tipo de retorno deve ser '''void'''. Neste caso, para realizar o retorno no código deve ser usada a palavra reservada '''return'''. | ||
==Um pouco mais sobre parâmetros== | ==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. | + | <blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> |
+ | 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. | ||
+ | </blockquote> | ||
+ | |||
+ | <blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> | ||
+ | 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. Neste último é repassado o endereço da variável para a função. Por ora, usaremos a passagem POR VALOR. | ||
+ | </blockquote> | ||
− | |||
− | |||
Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. | Os parâmetros passados na CHAMADA de uma função não são necessariamente variáveis. | ||
Linha 187: | Linha 407: | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
+ | #include <stdio.h> | ||
− | main() | + | /* OBS: num1, m2 e num3 são os parâmetros formais */ |
+ | float media_nums(float num1, float num2, float num3) | ||
+ | { | ||
+ | float media_local; | ||
+ | |||
+ | media_local = (num1 + num2 + num3)/3; | ||
+ | return media_local; | ||
+ | } | ||
+ | |||
+ | int main() | ||
{ | { | ||
float media, x,y,z; | float media, x,y,z; | ||
Linha 200: | Linha 430: | ||
/* exemplo de chamada 2 */ | /* exemplo de chamada 2 */ | ||
media = media_nums (x+y,y*y+5,(x+y)/2); | media = media_nums (x+y,y*y+5,(x+y)/2); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 207: | Linha 438: | ||
* na chamada 2 aparecem expressões ainda mais complexas. Todas elas devem ser resolvidas antes da função ser INVOCADA. | * 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. | *Existem funções que já foram implementadas e disponibilizadas através de uma biblioteca. | ||
Linha 217: | Linha 448: | ||
<blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> | <blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> | ||
− | EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de | + | EXERCÍCIO EM SALA: IMPLEMENTAR uma função para retornar a soma de N dados lançados randomicamente. |
Perguntas a serem respondidas antes de começar a implementação: | Perguntas a serem respondidas antes de começar a implementação: | ||
*Qual é a funcionalidade desta função? Qual o objetivo dela? | *Qual é a funcionalidade desta função? Qual o objetivo dela? | ||
− | *Esta função tem | + | *Esta função tem parâmetros? |
− | *A função retorna valor? | + | *A função retorna valor? De que tipo? |
+ | *Quais funções da biblioteca são usadas na sua impleemntação? | ||
*Liste possíveis variações desta função. | *Liste possíveis variações desta função. | ||
− | |||
− | |||
</blockquote> | </blockquote> | ||
− | + | =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. | + | <blockquote style="background: #DCF4CC; border: 1px solid black; padding: 1em;"> |
− | Na realidade, o ESCOPO da | + | Se variáveis são declaradas dentro de uma função (ou dentro de um bloco de código}, então a visibilidade (ESCOPO) destas variáveis é LOCAL, ou seja restrita ao código do bloco. Nenhuma outra função tem acesso a estas variáveis. |
+ | Na realidade, o ESCOPO da variável 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 | + | Uma variável pode ser GLOBAL, ou seja, declarada FORA das funções. Neste caso a variável é VISTA por todas as funções. |
+ | |||
+ | Uma BOA PRÁTICA é evitar o uso de variáveis GLOBAIS para minimizar possibilidade de erros nos programas. | ||
+ | </blockquote> | ||
+ | |||
+ | Seja o exemplo anterior modificado: | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
Linha 246: | Linha 482: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float aux1, aux2, aux3; /* Variáveis LOCAIS */ | float aux1, aux2, aux3; /* Variáveis LOCAIS */ | ||
Linha 261: | Linha 497: | ||
media_nums(aux1, aux2, aux3); | media_nums(aux1, aux2, aux3); | ||
printf ("\nmedia dos 3 numeros é %f\n", media); | printf ("\nmedia dos 3 numeros é %f\n", media); | ||
+ | return 0; | ||
} | } | ||
Linha 273: | Linha 510: | ||
no lado direito do sinal de atribuição. | no lado direito do sinal de atribuição. | ||
− | + | OBSERVAR que 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: | para o caso em que a função ''media_nums()'' retorna um valor, ela poderia ser usada como: | ||
Linha 287: | Linha 524: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float media, aux1, aux2, aux3; | float media, aux1, aux2, aux3; | ||
Linha 301: | Linha 538: | ||
media = media_nums(aux1, aux2, aux3); | media = media_nums(aux1, aux2, aux3); | ||
printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3)); | printf ("\nmedia dos 3 numeros multiplicada por 10 é %f\n", 10*media_nums(aux1, aux2, aux3)); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 306: | Linha 544: | ||
== Um parênteses sobre nome de variáveis == | == 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'') | + | *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. | + | *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. | Exercício: Execute o programa abaixo e verifique as saídas. | ||
Linha 353: | Linha 591: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | NOTA: variáveis LOCAIS não são iniciadas automaticamente | + | NOTA: variáveis LOCAIS não são iniciadas automaticamente com zero. Cabe ao programador iniciá-la corretamente. |
NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero. | NOTA: variáveis GLOBAIS são iniciadas automaticamente com zero. | ||
Linha 359: | Linha 597: | ||
Em sistemas embarcados pode não ser verdade! | Em sistemas embarcados pode não ser verdade! | ||
− | + | =Exercícios= | |
<ol> | <ol> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
<li> | <li> | ||
Linha 379: | Linha 605: | ||
float area_retang (float lado1 , float lado2) | float area_retang (float lado1 , float lado2) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | A função recebe os lados de um retângulo e retorna a área do mesmo. Crie uma VARIÁVEL LOCAL para armazenamento temporário da área. | ||
{{collapse top | Solução}} | {{collapse top | Solução}} | ||
+ | <!-- | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 395: | Linha 623: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float area; | float area; | ||
Linha 411: | Linha 639: | ||
printf("valor da area do retanguloa = %0.2f\n", area); | printf("valor da area do retanguloa = %0.2f\n", area); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | --> | ||
{{collapse bottom}} | {{collapse bottom}} | ||
− | |||
</li> | </li> | ||
Linha 424: | Linha 653: | ||
{{collapse top | Solução}} | {{collapse top | Solução}} | ||
+ | <!-- | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 434: | Linha 664: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float aux1, area; /* Variáveis LOCAIS */ | float aux1, area; /* Variáveis LOCAIS */ | ||
Linha 443: | Linha 673: | ||
area = area_circ(aux1); | area = area_circ(aux1); | ||
printf ("A area do circulo é %f\n", area); | printf ("A area do circulo é %f\n", area); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | --> | ||
{{collapse bottom}} | {{collapse bottom}} | ||
</li> | </li> | ||
Linha 452: | Linha 684: | ||
A função recebe o raio de dois círculos e retorna a diferença da área entre eles. Reaproveitar o exercício anterior. | A função recebe o raio de dois círculos e retorna a diferença da área entre eles. Reaproveitar o exercício anterior. | ||
− | {{collapse top | Solução | + | {{collapse top | Solução}} |
+ | <!-- | ||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 476: | Linha 709: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float dif; | float dif; | ||
Linha 491: | Linha 724: | ||
printf("valor da diferença = %0.2f\n", area); | printf("valor da diferença = %0.2f\n", area); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | --> | ||
{{collapse bottom}} | {{collapse bottom}} | ||
</li> | </li> | ||
+ | |||
+ | <li> | ||
+ | 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: | ||
+ | <syntaxhighlight lang=c> | ||
+ | float mod_complexo(float x, float y) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | {{collapse top | Solução}} | ||
+ | <!-- | ||
+ | <syntaxhighlight lang=c> | ||
+ | #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); | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | --> | ||
+ | {{collapse bottom}} | ||
+ | </li> | ||
+ | |||
+ | <li> | ||
+ | Elaborar uma função que recebe uma temperatura em graus em Fahrenheit e retorna graus celsius. | ||
+ | </li> | ||
+ | |||
+ | <li> | ||
+ | Elaborar uma função que calcula o índice massa corporal. Quais seriam os parâmetros da função? | ||
+ | </li> | ||
+ | |||
<li> | <li> | ||
Linha 501: | Linha 780: | ||
− | {{collapse top | Solução | + | {{collapse top | Solução}} |
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 521: | Linha 800: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
int i,x,y, soma_acumulada; | int i,x,y, soma_acumulada; | ||
Linha 533: | Linha 812: | ||
soma_acumulada = soma_int(x,y); | soma_acumulada = soma_int(x,y); | ||
printf("soma acumulada entre %d e %d é %d\n", x,y,soma_acumulada); | printf("soma acumulada entre %d e %d é %d\n", x,y,soma_acumulada); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 552: | Linha 832: | ||
qualquer subrprograma de função (independente de retornar valor). | qualquer subrprograma de função (independente de retornar valor). | ||
− | {{collapse top | Solução | + | {{collapse top | Solução}} |
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 567: | Linha 847: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
float num1, num2, num3; /* Variáveis LOCAIS */ | float num1, num2, num3; /* Variáveis LOCAIS */ | ||
Linha 578: | Linha 858: | ||
printf ("num2: %f\n", num2); | printf ("num2: %f\n", num2); | ||
printf ("num3: %f\n", num3); | printf ("num3: %f\n", num3); | ||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Linha 584: | Linha 865: | ||
<li> | <li> | ||
− | + | 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. | |
− | |||
− | |||
− | + | {{collapse top | Solução}} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | {{collapse top | Solução | ||
<!--<syntaxhighlight lang=c> | <!--<syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
Linha 617: | Linha 883: | ||
} | } | ||
− | main() | + | int main() |
{ | { | ||
int num1, num2; | int num1, num2; | ||
Linha 627: | Linha 893: | ||
resultado = calc_fatorial(num1) + calc_fatorial(num2); | resultado = calc_fatorial(num1) + calc_fatorial(num2); | ||
printf("Resultado: %d\n",resultado); | printf("Resultado: %d\n",resultado); | ||
− | + | return 0; | |
} | } | ||
</syntaxhighlight>--> | </syntaxhighlight>--> | ||
{{collapse bottom}} | {{collapse bottom}} | ||
+ | </li> | ||
− | |||
− | |||
− | |||
− | + | ||
+ | <li> | ||
+ | Considere o exercício para desenho de uma figura retangular tal como repassado em aula aula anterior. Confine a solução do problema em uma função onde são repassados a margem, o número de colunas e o número de linhas a ser impresso. A função deve ter o seguinte protótipo: | ||
+ | |||
+ | int desenhar_retang(int margem, int linha, coluna); | ||
+ | |||
+ | *A função somente aceita margem entre 0 e 10, linha entre 10 e 15 e coluna entre 10 e 15. | ||
+ | *A função DEVE chamar uma outra função cujo objetivo é desenhar linha; | ||
+ | *A função retorna o seguinte código: | ||
+ | |||
+ | **0 - Funcionamento Ok | ||
+ | **-1 - Não desenhado devido a erro em parâmetros passados. | ||
+ | |||
+ | Observe um exemplo de como poderia ser chamada esta função: | ||
+ | |||
<syntaxhighlight lang=c> | <syntaxhighlight lang=c> | ||
#include <stdio.h> | #include <stdio.h> | ||
− | + | int desenhar_retang(int margem, int linha, coluna) | |
− | + | { | |
− | + | /* implementar aqui */ | |
− | { | ||
− | |||
− | |||
− | |||
} | } | ||
− | + | ||
+ | |||
main() | main() | ||
{ | { | ||
− | + | desenhar_retang(5,10,30); | |
− | + | } | |
− | + | </syntaxhighlight> | |
− | + | </li> | |
− | + | ||
− | + | <li> Faça uma função para computar o número <math>e</math> usando série da seguinte forma: | |
− | + | <math>\sum_{n=0}^\infty \frac{1}{n!} = e </math>. Observe que onde está infinito deve ser usado um parâmetro que permita limitar a computação a alguns termos. Esta função deve se UTILIZAR de uma outra função (a ser implementada) que faz a computação do fatorial de um número. | |
+ | |||
+ | Demonstre o funcionamento na função main(). O esqueleto da função é dado: | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | float calc_e(int max_n) | ||
+ | { | ||
+ | // esta função deve chamar a função fatorial... | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | </li> | ||
+ | <li> Faça uma função para computar a combinação simples de 'n' elementos agrupados 'p' a 'p' dada pela fórmula (extraído de [https://pt.wikipedia.org/wiki/Combina%C3%A7%C3%A3o) Wikipedia]: | ||
+ | <br> | ||
+ | |||
+ | <math>C^n_p={n\choose p} =\frac{n!}{p!\cdot\left(n-p\right)!}</math> | ||
+ | </br> | ||
+ | A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de uma função que calcula o fatorial (''fat''()). O programa ''main'' deve testar o funcionamento da função, imprimindo a combinação de 4 elementos 2 a 2. | ||
+ | |||
+ | <syntaxhighlight lang=c> | ||
+ | |||
+ | int fat(int n) | ||
+ | { | ||
+ | } | ||
+ | |||
+ | int combinacao (int n, int p) | ||
+ | { | ||
+ | |||
+ | } | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | /* testar aqui */ | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | </li> | ||
+ | <li> Faça uma função para computar uma aproximação da função exponencial através dos N primeiros termos de: [https://pt.wikipedia.org/wiki/S%C3%A9rie_de_Taylor Wikipedia]: | ||
+ | <br> | ||
+ | |||
+ | |||
+ | <math>\mathrm{e}^{x} = \sum^{\infin}_{n=0} \frac{x^n}{n!}</math> | ||
+ | </br> | ||
+ | |||
+ | Exemplo: Caso se deseje computar com N=5 teremos: | ||
+ | |||
+ | <br> | ||
+ | <math>\mathrm{e}^{x} \approx \sum^{4}_{n=0} \frac{x^n}{n!}</math> que corresponde a somar os termos para n de 0 a 4: | ||
+ | |||
+ | <math>\frac{x^0}{0!} + \frac{x^1}{1!} + \frac{x^2}{2!} + \frac{x^3}{3!} + \frac{x^4}{4!}</math> | ||
+ | </br> | ||
+ | |||
+ | A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de: | ||
+ | :uma função que calcula o fatorial (''fat''()) | ||
+ | :uma função que computa a exponenciação (''expon''()). | ||
+ | <syntaxhighlight lang=c> | ||
+ | float expon(float x, int n) | ||
+ | { | ||
+ | /* implementar */ | ||
+ | } | ||
+ | |||
+ | int fat(int n) | ||
+ | { | ||
+ | /* implementar */ | ||
+ | } | ||
+ | float func_exp (int x, int N) | ||
+ | { | ||
+ | int n; | ||
+ | float soma_ac = 0; | ||
+ | |||
+ | /* esqueleto da solução */ | ||
+ | for(n = 0; n < N; n++) | ||
+ | soma_ac = soma_ac + expon(x,n)/fat(n); | ||
+ | /* retornar: a fazer */ | ||
+ | } | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | /* exemplo de uso*/ | ||
+ | float valor; | ||
+ | |||
+ | /* calcula os 5 primeiros termos da série correspondente a e^4.3 */ | ||
+ | valor = func_exp(4.5,5); | ||
+ | |||
+ | return 0; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | </li> | |
+ | <li> | ||
+ | Elaborar uma função que imprime uma mensagem:<br /> | ||
+ | '''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. Será que é importante que esta função retorne um valor? | ||
+ | </li> | ||
+ | |||
+ | <li> | ||
+ | Elaborar uma função "linha_vazada()" para desenhar uma linha da forma:<syntaxhighlight> | ||
+ | XXbbbbbbbbbbbXX | ||
+ | </syntaxhighlight> | ||
+ | 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<br /> | ||
+ | total da linha (número de espaços em branco) mas mantendo sempre os lados com XX. | ||
+ | |||
+ | </li> | ||
+ | |||
+ | </ol> | ||
− | |||
− | |||
− | |||
− | |||
− | + | <!--<div> | |
+ | # | ||
+ | ## | ||
## Refazer o exercício anterior decompondo a função em 2 subproblemas: desenhar linha_cheia e desenhar_corpo<span class="single_linebreak" title="single linebreak" contenteditable="false"></span><code><div> | ## Refazer o exercício anterior decompondo a função em 2 subproblemas: desenhar linha_cheia e desenhar_corpo<span class="single_linebreak" title="single linebreak" contenteditable="false"></span><code><div> | ||
### include <stdio.h></div></div> | ### include <stdio.h></div></div> |
Edição atual tal como às 11h25min de 31 de outubro de 2023
Objetivos da Aula
- Conceituar funções, parâmetros e valor de retorno;
- Definir, declarar e chamar funções no C;
- Declarar protótipo de funções;
- Distinguir e saber criar variáveis locais e globais;
- Aplicar funções para resolver subproblemas de um grande problema;
- Noção de recursividade e o cuidado no uso...
Referências Históricas
Conceito de Função
Uma função é um "bloco de código" que resolve um dado problema específico, que possui um nome associado e que pode ser chamado quando necessário. Ao final da função a linha de execução retorna para quem chamou a função.
Exemplo: para calcular o seno de um ângulo chamamos uma função para resolver o problema específico: "calcular um seno". Dados de entrada devem ser fornecidos, no caso o ângulo. O dado de saída é o seno computado deste ângulo.
Notar que a função permite REAPROVEITAR o código. Não precisamos a todo momento reescrever um código que computa o seno. Basta chamar a função.
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 fututamente).
Exemplo: Implementar uma função que imprimi uma linha com 10 caracteres X lado a lado. Na sequência, melhorar a função e imprimir 5 linhas com 10 caracteres Y cada.
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 somar_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 = somar_dois_dados();
printf("Valor da jogada de dados é %d\n", teste);
return 0;
}
Considere uma aplicação que deve gerenciar salas e usuários de uma instituição. Ela deve permitir cadastrar salas e usuários para alguma finalidade. Teríamos que apresentar menus e submenus para esta facilidade. O código abaixo demonstra esta possibilidade. Note que o código somente apresenta os menus e o uso de funções para apresentar submenus e retornar ao menu principal. Ele não apresenta a lógica necessária para gerenciar usuários e salas.
Obs: Baseado nas discussões em cboard.cprogramming.com
Exemplo de menus e submenus usando funções para chamada de submenus |
---|
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
/* Autores: Professores PRG1 - IFSC -SJ */
/******************************************/
/*
Para fins didáticos estão concentradas aqui
todas as funções para exemplificar a elaboração
de menus em modo texto.
Em versões finais o código deve ser organizado em arquivos .h
e .c, agrupando as funções conforme a funcionalidade.
Por exemplo: em um arquivo salas.c colocar as funções
de gerenciamento de sala, com os protótipos no salas.h
*/
/******************************************/
/******************************************/
/* Protótipos de funções - colocar em .h */
/******************************************/
void gerenciar_usuarios();
void gerenciar_salas();
void adicionar_usuario();
void remover_usuario();
void adicionar_sala();
void remover_sala();
/******************************************/
/* Variáveis Globais */
/******************************************/
/* a fazer */
/******************************************/
int main()
{
int opcao;
do {
system("clear");
printf("**********************************\n");
printf("Menu Nível 1\n\n");
printf("1. Gererenciar Usuários\n");
printf("2. Gerenciar Salas\n");
printf("3. Sair\n");
printf("**********************************\n");
scanf("%d",&opcao);
switch (opcao) {
case 1: gerenciar_usuarios();
break;
case 2: gerenciar_salas();
break;
case 3: printf("Finalizando Programa...\n");
break;
default: printf("Opção inexistente. Tente novamente...\n");
sleep(1); /* tempo somente para fins de visualização */
break;
}
} while (opcao != 3);
}
/***************************************************/
/* Esta funções deveriam estar em arquivo separado */
/***************************************************/
void gerenciar_usuarios()
{
int opcao;
do {
system("clear");
printf("**********************************\n");
printf("Menu Nível 2 - Gerenciar Usuários\n\n");
printf("1. Adicionar Usuário\n");
printf("2. Remover Usuário\n");
printf("3. Sair do Gerenciar Usuários\n");
printf("**********************************\n");
scanf("%d",&opcao);
switch (opcao) {
case 1: adicionar_usuario();
break;
case 2: remover_usuario();
break;
case 3: printf("Finalizando Gerenciar Usuários...\n");
sleep(1); /* tempo somente para fins de visualização */
break;
default: printf("Opção inexistente. Tente novamente...\n");
sleep(1); /* tempo somente para fins de visualização */
break;
}
} while (opcao != 3);
}
void adicionar_usuario()
{
/* aqui poderia ter um menu nível 3 */
printf("adicionando usuário\n ");
sleep(1);
printf("usuário adicionado\n ");
sleep(1);
}
void remover_usuario()
{
/* aqui poderia ter um menu nível 3 */
printf("removendo usuário\n ");
sleep(1);
printf("usuário removido\n ");
sleep(1);
}
/***************************************************/
/* Esta funções deveriam estar em arquivo separado */
/***************************************************/
void gerenciar_salas()
{
int opcao;
do {
system("clear");
printf("**********************************\n");
printf("Menu Nível 2 - Gerenciar Salas\n\n");
printf("1. Adicionar Sala\n");
printf("2. Remover Sala\n");
printf("3. Sair do Gerenciar Salas\n");
printf("**********************************\n");
scanf("%d",&opcao);
switch (opcao) {
case 1: adicionar_sala();
break;
case 2: remover_sala();
break;
case 3: printf("Finalizando Gerenciar Sala...\n");
sleep(1); /* tempo somente para fins de visualização */
break;
default: printf("Opção inexistente. Tente novamente...\n");
sleep(1); /* tempo somente para fins de visualização */
break;
}
} while (opcao != 3);
}
void adicionar_sala()
{
/* aqui poderia ter um menu nível 3 */
printf("adicionando sala\n ");
sleep(1);
printf("sala adicionada\n ");
sleep(1);
}
void remover_sala()
{
/* aqui poderia ter um menu nível 3 */
printf("removendo sala\n ");
sleep(1);
printf("sala removida\n ");
sleep(1);
}
|
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. Note que se trata de um exemplo pois NÃO seria necessário uma função para esta finalidade.
#include <stdio.h>
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
int 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);
return 0;
}
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 lista_instruções return; /* comando de retorno - pode ou não retornar valor - pode ser omitido */ }
Por enquanto, assumiremos que variáveis devem ser somente declaradas no início da função (logo após a abertura do bloco com '{'. Existem situações que poderemos relaxar esta afirmação.
U ponto a ser observado é a questão do retorno de uma função. Se a função não retorna um valor então tipo de retorno deve ser void. Neste caso, para realizar o retorno no código deve ser usada a palavra reservada return.
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. Neste último é repassado o endereço da variável para a função. 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():
#include <stdio.h>
/* OBS: num1, m2 e num3 são os parâmetros formais */
float media_nums(float num1, float num2, float num3)
{
float media_local;
media_local = (num1 + num2 + num3)/3;
return media_local;
}
int 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);
return 0;
}
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 N 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?
- A função retorna valor? De que tipo?
- Quais funções da biblioteca são usadas na sua impleemntação?
- Liste possíveis variações desta função.
Variáveis GLOBAIS e variáveis LOCAIS
Se variáveis são declaradas dentro de uma função (ou dentro de um bloco de código}, então a visibilidade (ESCOPO) destas variáveis é LOCAL, ou seja restrita ao código do bloco. Nenhuma outra função tem acesso a estas variáveis. Na realidade, o ESCOPO da variável 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.
Uma BOA PRÁTICA é evitar o uso de variáveis GLOBAIS para minimizar possibilidade de erros nos programas.
Seja o exemplo anterior modificado:
#include <stdio.h>
float media; /* Variável GLOBAL */
void media_nums(float num1, float num2, float num3)
{
media = (num1 + num2 + num3)/3;
return;
}
int 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);
return 0;
}
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.
OBSERVAR que 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;
}
int 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));
return 0;
}
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 com zero. 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 um programa contendo uma função da forma:
float area_retang (float lado1 , float lado2)
A função recebe os lados de um retângulo e retorna a área do mesmo. Crie uma VARIÁVEL LOCAL para armazenamento temporário da área.
Solução -
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 -
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 -
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 - Elaborar uma função que recebe uma temperatura em graus em Fahrenheit e retorna graus celsius.
- Elaborar uma função que calcula o índice massa corporal. Quais seriam os parâmetros da função?
-
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 #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; } int 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); return 0; }
-
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 #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; } int 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); return 0; }
-
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 -
Considere o exercício para desenho de uma figura retangular tal como repassado em aula aula anterior. Confine a solução do problema em uma função onde são repassados a margem, o número de colunas e o número de linhas a ser impresso. A função deve ter o seguinte protótipo:
int desenhar_retang(int margem, int linha, coluna);
- A função somente aceita margem entre 0 e 10, linha entre 10 e 15 e coluna entre 10 e 15.
- A função DEVE chamar uma outra função cujo objetivo é desenhar linha;
- A função retorna o seguinte código:
- 0 - Funcionamento Ok
- -1 - Não desenhado devido a erro em parâmetros passados.
#include <stdio.h> int desenhar_retang(int margem, int linha, coluna) { /* implementar aqui */ } main() { desenhar_retang(5,10,30); }
- Faça uma função para computar o número usando série da seguinte forma:
. Observe que onde está infinito deve ser usado um parâmetro que permita limitar a computação a alguns termos. Esta função deve se UTILIZAR de uma outra função (a ser implementada) que faz a computação do fatorial de um número.
Demonstre o funcionamento na função main(). O esqueleto da função é dado:
float calc_e(int max_n) { // esta função deve chamar a função fatorial... }
- Faça uma função para computar a combinação simples de 'n' elementos agrupados 'p' a 'p' dada pela fórmula (extraído de Wikipedia:
A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de uma função que calcula o fatorial (fat()). O programa main deve testar o funcionamento da função, imprimindo a combinação de 4 elementos 2 a 2.int fat(int n) { } int combinacao (int n, int p) { } int main() { /* testar aqui */ return 0; }
- Faça uma função para computar uma aproximação da função exponencial através dos N primeiros termos de: Wikipedia:
Exemplo: Caso se deseje computar com N=5 teremos:
que corresponde a somar os termos para n de 0 a 4:
A função deve ter a estrutura do esqueleto abaixo e DEVE se utilizar de:- uma função que calcula o fatorial (fat())
- uma função que computa a exponenciação (expon()).
float expon(float x, int n) { /* implementar */ } int fat(int n) { /* implementar */ } float func_exp (int x, int N) { int n; float soma_ac = 0; /* esqueleto da solução */ for(n = 0; n < N; n++) soma_ac = soma_ac + expon(x,n)/fat(n); /* retornar: a fazer */ } int main() { /* exemplo de uso*/ float valor; /* calcula os 5 primeiros termos da série correspondente a e^4.3 */ valor = func_exp(4.5,5); return 0; }
-
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. Será que é importante que esta função retorne um valor? -
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.