Sie sind auf Seite 1von 80

Algoritmos e Estruturas de Dados I

IEC012

Procedimentos
e
Funções

Baseado nas Notas de Aula do Prof.


Leandro Galvão
Procedimentos e Funções

❖ Procedimentos – são estruturas que agrupam um


conjunto de comandos, que são executados
quando o procedimento é chamado.

❖ Funções – são procedimentos que retornam um


valor ao seu término. É como se o nome da
função assumisse o valor de retorno.

❖ A Linguagem C não faz distinção.


Porque utilizar procedimentos e funções?

❖ Evitam que os blocos do programa fiquem


grandes demais e mais difíceis de ler e entender.

❖ Ajudam a organizar o programa.

❖ Permitem reaproveitamento de códigos


construídos anteriormente.

❖ Evitam repetição de trechos de códigos,


minimizando erros e facilitando alterações.
Funções
:: Como declarar

<tipo>
<tipo> nome_da_função
nome_da_função (<tipo>
(<tipo> arg1,
arg1, <tipo>
<tipo> arg2,
arg2, ...,
...,
<tipo>
<tipo> argN)
argN)
{{

<corpo
<corpo da
da função>
função>
return
return valor_de_retorno;
valor_de_retorno;
}}
Funções
:: Como declarar

❖ Exemplo de uma função:

int
int soma(int
soma(int a, a, int
int b)
b)
{{
int
int c;c;
cc == aa ++ b;
b;
return
return c; c;
}}
Funções
:: Como declarar
Toda função deve ter um tipo
(char, int, float), o qual indicará o
tipo de seu valor de retorno
(saída).

int
int soma(int
soma(int a, a, int
int b)
b)
{{
int
int c;c;
cc == aa ++ b;
b;
return
return c; c;
}}
Funções
:: Como declarar
Os argumentos (ou parâmetros)
indicam o tipo e quais valores são
esperados para serem manipulados
pela função (entrada).

int
int soma(int
soma(int a, a, int
int b)
b)
{{
int
int c;c;
cc == aa ++ b;
b;
return
return c; c;
}}
Funções
:: Como declarar

int
int soma(int
soma(int a, a, int
int b)
b)
{{
int
int c;c;
Corpo da função
cc == aa ++ b;
b;
return
return c; c;
}}
Funções
:: Como declarar

❖ Uma função pode não ter argumentos,


basta não informá-los. Exemplo:

int
int random()
random()
{{
srand(time(NULL));
srand(time(NULL));
return
return (rand()
(rand() %% 100);
100);
}}
Funções
:: Como declarar

❖ A expressão contida no comando return é


chamado de valor de retorno da função.

❖ Usualmente, este comando é sempre o último a


ser executado por uma função. Nada após ele
será executado.

❖ As funções só podem ser declaradas fora de


outras funções. Lembre-se que o corpo do
programa principal (main()) é uma função!
Funções
:: Invocando

❖ Uma forma clássica de realizarmos a invocação


(ou chamada) de uma função é atribuindo o seu
valor a uma variável:

resultado
resultado == soma(x,y);
soma(x,y);

❖ Na verdade, o resultado da chamada de uma


função é uma expressão, que pode ser usada em
qualquer lugar que aceite uma expressão:

printf("Soma:
printf("Soma: %d\n",
%d\n", soma(a,b)
soma(a,b) );
);
Funções
:: Invocando

❖ Função que calcula a soma dos valores de


x e y:
int
int x,
x, y,
y, resultado;
resultado;
int
int soma(int
soma(int a,
a, int
int b){
b){
return
return (a
(a ++ b);
b);
}}

int
int main(){
main(){
xx == 3;
3;
yy == 5;
5;
resultado
resultado == soma(x,
soma(x, y);
y);
printf("%d\n",
printf("%d\n", resultado);
resultado);
}}
Funções
:: Invocando

❖ As variáveis x e y no exemplo anterior são


chamadas de parâmetros reais.

❖ Conforme exemplo anterior, os argumentos não


possuem necessariamente os mesmos nomes
que os parâmetros que a função espera.

❖ Seus valores são apenas copiados para a função


