Você está na página 1de 33

Algoritmos e

estruturas de dados I
Módulos

Elverton Fazzion

Algoritmos e estruturas de dados I


Revisão

● Faça um programa que receba os coeficientes de uma


equação de segundo grau ( y(x) = ax² + bx + c), um valor
real para x e imprima na tela o valor resultante da
equação (y(x)). Você deve implementar uma função além
da main

Algoritmos e estruturas de dados I 2


Revisão

#include <stdio.h>

double calcula_equacao(double a, double b, double c, double x){


double y = a*x*x + b*x + c;
return y;
}

int main(){
double a, b, c, d;
printf(“Insira os coeficientes (a, b, c) e x:”);
scanf(“%lf %lf %lf %lf”, &a, &b, &c, &d);
double y = calcula_equacao(a, b, c, d);
printf(“Y=%.2lf\n”, y);
return 0;
}

Algoritmos e estruturas de dados I 3


Assinatura de função
● Para uma função ser utilizada, é necessário declará-la
primeiro
#include <stdio.h>

int main(){
double a, b, c, d;
printf(“Insira os coeficientes (a, b, c) e x:”);
scanf(“%lf %lf %lf %lf”, &a, &b, &c, &d);
calcula_equacao(a, b, c, d);
return 0;
}

double calcula_equacao(double a, double b, double c, double x){


double y = a*x*x + b*x + c;
return y;
}

Algoritmos e estruturas de dados I 4


Assinatura de função
● Podemos declarar uma função sem implementá-la
inicialmente
○ Uma assinatura de uma função é definida como

tipo_retorno nome_função(parâmetros);

○ Se houver parâmetros, podemos apenas indicar o tipo. Não é


necessário colocar o nome das variáveis na declaração.

tipo_retorno nome_função(tipo, tipo, …);

○ Exemplo:

double calcula_equacao(double, double, double, double);

Algoritmos e estruturas de dados I 5


Assinatura de função
● Com a assinatura da função, a linguagem C reconhece a
função e não gera erro, mesmo definindo a função
posteriormente
#include <stdio.h>

double calcula_equacao(double, double, double, double);

int main(){
double a, b, c, d;
printf(“Insira os coeficientes (a, b, c) e x:”);
scanf(“%lf %lf %lf %lf”, &a, &b, &c, &d);
calcula_equacao(a, b, c, d);
return 0;
}

double calcula_equacao(double a, double b, double c, double x){


double y = a*x*x + b*x + c;
return y;
}
Algoritmos e estruturas de dados I 6
Programa objeto
● Somente com a assinatura de função não é possível
gerar o programa final
○ Necessitamos da implementação da função!

#include <stdio.h>

double calcula_equacao(double, double, double, double);

int main(){
double a, b, c, d;
printf(“Insira os coeficientes (a, b, c) e x:”);
scanf(“%lf %lf %lf %lf”, &a, &b, &c, &d);
calcula_equacao(a, b, c, d);
return 0;
}

Algoritmos e estruturas de dados I 7


Programa objeto
● Porém podemos compilar um código de forma parcial
○ Não realizamos a etapa de ligação com bibliotecas!
○ Chamamos esse formato parcial de compilação de programa
objeto (arquivo com extensão .o)

Paramos a
compilação
aqui!
Programa Programa Programa
Compilador Ligador Executável
Fonte Objeto

Programa
Objeto das
Bibliotecas

Algoritmos e estruturas de dados I 8


Programa objeto
● Podemos gerar um programa objeto no gcc usando o -c
○ O arquivo gerado está em binário mas falta ligar com bibliotecas
○ Dessa forma, não é possível executá-lo
#include <stdio.h>

double calcula_equacao(double, double, double, double);

int main(){
double a, b, c, d;
printf(“Insira os coeficientes (a, b, c) e x:”);
scanf(“%lf %lf %lf %lf”, &a, &b, &c, &d);
calcula_equacao(a, b, c, d);
return 0;
}

Algoritmos e estruturas de dados I 9


Programa objeto
● Do ponto de vista mais prático, as etapas de compilação
podem ser vistas da seguinte forma

Falta o binário das Preenchido com


bibliotecas! bibliotecas pelo
01010101000 ligador!
01010101000
010XXXXXX01 01011110001
int main(){ 01010101101 01010101101
… YYYYY010101 00010010101
} 01010111110 01010111110
10000011111 10000011111

