• Nenhum resultado encontrado

Programação imperativa. 10. Pilha de execução

N/A
N/A
Protected

Academic year: 2021

Share "Programação imperativa. 10. Pilha de execução"

Copied!
20
0
0

Texto

(1)

Programação imperativa

(2)

10. Pilha de execução

A pilha de execução.

Memória dinâmica.

(3)

10. Pilha de execução

A pilha de execução.

Memória dinâmica.

(4)

Pilha de execução

Em inglês, runtime stack.

A pilha de execução é formada por uma sequência de registos de ativação, cada um deles correspondendo a uma ativação de uma função, gerida em modo pilha. Em inglês, registo de ativação é stack frame.

Na presença de recursividade, pode haver na pilha várias

frames relativas a uma mesma função.

Na frame há espaço de memória para os argumentos da função, para as variáveis locais e para o endereço de

retorno.

As frames relativas a uma função têm todas o mesmo

(5)

Observando a pilha de execução

Este é o programa que

vamos usar, para observar a

pilha de execução.

#include <stdio.h> int g(int *a, int n) { int result = 0; int i; for (i = 0; i < n; i++) result += a[i]; return result; }

int f(int x, int y) { int result; int a[10]; int i = 0; for (i = 0; i < y; i++) a[i] = x;

result = g(a, y); return result; void t5(void) { int x; int y; x = g(primes, 10); y = f(3, 6); printf("%d %d\n", x, y); } int main(void) { t5(); return 0; }

(6)

Janela da pilha de execução

A função main chamou a função t2, que chamou a função g.

...

x = g(primes, 10); ...

int g(int *a, int n) { int result = 0; int i; for (i = 0; i < n; i++) result += a[i]; return result; }

Nesta altura, a variável result já foi

inicializada mas a variável i ainda não. O argumento n vale 10 e o argumento a referencia o array primes.

(7)

Janela da pilha de execução (2)

A função main chamou a função t2, que chamou a função f, que chamou a função g.

...

y = f(3, 6); ...

int f(int x, int y) { int result; int a[10]; int i = 0; for (i = 0; i < y; i++) a[i] = x;

result = g(a, y); return result; }

Note bem: o argumento a referencia a variável a da função f. Terem o mesmo nome é apenas uma coincidência.

(8)

Observando a recursividade

Se uma função se

chama a si própria, na

pilha de execução

passaremos a ter dois

frames seguidos, cada

um para cada ativação

da função.

Usemos o seguinte

exemplo, com a

função fatorial:

#include <stdio.h> int fact(int x) { return x == 0 ? 1 : x * fact(x-1); } void t6(void) { int z; z = fact(8); printf("%d\n", z); } int main(void) { t6(); return 0; }

A função fact chama-se a si própria, quando o

argumento é diferente de zero.

(9)

Observando a recursividade (2)

Aqui estamos a desempilhar: a função retornou 120, quando x valia 5 e agora está na frame onde x vale 6.

Aqui estamos a empilhar: a função main chamou t3, que chamou fact, que chamou fact, que chamou fact, que chamou fact, que chamou fact, que chamou fact. Nesta altura, o argumento é 3.

(10)

Memória da pilha de execução

Usemos a seguinte função para inspeccionar a

memória da pilha de execução.

int facta(int x) { int v[2]; v[0] = primes[x]; v[1] = powers[x]; return x == 0 ? 1 : x * facta(x-1); } void t7(void) { int z; z = facta(8); printf("%d\n", z); }

O array v serve só para nos ajudar a localizar a

memória de cada ativação da função facta.

(11)

Memória da pilha de execução (2)

A memória da pilha de execução, logo após

chamada facta(6), antes da inicialização do array v. Conseguimos localizar as posições de memória onde estão os argumentos

(marcadas a azul) e as sucessivas ativações do array v (marcadas a vermelho).

(12)

10. Pilha de execução

A pilha de execução.

Memória dinâmica.

(13)

Memória dinâmica

A função f usada no exemplo da pilha de execução é insegura: se y for maior do que 10, o array a, declarado na função, vai transbordar.

Qual deve então ser a capacidade do array a?

Deve ser y!

Só que o valor de y não pode ser determinado no momento da compilação.

A capacidade dos arrays estáticos ou automáticos deve ser uma constante, conhecida no momento da

compilação.

Isso permite que a frame de cada função tenha um

tamanho determinado durante a compilação.

(14)

malloc

A função malloc requisita ao sistema de operação o número de bytes indicado no argumento.

Observe a função f1, equivalente a f, mas onde o array a é alocado dinamicamente, com malloc:

int f1(int x, int y) {

int result;

int *a = (int *) malloc(y * sizeof(int));

int i = 0;

for (i = 0; i < y; i++) a[i] = x;

result = g(a, y);

free(a);

return result; }

Dizemos que o array a é alocado dinamica-mente ou que fica na memória dinâmica.

No fim da função, devemos libertar a memória alocada dinamicamente.

Para usar malloc, temos de fazer #include <stdlib.h>

O número de bytes é o número de elementos vezes o número de bytes de cada elemento.

(15)

Experimentando f1

void t8(void) { int x; x = f(1, 10); printf("%d\n", x); x = f(1, 10000); printf("%d\n", x); } void t81(void) { int x; x = f1(1, 10); printf("%d\n", x); x = f1(1, 10000); printf("%d\n", x); } 10 10 10000

Press any key to continue . . .

(16)

Onde está a memória dinâmica?

Procuremos, com a seguinte função:

int f2(int x, int y) {

int result;

int *a = (int *) malloc(y * sizeof (int)); int b[10]; int i = 0; for (i = 0; i < y; i++) a[i] = x; for (i = 0; i < 10; i++) b[i] = x * i;

result = g(a, y); free(a);

return result; }

Com este exemplo,

teremos os arrays primes e powers na memória estática, o array b na

memória automática e o array a na memória

(17)

Observando a memória dinâmica

Estática

Automática

Situação mesmo antes da instrução free na função f2.

(18)

10. Pilha de execução

A pilha de execução.

Memória dinâmica.

(19)

Conversão hexadecimal-decimal

Note bem: não há números hexadecimais. Há sim a notação hexadecimal.

Problema: representar decimalmente um número dado usando a representação

hexadecimal. Observe:

void hex2dec(void) {

int x;

while (scanf("%x", &x) != EOF) printf("%d\n", x); } 0022fb60 2292576 cccccccc -858993460 00000001 1 00000010 16 00000100 256 00001000 4096 00010000 65536 00100000 1048576 01000000 16777216 10000000 268435456 7fffffff 2147483647 80000000 -2147483648 ffffffff

(20)

Conversão decimal-hexadecimal

Para converter no sentido decimal ->

hexadecimal é parecido:

void dec2hex(void) {

int x;

while (scanf("%d", &x) != EOF) printf("%x\n", x); } 10 a 100 64 64 40 204 cc 2147483647 7fffffff -1 ffffffff 255 ff 160 a0 170 aa 17 11 26 1a

Referências

Documentos relacionados

As Universidades que integram a Rede Nacional de Formação Continuada nas áreas de alfabetização/ linguagem e de matemática são responsáveis pelo desenvolvimento e produção

Para instalação em tubo de escoamento, retire a curva plástica, empurrando a mangueira para dentro da curva plástica e, em seguida, para cima.Nunca solte a mangueira

• Hubs Criativos (projeto FAPESP – Disseminação e Compartilhamento de conhecimento em Hubs Criativos - em parceria com Queen Mary University of London, University of West of England

Dependendo se você usa o terminal com o portal farmpilot, ou transfere os dados para um dispositivo USB a partir do sistema gerencial de campo, o dispositivo USB deve conter outras

122 do CP, o qual prevê a conduta de instigação, auxílio ou induzimento ao suicídio, não admite a forma tentada (art. Nesse sentido, como Maria teve apenas alguns arranhões,

•   O  material  a  seguir  consiste  de  adaptações  e  extensões  dos  originais  gentilmente  cedidos  pelo 

Declaro meu voto contrário ao Parecer referente à Base Nacional Comum Curricular (BNCC) apresentado pelos Conselheiros Relatores da Comissão Bicameral da BNCC,

libras ou pedagogia com especialização e proficiência em libras 40h 3 Imediato 0821FLET03 FLET Curso de Letras - Língua e Literatura Portuguesa. Estudos literários