chamada, sem ser afetados pelas alterações nos
parâmetros dentro da função.
O tipo void

❖ É utilizado em procedimentos.
❖ É um tipo que representa o “nada”, ou
seja:
◗ uma variável desse tipo armazena conteúdo
indeterminado,
◗ uma função desse tipo retorna um conteúdo
indeterminado.
❖ Indica que uma função não retorna
nenhum valor, ou seja, é um
procedimento.
Procedimentos
:: Como declarar

void
void nome_do_procedimento
nome_do_procedimento (<tipo>
(<tipo> parâmetro1,
parâmetro1,
<tipo>
<tipo> parâmetro2,
parâmetro2, ...,
..., <tipo>
<tipo> parâmetroN)
parâmetroN)
{{
<corpo
<corpo do
do procedimento>
procedimento>
}}
Procedimentos
:: Como declarar

❖ Exemplo de procedimento:

void
void imprime_dobro(int
imprime_dobro(int x)
x)
{{
printf("Dobro
printf("Dobro de
de x:
x: %d",
%d", 2*x);
2*x);
}}
Procedimentos
:: Invocando

❖ Para invocarmos um procedimento, devemos


utilizá-lo como qualquer outro comando:

procedimento(parâmetros);
procedimento(parâmetros);

❖ Compare a diferença de invocação de uma


função:

resultado
resultado == função(parâmetros);
função(parâmetros);
Procedimentos
:: Invocando

int
int x,
x, y,
y, resultado;
resultado;

void
void soma()
soma()
{{
resultado
resultado == xx ++ y;
y;
}}

int
int main()
main()
{{
xx == 3;
3;
yy == 5;
5;
soma();
soma();
printf("%d\n",
printf("%d\n", resultado);
resultado);
}}
A função main()

❖ É uma função especial invocada


automaticamente pelo sistema operacional (OS)
ao iniciar o programa.

❖ Quando utilizado, o comando return informa ao


OS se o programa funcionou corretamente ou
não.

❖ O padrão é que um programa retorne:


◗ = zero – caso tenha funcionado corretamente ,
◗ ≠ zero – caso contrário.
Variáveis locais e globais

❖ Uma variável é chamada local quando é


declarada dentro de uma função. Nesse caso:
◗ Ela existe apenas dentro da função que a contém.
◗ Após o término da execução da função, ela deixa de
existir.

❖ Uma variável é chamada global quando é


declarada fora de qualquer função. Nesse caso:
◗ Pode ser acessada em qualquer parte do programa.
◗ Ela existe durante toda a execução do programa.
Variáveis locais e globais

❖ Boa prática de programação:


◗ Deve-se evitar o uso de variáveis globais.
◗ As funções devem modificar apenas as suas
variáveis locais e as variáveis passadas a elas
como parâmetros.
Escopo de variáveis

❖ O escopo de uma variável determina de que


partes do código ela pode ser acessada.

❖ A regra de escopo em C é bem simples:


◗ As variáveis globais são visíveis por todas as funções.
◗ As variáveis locais são visíveis apenas na função onde
foram declaradas.
Escopo de variáveis

❖ É possível declarar variáveis locais com o


mesmo nome de variáveis globais.
❖ Nesta situação, a variável local “esconde”
a variável global.

int
int nota;
nota;
void
void funcao()
funcao()
{{
int
int nota;
nota;
//
// Neste
Neste ponto,
ponto, nota
nota eh
eh variavel
variavel local.
local.
}}
Variáveis automáticas × estáticas

❖ Variáveis declaradas dentro de uma função


(locais) têm existência apenas enquanto a função
está sendo executada, deixando de existir
quando a função termina sua tarefa.

❖ Tal mecanismo é chamado pilha de execução:


1. A pilha de execução está vazia;
2. Ao iniciar a execução de um bloco {}, as variáveis são
empilhadas à medida em que são criadas;
3. Ao final de um bloco {}, essas variáveis são
desempilhadas, liberando espaço na memória.
Variáveis automáticas × estáticas

❖ Exemplo:
◗ Considere um procedimento que simplifica
uma fração
◗ A fração é guardada em um vetor de dois
elementos:
 posição 0: guarda o numerador
 posição 1: guarda o denominador

◗ A fração é simplificada dividindo-se cada


elemento pelo máximo divisor comum
Variáveis automáticas × estáticas

void
void simplifica(int
simplifica(int f[]) f[]) {{
A int
int num,
num, den;
den;
num
num == f[0];
f[0];
den
den == f[1];
f[1];
while
while (den)
(den) //
// Equivale
Equivale aa (den
(den !=
!= 0)
0)
{{
B int
int resto;
resto;
resto
resto == num
num %% den;
den;
num
num == den;
den;
den
den == resto;
resto;
}}
C f[0]
f[0] == f[0]/num;
f[0]/num;
f[1]
f[1] == f[1]/num;
f[1]/num;
}}
D
Variáveis automáticas × estáticas
:: Situação da pilha de execução

A Antes do laço while: B Dentro do laço while:

resto
num num
den den

C Após o laço while: D Depois do procedimento:

num
den
Variáveis automáticas × estáticas

❖ As variáveis locais também são conhecidas como


variáveis automáticas, por serem criadas e
destruídas sempre que a função for executada.
❖ Se houver uma atribuição de valor a uma
variável dentro de uma função, ela será realizada
todas as vezes em que essa função for chamada.
Variáveis automáticas × estáticas

❖ Para que uma função não destrua uma variável


local ao final da execução, é preciso declará-la
como estática.

❖ Para uma variável estática, a atribuição de valor


inicial acontece somente uma vez, quando a
variável é criada.

❖ Ao contrário das variáveis globais, as variáveis


estáticas só podem ser usadas dentro da função
que as declara.
Variáveis automáticas × estáticas

/*
/* Proc.
Proc. impressao
impressao de
de var.
var. local
local estatica
estatica */
*/
void
void proc_est()
proc_est()
{{
static
static int
int var
var == 100;
100;
printf("Variavel
printf("Variavel estatica:
estatica: %d\n",
%d\n", --var);
--var);
}}

/*
/* Proc.
Proc. impressao
impressao de
de var.
var. local
local automatica
automatica */
*/
void
void proc_auto()
proc_auto()
{{
int
int var
var == 100;
100;
printf("Variavel
printf("Variavel automatica:
automatica: %d\n",
%d\n", --var);
--var);
}}
Variáveis automáticas × estáticas

/*
/* Funcao
Funcao principal
principal */
*/
int
int main(void)
main(void)
{{
/*
/* variavel
variavel local
local automatica
automatica */
*/
proc_auto();
proc_auto();
proc_auto();
proc_auto();

printf("\n");
printf("\n");

/*
/* variavel
variavel local
local estatica
estatica */
*/
proc_est();
proc_est();
proc_est();
proc_est();

return
return 0;
0;
}}
Parâmetros

❖ Parâmetros ou argumentos são os valores


recebidos e/ou retornados por uma função.

❖ Podem ser divididos em duas categorias:


◗ Formais: correspondem aos parâmetros utilizados na
definição da função.
◗ Reais: correspondem aos parâmetros da função
chamadora utilizados para chamar a função.
Parâmetros

Parâmetros formais
int
int soma(int
soma(int a,a, int
int b)
b)
{{
return
return (a
(a ++ b);
b);
}}

int
int main()
main()
{{
int
int xx == 3;
3;
int
int yy == 5;
5;
printf("%d\n",
printf("%d\n", soma(x
soma(x ++ y));
y));
}}
Parâmetros
reais
Passagem de Parâmetros

❖ É o mecanismo de informar sobre quais valores o


processamento definido na função deve ser
realizado.

❖ Os parâmetros são passados para uma função de


acordo com a sua posição.

❖ Os parâmetros formais de uma função se


comportam como variáveis locais (criados na
entrada e destruídos na saída)

❖ Existem duas categorias:


◗ Por valor
◗ Por referência
Passagem de Parâmetros
:: Passagem por valor

❖ Os valores das 0001 1001

variáveis externas 0101 1010


1111 0101
(função chamadora) 1011 0011

são copiados para as var


0000
0000 0001
0001
0001
0001 1001
1001

variáveis internas da 0101


0101
1111
1010
1010
0101
1111 0101
função chamada. 1011 0011
0000 0001
0001 1001
❖ Alteração no valor das 0101 1010
1111 0101
variáveis terá efeito 1011 0011

local à função var_interna


0000 0001
0001 1001

chamada. 0101 1010


1111 0101
1011 0011
0000 0001
0001 1001
0101 1010
1111 0101
1011 0011
Passagem de Parâmetros
:: Passagem por valor

#include <stdio.h>
/* Calcula o quadrado de x */
int square (int x)
{
  printf ("O quadrado e %d",(x*x));
  return(0);
}

int main ()
{
  int num;
  printf ("Entre com um numero: ");
  scanf ("%d",&num);
   printf ("\n\n");
   square(num);
  return(0);
Passagem de Parâmetros
:: Passagem por valor

Na definição de square() dizemos
que a função receberá um
argumento inteiro x.

Quando fazemos a chamada à
função, o inteiro num é passado
como argumento.

Temos que satisfazer aos requisitos
da função quanto ao tipo e à
quantidade de argumentos
quando a chamamos.
Passagem de Parâmetros
:: Passagem por valor


Em seguida vamos dar um exemplo de
função de mais de uma variável.

Neste caso, os argumentos são separados por
vírgula e que deve-se explicitar o tipo de
cada um dos argumentos, um a um.

Note, também, que os argumentos passados
para a função não necessitam ser todos
variáveis porque mesmo sendo constantes
serão copiados para a variável de entrada da
função.
Passagem de Parâmetros
:: Passagem por valor

#include <stdio.h>
/* Multiplica 3 numeros */
int mult (float a, float b,float c) 
{
  printf ("%f",a*b*c);
  return(0);
}

int main ()
{
  float x,y;
  x=23.5;
  y=12.9;
  mult (x,y,3.87);
  return(0);
Passagem de Parâmetros
:: Passagem por referência

É um tipo de passagem de parâmetros em


❖É
que alterações nos parâmetros formais,
dentro da função, alteram os valores dos
parâmetros que foram passados para a
função.
Este tipo de chamada de função tem o nome
❖Este
de "chamada por referência".
Este nome vem do fato de que, neste tipo de
❖Este
chamada, não se passa para a função os
valores das variáveis, mas sim suas
referências (ou endereço das variáveis).
Passagem de Parâmetros
:: Passagem por referência

0001 1001
0101 1010
1111 0101
1011 0011
0000 0001
0001 1001
var 0101 1010
1111 0101
1011 0011
0000 0001
0001 1001
0101 1010
1111 0101
1011 0011
0000 0001
0001 1001
0101 1010
1111 0101
1011 0011
0000 0001
0001 1001
0101 1010
1111 0101
1011 0011
Passagem de Parâmetros
:: Passagem por referência

❖ Mas o C só faz chamadas por valor!!!


❖ Isto é bom quando queremos usar os
parâmetros formais à vontade dentro da
função, sem termos que nos preocupar
em estar alterando os valores dos
parâmetros que foram passados para a
função.
❖ Mas isto também pode ser ruim, porque
podemos querer mudar os valores dos
parâmetros fora da função também.
❖ Há entretanto, no C, um recurso de
programação que podemos usar para
simular uma chamada por referência.
Passagem de Parâmetros
:: Passagem por referência

❖ Quando queremos alterar as variáveis


que são passadas para uma função,
nós podemos declarar seus parâmetros
formais como sendo ponteiros.
❖ Os ponteiros são a "referência" que
precisamos para poder alterar a
variável fora da função.
❖ O único inconveniente é que, quando
usarmos a função, teremos de lembrar
de colocar um & na frente das
variáveis que estivermos passando
para a função.
Passagem de Parâmetros
:: Passagem por referência
#include <stdio.h>
void Swap (int *a,int *b)
{
  int temp;
  temp=*a;
  *a=*b;
  *b=temp;
}

void main (void)
{
  int num1,num2;
  num1=100;
  num2=200;
  printf ("Antes: num1=%d num2=%d\n",num1,num2);
  Swap (&num1,&num2);
  printf ("Depois: num1=%d num2=%d\n",num1,num2);
}
Passagem de Parâmetros
:: Passagem por referência

❖O que está acontecendo é que passamos


para a função Swap o endereço das variáveis
num1 e num2.
❖Estes endereços são copiados nos ponteiros
a e b.
❖Através do operador * estamos acessando o
conteúdo apontado pelos ponteiros e
modificando-o.
❖Mas, quem é este conteúdo? Nada mais que
os valores armazenados em num1 e num2,
que, portanto, estão sendo modificados!
Passagem de Parâmetros
:: Passagem por referência

❖ Será que nós já não vimos esta estória de


chamar uma função com as variáveis
precedidas de &?
❖ Sim! É assim que nós chamamos a função
scanf(). Mas porquê?
❖ A função scanf() usa chamada por referência
porque ela precisa alterar as variáveis que
passamos para ela!
❖ Ela lê variáveis para nós e portanto precisa
alterar seus valores. Por isto passamos para a
função o endereço da variável a ser
modificada!
Passagem de Parâmetros
:: Retornando Valores

❖ Muitas vezes é necessário fazer com que uma função


retorne um valor.
❖ As funções que vimos até aqui estavam
retornando o número 0.
❖ Podemos especificar um tipo de retorno
indicando-o antes do nome da função.
❖ Mas para dizer ao C o que vamos retornar
precisamos da palavra reservada return.
❖ Sabendo disto fica fácil fazer uma função para
multiplicar dois inteiros e que retorna o
resultado da multiplicação.
Passagem de Parâmetros
:: Retornando Valores

#include <stdio.h>
int prod (int x, int y)
{
  return (x*y);
}

int main ()
{
  int saida;
  saida = prod (12,7);
  printf ("A saida e: %d\n",saida);
  return(0);
}
Passagem de Parâmetros
:: Retornando Valores

❖ Como prod retorna o valor de 12 * 7, este valor pode


ser usado em uma expressão qualquer.
❖ No programa fizemos a atribuição deste
resultado à variável saida, que posteriormente
foi impressa usando o printf.
❖ Uma observação adicional: se não
especificarmos o tipo de retorno de uma
função, o compilador C automaticamente
suporá que este tipo é inteiro.
❖ Porém, não é uma boa prática não se
especificar o tipo de retorno.
Passagem de Vetores

❖ Vetores têm um comportamento diferente


quando usados como parâmetros ou valores de
retorno de funções.

❖ O compilador interpreta o nome de um vetor


como o endereço do primeiro elemento do vetor.

❖ Dessa forma, os vetores são sempre passados


por referência, sem usar uma notação especial.
Passagem de Vetores
:: Exemplo

<tipo>
<tipo> funcao(int
funcao(int vet[],
vet[], ...)
...)
{{
...
...
}}
Passagem de Vetores
:: Exemplo

void ler_vetor(int vet[], int n_elem)
void ler_vetor(int vet[], int n_elem)
{{
int i;
int i;
for (i = 0; i < n_elem; i++) {
for (i = 0; i < n_elem; i++) {
printf("vet[%d]: ", i);
printf("vet[%d]: ", i);
scanf("%d", &vet[i]);
scanf("%d", &vet[i]);
}}
}}

void imprime_vetor(int vet[], int n_elem)
void imprime_vetor(int vet[], int n_elem)
{{
int i;
int i;
for (i = 0; i < n_elem; i++) 
for (i = 0; i < n_elem; i++) 
printf("vet[%d]: %d\n", i, vet[i]);
printf("vet[%d]: %d\n", i, vet[i]);
}}
Passagem de Vetores

❖Ao passar um vetor como parâmetro,


se ele for alterado dentro da função,
as alterações ocorrerão no próprio
vetor e não em uma cópia.
❖Ao passar um vetor como parâmetro,
não é necessário fornecer o seu
tamanho na declaração da função.
❖Porém, é importante lembrar que o
vetor tem um tamanho que deve ser
considerado pela função durante a
manipulação dos dados.
Passagem de Vetores

❖ Quando o vetor é multidimensional, a


possibilidade de não informar o tamanho
na declaração da função se restringe
apenas à primeira dimensão.

void
void show_matriz(int
show_matriz(int mat[][10],
mat[][10], int
int n_linhas)
n_linhas)
{{
...
...
}}
Passagem de Vetores

❖ Quando o vetor é multidimensional, a


possibilidade de não informar o tamanho
na declaração da função se restringe
apenas à primeira dimensão.

void
void show_matriz(int
show_matriz(int mat[][10],
mat[][10], int
int n_linhas)
n_linhas)
{{
...
...
}}
Passagem de Vetores

void mostra_matriz(int mat[][10], int lin) 
void mostra_matriz(int mat[][10], int lin) 
{{
int i, j;
int i, j;
for (i = 0; i < lin; i++) {
for (i = 0; i < lin; i++) {
for (j = 0; j < 10; j++)
for (j = 0; j < 10; j++)
printf("%2d ", mat[i][j]);
printf("%2d ", mat[i][j]);
printf("\n");
printf("\n");
}}
}}
Passagem de Vetores

int
int main(void)
main(void)
{{
int
int mat[][10]
mat[][10] == {{
{00,
{00, 01,
01, 02,
02, 03,
03, 04,
04, 05,
05, 06,
06, 07,
07, 08,
08, 09},
09},
{10,
{10, 11,
11, 12,
12, 13,
13, 14,
14, 15,
15, 16,
16, 17,
17, 18,
18, 19},
19},
{20,
{20, 21,
21, 22,
22, 23,
23, 24,
24, 25,
25, 26,
26, 27,
27, 28,
28, 29},
29},
{30,
{30, 31,
31, 32,
32, 33,
33, 34,
34, 35,
35, 36,
36, 37,
37, 38,
38, 39},
39},
{40,
{40, 41,
41, 42,
42, 43,
43, 44,
44, 45,
45, 46,
46, 47,
47, 48,
48, 49},
49},
{50,
{50, 51,
51, 52,
52, 53,
53, 54,
54, 55,
55, 56,
56, 57,
57, 58,
58, 59},
59},
{60,
{60, 61,
61, 62,
62, 63,
63, 64,
64, 65,
65, 66,
66, 67,
67, 68,
68, 69},
69},
{70,
{70, 71,
71, 72,
72, 73,
73, 74,
74, 75,
75, 76,
76, 77,
77, 78,
78, 79}};
79}};
mostra_matriz(mat,
mostra_matriz(mat, 8);
8);
return
return 0;
0;
}}
Const

❖ Para indicar que um parâmetro de função não


deve ser alterado, pode-se utilizar o qualificador
const.

❖ Seu uso não inibe a alteração do parâmetro.

❖ Porém, se existir no corpo da função uma


alteração de um parâmetro declarado como
constante, o compilador gerará uma mensagem
de advertência.
Const

void copiar(const char *origem, char *destino)
void copiar(const char *origem, char *destino)
{{
while (*origem)
while (*origem)
*destino++ = *origem++;
*destino++ = *origem++;
}}

int main(void)
int main(void)
{{
char origem[8] = "Manaus";
char origem[8] = "Manaus";
char destino[8];
char destino[8];
printf("Antes\t Origem:%s\n", origem);
printf("Antes\t Origem:%s\n", origem);
copiar(origem, destino);
copiar(origem, destino);
printf("Depois\t Origem:%s ", origem);
printf("Depois\t Origem:%s ", origem);
printf("Destino: %s\n", destino);
printf("Destino: %s\n", destino);
   return 0;
   return 0;
}}
Parâmetros da função principal
:: argv, argc

❖ Parâmetros
◗ Argc (Número de argumentos recebidos)
 É um número inteiro
 Possui valor maior ou igual a 1(um)

◗ Argv (Guarda os argumentos recebidos)


 É um vetor de ponteiros para strings
 O primeiro argumento, argv[0], é sempre o nome do
programa

int
int main(int
main(int argc,
argc, char
char **argv)
**argv)
Parâmetros da função principal
:: argv, argc

❖ Exemplo. Ao executar:

./p66a
./p66a arg1
arg1 arg2
arg2 arg3
arg3 arg4
arg4

argc = 5 p 6 6 a
0 a r g 1
argv 1
a r g 2
2
3 a r g 3
4
a r g 4
Funções
:: Recursividade

❖ Um objeto é dito recursivo se pode ser


definido em termos de si próprio.

“Para
“Para fazer
fazer iogurte,
iogurte, você
você precisa
precisa de
de
leite
leite ee de
de um
um pouco
pouco de
de iogurte.”
iogurte.”

“Para
“Para entender
entender recursividade,
recursividade, você
você
primeiro
primeiro tem
tem de
de entender
entender
recursividade.”
recursividade.”
Funções
:: Recursividade

❖ A recursão é uma forma interessante de resolver


problemas, pois o divide em problemas menores
de mesma natureza.

❖ Um processo recursivo consiste de duas partes:


◗ O caso trivial, cuja solução é conhecida.
◗ Um método geral que reduz o problema a um ou mais
problemas menores de mesma natureza.
Funções
:: Recursividade – Fatorial

❖ Cálculo do fatorial:

1, se n = 1
fat(n) =
n * fat(n-1), se n > 1
Funções
:: Recursividade – Fatorial

❖ Função recursiva que calcula o fatorial de


um número:

int
int fat(int
fat(int n)
n)
{{
if
if (n
(n !=
!= 1)
1)
return
return nn ** fat(n-1);
fat(n-1);
else
else
return
return 1;
1;
}}
Funções
:: Recursividade – Série de Fibonacci

❖ Certos algoritmos são mais eficientes quando


feitos de maneira recursiva.

❖ Contudo, quando usada incorretamente, a


recursividade tende a consumir muita memória e
ser lenta.

❖ Um parcela da memória é reservada cada vez


que o computador faz chamada a uma função.

❖ Compare as duas implementações da série de


Fibonacci, uma realizada de forma iterativa e
outra de forma recursiva.
Funções
:: Recursividade – Série de Fibonacci

❖ Certos algoritmos são mais eficientes quando


feitos de maneira recursiva.
int
int fiborec(int
fiborec(int n)
n)
❖ Um parcela da memória é reservada cada vez
{{ que o computador faz chamada a uma função.
if
if ((n==1)
((n==1) ||
|| (n==2))
(n==2))
❖ Comparereturn 1;
as duas
return 1; implementações da série de
Fibonacci,
else
else uma realizada de forma iterativa e
outra return
de forma
return recursiva.
fiborec(n-1)
fiborec(n-1) ++ fiborec(n-2);
fiborec(n-2);

}}
Funções
:: Recursividade – Série de Fibonacci

int
int fibo_it(int
fibo_it(int n) n)
{{
int
int i,
i, a,
a, b,b, c;
c;
if
if ((n==1)
((n==1) || || (n==2))
(n==2)) return
return 1;1;
else
else
{{
aa == 1;
1; bb == 1;
1;
for
for (i(i == 3;
3; ii <=
<= n;
n; i++)
i++)
{{
cc == aa ++ b;
b; aa == b;
b; bb == c;
c;
}}
return
return c; c;
}}
}}
Funções
:: Recursividade – Torre de Hanói

❖ São dados n discos de diâmetro 1, 2, 3, ..., n,


dispostos por ordem decrescente no primeiro
poste.
❖ Pretende-se transferir todos os discos para o
terceiro poste, utilizando o menor número de
movimentos, de tal modo que as seguintes
restrições sejam satisfeitas:
1. Apenas um disco pode ser movido de cada vez.
2. Apenas os discos do topo podem ser movidos.
3. Um disco não pode ser colocado sobre outro menor.
Funções
:: Recursividade – Torre de Hanói
Funções
:: Recursividade – Torre de Hanói

void hanoi(int n, char orig, char dest, char ajuda)
void hanoi(int n, char orig, char dest, char ajuda)
{{
  if (n == 1)
  if (n == 1)
    printf("Mova disco %d de %c para %c \n", n, orig, dest);
    printf("Mova disco %d de %c para %c \n", n, orig, dest);
  else
  else
  {
  {
    hanoi(n­1, orig, ajuda, dest);
    hanoi(n­1, orig, ajuda, dest);
    printf("Mova disco %d de %c para %c \n", n, orig, dest);
    printf("Mova disco %d de %c para %c \n", n, orig, dest);
    hanoi(n­1, ajuda, dest, orig);
    hanoi(n­1, ajuda, dest, orig);
  }
  }
}}
Macros

❖ Macros são definições que aceitam


parâmetros (argumentos).

❖ Antes da compilação do programa C, o


pré-processador substitui as macros por
sua definição.

❖ A substituição só não é realizada dentro


de strings.
Macros

❖ Macros podem ser utilizadas no lugar de funções


simples.

❖ Não há verificação de tipo de dados para os


argumentos de uma macro, pois macros são
utilizadas simplesmente para substituição de
texto.

❖ Uma macro sem argumentos é processada como


uma constante simbólica.
Macros
#define
#define MAX
MAX 100
100
#define
#define TITULO
TITULO "maxi"
"maxi"
#define
#define MOSTRA(x)
MOSTRA(x) "Valor
"Valor (MAXIMO
(MAXIMO == %d):
%d): ",
", xx

int
int main()
main() {{
int
int maxi;
maxi;
printf(TITULO);
printf(TITULO);
printf(MOSTRA(MAX));
printf(MOSTRA(MAX));
scanf("%d",
scanf("%d", &maxi);
&maxi);
printf("Valor
printf("Valor lido
lido de
de MAX
MAX == %d\n",
%d\n", maxi);
maxi);
}}

int
int main()
main() {{
int
int maxi;
maxi;
printf("maxi");
printf("maxi");
printf("Valor
printf("Valor (MAXIMO
(MAXIMO == %d):
%d): ",
", 100);
100);
scanf("%d",
scanf("%d", &maxi);
&maxi);
printf("Valor
printf("Valor lido
lido de
de MAX
MAX == %d\n",
%d\n", maxi);
maxi);
}}
Macros

❖ No exemplo anterior:

//
// Constante
Constante numérica
numérica
#define
#define MAX
MAX 100
100

//
// Constante
Constante de
de caracteres
caracteres
#define
#define TITULO
TITULO "maxi"
"maxi"

//
// Macro
Macro
#define
#define MOSTRA(x)
MOSTRA(x) "Valor
"Valor (MAXIMO
(MAXIMO == %d):
%d): ",
", xx
Macros

❖ Mais exemplos de macros:

//
// Determina
Determina oo maior
maior entre
entre dois
dois números
números
#define
#define MAX(x)
MAX(x) (( ((x)
((x) >> (y))
(y)) ?? (x)
(x) :: (y)
(y) ))

//
// Determina
Determina oo menor
menor entre
entre dois
dois números
números
#define
#define MIN(x)
MIN(x) (( ((x)
((x) << (y))
(y)) ?? (x)
(x) :: (y)
(y) ))
Macros

❖ Para que tantos parênteses?

❖ Definições de macro devem utilizar


parênteses para garantir que a definição
esteja correta mesmo se os parâmetros
forem substituídos por expressões.
Macros

❖ Não incluir ponto-e-vírgula na definição de


constantes ou macros:

#define
#define SOMA
SOMA (x,y)
(x,y) ((x)
((x) ++ (y));
(y));
printf(“Resultado:
printf(“Resultado: %d”,
%d”, SOMA(3,5));
SOMA(3,5));

❖ Após o pré-processamento:

printf(“Resultado:
printf(“Resultado: %d”,
%d”, ((3)
((3) ++ (5)););
(5)););
Macros

❖ Não deixar espaço entre o nome da macro


e as lista de argumentos:

#define
#define SOMA
SOMA (x,y)
(x,y) ((x)
((x) ++ (y))
(y))

❖ A definição acima será interpretada como


uma constante cujo valor é:

(x,y)
(x,y) ((x)
((x) ++ (y))
(y))
Questões

Das könnte Ihnen auch gefallen