Programa Programa Programa


Compilador Ligador Executável
Fonte Objeto

Programa
Objeto das
Bibliotecas

Algoritmos e estruturas de dados I 10


Arquivos de cabeçalho (.h)
● E qual o objetivo disso tudo?
○ Até o momento estamos usando as funções printf e scanf da
biblioteca stdio.h sem se preocupar sobre como elas funcionam
○ Podemos implementar nossas próprias bibliotecas também!

● Observe que quando incluimos uma biblioteca em C,


colocamos extensão .h (e.g., <nome_biblioteca.h>)
○ Exemplo: <stdio.h>, <math.h>

● Um arquivo com extensão .h (header) possui somente


declarações
○ Implementações ficam em um arquivo com extensão .c

Algoritmos e estruturas de dados I 11


Arquivos de cabeçalho (.h)
● Exemplo: Podemos criar uma biblioteca que possui
funções para calcular informações sobre retângulos:
○ perímetro, área, diagonal

● Vamos criar, inicialmente, um arquivo de cabeçalho


(retangulo.h) com a assinatura das funções

// Função que calcula o perímetro de um retângulo


double perimetro_retangulo(double, double);

// Função que calcula a área de um retângulo


double area_retangulo(double, double);

// Função que calcula a diagonal de um retângulo


double diagonal_retangulo(double, double);

Algoritmos e estruturas de dados I 12


Arquivos de cabeçalho (.h)
● Para deixar a biblioteca completa, temos que implementar
as funções declaradas no .h
○ Para isso, usamos um arquivo .c com mesmo nome do arquivo .h
○ No nosso exemplo, criamos um arquivo retangulo.c
#include “retangulo.h” Incluímos o arquivo
#include <math.h>
de cabeçalho (.h)
// Função que calcula o perímetro de um retângulo no arquivo de
double perimetro_retangulo(double a, double b){ implementação (.c)
return 2*a + 2*b;
}

// Função que calcula a área de um retângulo


double area_retangulo(double a, double b){
return a * b;
}

// Função que calcula a diagonal de um retângulo


double diagonal_retangulo(double a, double b){
return sqrt(a*a + b*b);
}

Algoritmos e estruturas de dados I 13


Criando um módulo
● Para criar o módulo (ou biblioteca), podemos compilar
apenas o programa objeto

Programa objeto

Algoritmos e estruturas de dados I 14


Importando módulos
● Agora podemos usar nossa biblioteca de retângulos em
outros programas
○ <>: procura a biblioteca em pastas pré-definidas do sistema
○ “”: caminho do sistema até a biblioteca

Como vamos usar funções da biblioteca retângulo, incluimos


“retangulo.h”. Essa inclusão indica que o arquivo retangulo.h está
na mesma pasta do nosso programa!

#include “retangulo.h”
#include <stdio.h>

int main(){
double a = 2.0, b = 3.0;
printf(“Perimetro: %lf\n”, perimetro_retangulo(a, b));
printf(“Área: %lf\n”, area_retangulo(a, b));
printf(“Diagonal: %lf\n”, diagonal_retangulo(a, b));
return 0;
}

Algoritmos e estruturas de dados I 15


Compilação com módulos
● Se tentarmos compilar o programa anterior com gcc
main.c -o main, dará erro informando que não existem
algumas funções como area_retangulo

Algoritmos e estruturas de dados I 16


Compilação com módulos
● Para compilar um programa corretamente, temos que
incluir o nosso módulo

Algoritmos e estruturas de dados I 17


Visibilidade
● Quando o usuário importa o arquivo de cabeçalho (.h),
somente as funções definidas no cabeçalho podem ser
utilizadas pelo usuário
○ Funções que não estão definidas no cabeçalho são invisíveis pro
usuário (por exemplo, criadas somente dentro do arquivo .c)

double perimetro_retangulo(double, double);


double area_retangulo(double, double); Módulo fornece essas três
double diagonal_retangulo(double, double); funções para o usuário

retangulo.h

Algoritmos e estruturas de dados I 18


Visibilidade
double perimetro_retangulo(double, double);
double area_retangulo(double, double); retangulo.h
double diagonal_retangulo(double, double);

#include “retangulo.h”
#include <math.h>

