1 MCTA028 Programação Estruturada - Mapa de memória de um processo - Ponteiros Material preparado a partir de slides dos profs. Jesús Mena-Chalco e Fabrício Olivetti Luiz Rozante 3Q-2018
2 Alocação de memória Na execução, um programa é um processo. (processos de SOs são módulos executáveis únicos) Um processo ocupa parte da memória principal, reservada para: instruções, dados, pilha, heap O espaço de endereços de um processo em execução é dividido nessas 4 áreas (as mais importantes)
3 Alocação de memória Modelo geral de organização da memória:
4 Alocação de memória Text area: contém o código do programa e suas constantes. Esta área é alocada durante a chamada exec e permanece do mesmo tamanho durante toda a vida do processo. Data area: é a memória de trabalho do processo, onde ele armazena suas variáveis globais e estáticas. Tem tamanho fixo ao longo da execução do processo. Stack area: contém a pilha de execução, onde são armazenadas os parâmetros, endereços de retorno e variáveis locais de funções. Pode variar de tamanho durante a execução do processo. Heap area: contém áreas de memória alocadas a pedido do processo, durante sua execução. Varia de tamanho durante a vida do processo.
5 Alocação de memória Um processo C suporta três tipos de alocação de memória:: A alocação estática ocorre quando são declaradas variáveis globais ou estáticas; geralmente usa a área Data. A alocação automática ocorre quando são declaradas variáveis locais e parâmetros de funções. O espaço para a alocação dessas variáveis é reservado quando a função é invocada, e liberado quando a função termina. Geralmente é usada a pilha (stack). A alocação dinâmica, quando o processo requisita explicitamente um bloco de memória para armazenar dados; o controle das áreas alocadas dinamicamente é manual ou semi-automático: o programador é responsável por liberar as áreas alocadas dinamicamente. A alocação dinâmica geralmente usa a área de heap.
6 Alocação estática Ocorre com variáveis globais (alocadas fora de funções). Ocorre quando variáveis locais (internas a uma função) são alocadas usando o modificador static. Uma variável alocada estaticamente mantém seu valor durante toda a vida do programa, exceto quando explicitamente modificada.
7 Alocação automática As variáveis definidas dentro de uma função (variáveis locais e parâmetros) são alocadas de forma automática na pilha de execução do programa (stack) a cada chamada da função. São descartadas quando a função encerra. Pilha de execução geralmente é uma área pequena. (problema para variáveis locais muito grande e funções recurcivas)
Alocação dinâmica O programa (processo) solicita explicitamente áreas de memória ao SO. Depois de utilizá-las as libera quando não são mais necessárias. - depois de liberado, espaço estará disponibilizado para outros usos e não pode mais ser acessado - espaço alocado e não liberado explicitamente, será automaticamente liberado ao final da execução As requisições de memória dinâmica são geralmente alocadas na área heap. (área heap é maior do que a área da pilha) 8
9 Quando temos variáveis locais muito grande ou muitas chamadas recursivas Fenômeno: Stack Overflow Processo na memória INSTRUÇÕES PILHA (STACK) HEAP
10 Como resolver? Processo na memória INSTRUÇÕES PILHA (STACK) HEAP Em Java e Python o uso é transparente. Não precisa se preocupar de alocar e liberar memória
Endereços e ponteiros (ferramentas para fazer alocação dinâmica) (*) Fonte: P. Feofiloff. Algoritmos em Linguagem C. 1ª Edição, Editora Campos, 2008. 11
Endereços e ponteiros Os conceitos de endereço e ponteiro são fundamentais em qualquer linguagem de programação. Na linguagem C é mais visível este conceito. Requer um esforço para usar os ponteiros. (*) Fonte: P. Feofiloff. Algoritmos em Linguagem C. 1ª Edição, Editora Campos, 2008. 12
Endereços A memória de qualquer computador (arquitetura de von Neumann) é uma sequência de bytes. Cada byte armazena um de 256 possíveis valores Os bytes são numerados sequencialmente e o número de um byte é o seu endereço (*) Fonte: http://codingfox.com/3-1-computer-memory-and-data-representation/ 13
14 Endereços Cada objeto na memória do computador tem um endereço.
15 Endereços 37FD00 37FD01 37FD02 37FD03... 01010111 11000011 01100100 11100010... Geralmente o endereço do objeto é o endereço do 1ro byte.
16 Endereços e ponteiros Em C o endereço de um objeto é dado pelo operador & Se x é uma variável, então &x é o seu endereço int s = -999 s -9999 0x89422
Endereços e ponteiros Em c o endereço de um objeto é dado pelo operador & Se x é uma variável, então &x é o seu endereço int s = -9999 int *p = &s //(ou int *p; p=&s;) p 0x89422 0x60001 s -9999 0x89422 p aponta para a s p é o endereço de s p aponta a s p = 0x89422 &p = 0x60001 *p = -9999 *p é o mesmo que escrever s (*p=``conteúdo apontado por p ) 17
18 Endereços e ponteiros 4 8 Os ponteiros são variáveis de 2 a 8 bytes (dependendo do computador) que armazenam um endereço de memória.
19 Endereços Todo ponteiro pode ter o valor NULL. NULL é uma constante, geralmente vale 0 (definida no arquivo interface stdlib) int *p = NULL; /* não aponta o dedo pra ninguém */ p 0x000000 0x564320
Endereços Há vários tipos de ponteiros: P. para caracteres P. para inteiros P. para registros P. para ponteiros para inteiros int* p ; int *p; Um tipo de dado novo int* (conceitualmente correto) O * modifica a variável e não o int (mais aceito) int * p; O compilador C aceita qualquer das formas. 20
21 exemploponteiro1.c Operadores unarios & Referência: na frente de uma variável: Devolve o endereço de memória onde a variável está armazenada * Derreferência: na frente de variável ou expressão: Devolve o valor ou conteúdo do endereço de memória apontada pela variável ou expressão
22 exemploponteiro2.c Conteúdo apontado pelo endereço de i
23 exemploponteiro3.c Passagem de parâmetros por valor:
24 exemploponteiro3.c Passagem de parâmetros por referência:
25 exemploponteiro3.c Por que o código abaixo está errado?
26 exemploponteiro3.c Por que o código abaixo está errado? Porque temp é um ponteiro para o qual não foi atribuído um endereço que conhecemos : ele contém um endereço de memória que não pertence a nenhuma das variáveis que criamos.
Vetores e endereços 27
28 Vetores Os elementos de um vetor são alocados consecutivamente na memória do computador. Se cada elemento ocupa b bytes, a diferença entre os endereços de dois elementos consecutivos será de b. (ex. inteiros ocupam 4 bytes, em uma plataforma de 64 bits)
29 Vetores Os elementos de um vetor são alocados consecutivamente na memória do computador. Se cada elemento ocupa b bytes, a diferença entre os endereços de dois elementos consecutivos será de b. O compilador C cria a ilusão de que b vale 1 qualquer que seja o tipo dos elementos do vetor.
Vetores e ponteiros 30
31 Vetores e ponteiros... vetor...
32 Vetores e ponteiros...... Vetor + 1; /* avança sizeof(int) bytes na memória */
Alocação dinâmica malloc aloca um bloco de bytes consecutivos na memória heap (void *) malloc( size ); size: tamanho (número de bytes a alocar) void * : endereço devolvido por malloc void * : ponteiro do tipo void é utilizado para referenciar um tipo genérico, que pode ser transformado em qualquer outro tipo. 33
Alocação dinâmica 34
Alocação dinâmica 35
Alocação dinâmica 36
37 Alocação dinâmica Ideia V+i*sizeof(int)
Alocação dinâmica 38
39 A função malloc não assegura que o espaço de memória foi realmente alocado, por isso é importante verificar se o ponteiro é diferente de NULL antes usá-lo! Quando não for possível Separar memoria suficiente Um ponteiro NULO é devolvido
Quando não for possível Separar memoria suficiente Um ponteiro nulo é devolvido A diferença de ponteiros Devolve um long e é permitida se os dois forem do Mesmo tipo 40
41 Alocação dinâmica uma vez alocado o espaço, não existe garantias do valor inicial dos elementos da array!!
42 Os ponteiros facilitam a alocação dinâmica de memória Após o uso e antes de terminar o programa, devemos liberar a memória para que ela seja utilizada por outros processos ou programas.
Matrizes Material adaptado da aula de Matrizes de Ronaldo F. Hashimoto e Carlos H. Morimoto (IME/USP) 43
Declara uma matriz M de 100 linhas com 200 colunas (20mil inteiros) A memória do computador é linear! 44
Estrutura da matriz na memória do computador 45
46 Disposição dos 20mil elementos da matriz M na memória Qual o endereço de M[0][78]? (tendo como base M[0][0])
47 Disposição dos 20mil elementos da matriz M na memória Qual o endereço de M[0][78]? (tendo como base M[0][0]) &M[0][0]+78
48 Disposição dos 20mil elementos da matriz M na memória Qual o endereço de M[78][21]? (tendo como base M[0][0])
49 Disposição dos 20mil elementos da matriz M na memória Qual o endereço de M[78][21]? (tendo como base M[0][0]) &M[0][0] + (78*200+21)
50 Índices Na linguagem C não existe verificação de índices fora da matriz/vetor. Quem deve controlar o uso correto dos índices é o programador. O acesso utilizando um índice errado pode ocasionar o acesso de outra variável na memória. Se o acesso à memória é indevido você recebe a mensagem segmentation fault.
Matrizes 51
Matrizes 52
53
54 Matrizes A alocação dinâmica de memória para matrizes é realizada da mesma forma que para vetores. A diferença é que temos um ponteiro apontando para outro ponteiro que aponta para o valor final. Ou seja é um ponteiro para ponteiro (indireção múltipla). A indireção múltipla pode ser levada a qualquer dimensão desejada, mas raramente é necessário mais de um ponteiro para um ponteiro.
55 Matrizes A estrutura de dados utilizada é composta por um vetor de ponteiros (correspondendo ao primeiro índice da matriz), sendo que cada ponteiro aponta para o início de uma linha da matriz. Em cada linha existe um vetor alocado dinamicamente, como descrito anteriormente (compondo o segundo índice da matriz).
56 Matrizes Matrizes (bidimensionais) são implementadas como vetores de vetores. Exemplo de trecho de código para alocar uma matriz M com m linhas e n colunas:
Atividade em aula 57
58 Questão 1 - a Escreva o resultado da execução do seguinte programa
59 Questão 1 - b Escreva o resultado da execução do seguinte programa
Questão 1 - c 60
61 Função com matriz como parâmetro O nome de uma matriz dentro do parâmetro de uma função é utilizado como sendo um ponteiro para o primeiro elemento da matriz que está sendo usada na hora de utilizar a função. Não é alocada memória (novamente) para um vetor passado por parâmetro para uma função.
Questão 2 Escreva um programa que leia um número inteiro positivo n seguido de n números inteiros e imprima esses n números em ordem invertida. Por exemplo, ao receber 5 22 33 44 55 66 o seu programa deve imprimir 66 55 44 33 22 Seu programa não deve impor limitações sobre o valor de n Seu programa não deve usar colchetes. 62
63