double perimetro_retangulo(double a, double b){


return 2*a + 2*b;
}
double area_retangulo(double a, double b){
invisível pro return a * b; retangulo.c
usuário pois não }
tem definição em double diagonal_retangulo(double a, double b){
retangulo.h return sqrt(a*a + b*b);
}
double semiperimetro_retangulo(double a, double b){
return a + b;
}

Algoritmos e estruturas de dados I 19


Vantagens de usar módulos
● Encapsulamento!!!
○ O usuário das funções do módulo não precisa saber como as
funções são implementadas
○ O usuário precisa saber a semântica da função (o que ela faz), o
que ela recebe e o que ela gera!

Não precisamos saber como o printf() é


implementado. Precisamos saber
printf(“Oi, Mundo!”); apenas o que ele recebe como
parâmetro e o que ele gera como saída!

Algoritmos e estruturas de dados I 20


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
<TAB> gcc -c main.c

retangulo.o: retangulo.c retangulo.h


<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 21


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

Executa a primeira binario: main.o retangulo.o


regra <TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
<TAB> gcc -c main.c

retangulo.o: retangulo.c retangulo.h


<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 22


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

Tem dependência binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
<TAB> gcc -c main.c

retangulo.o: retangulo.c retangulo.h


<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 23


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

Resolve a main.o: main.c


dependência que é <TAB> gcc -c main.c
uma outra regra
(main.o) retangulo.o: retangulo.c retangulo.h
<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 24


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

Arquivo main.c main.o: main.c


existe! Dependência <TAB> gcc -c main.c
satisfeita
retangulo.o: retangulo.c retangulo.h
<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 25


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
Executa o comando <TAB> gcc -c main.c
da regra, gerando o
main.o retangulo.o: retangulo.c retangulo.h
<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 26


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
Resolve a segunda <TAB> gcc -c main.c
dependência para
gerar retangulo.o retangulo.o: retangulo.c retangulo.h
<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 27


Makefile
● Podemos automatizar o processo de compilação de um
código usando o Makefile
○ Um makefile é composto por regras

<nome da regra>: <dependencias>


<TAB> <comando>

Com as binario: main.o retangulo.o


dependências <TAB> gcc main.o retangulo.o -o main -lm
resolvidas, executa
o comando para main.o: main.c
gerar nosso binário <TAB> gcc -c main.c
com nome main
retangulo.o: retangulo.c retangulo.h
<TAB> gcc -c retangulo.c

Algoritmos e estruturas de dados I 28


Makefile

● O arquivo Makefile deve estar na pasta do código que


iremos compilar
○ Dessa forma, basta dar o comando make que ele irá gerar o
binário automaticamente

Comandos executados na ordem das


dependências que analisamos anteriormente
no arquivo Makefile

Algoritmos e estruturas de dados I 29


Makefile
● Podemos também especificar qual regra executar
○ Basta dar um “make <nome_da_regra>”
○ Por exemplo, podemos ter uma regra que limpa a pasta de
arquivos indesejados (*.o)

binario: main.o retangulo.o


<TAB> gcc main.o retangulo.o -o main -lm

main.o: main.c
<TAB> gcc -c main.c

retangulo.o: retangulo.c retangulo.h


<TAB> gcc -c retangulo.c

clean:
<TAB> rm *.o

Algoritmos e estruturas de dados I 30


Makefile
● Vantagens de usar o Makefile
○ Para programas com módulos, torna a compilação mais fácil de
realizar
○ É mais rápido também pois, em caso de mudança no código,
somente o módulo que foi alterado que é compilado

● Existe um documento no Portal Didático chamado


Direcionamentos básicos de programação
○ Recomendo fortemente a leitura das seções 4 e 5

Algoritmos e estruturas de dados I 31


Exercício de revisão
● Faça um módulo com funções para calcular as seguintes
informações abaixo sobre triângulos
○ perímetro, área e se o triângulo é isósceles, escaleno ou
equilátero
○ Considere que as funções do módulo recebam os lados do
triângulo e que são do tipo double

Para calcular a área de um triângulo,


p é o semi-perímetro!
use a Fórmula de Heron

Algoritmos e estruturas de dados I 32


Algoritmos e
estruturas de dados I
Módulos

Elverton Fazzion

Algoritmos e estruturas de dados I

Você também pode gostar