Alocação Dinâmica
Profa.Dra.Thatyana de Faria Piola Seraphim Universidade Federal de Itajubá
de memória.
I Nestes endereços da memória é possível colocar valores e em
seguida utilizá-los.
I Os tipos de valores colocados nos endereços de memória são
denidos na declaração de um ponteiro.
I É esse tipo que indica ao compilador a quantidade de memória
necessária para armazenar os valores.
I Uma variável do tipo ponteiro aponta para uma variável de
um determinado tipo (char, int, oat, double, . . .).
I É necessário na declaração de um ponteiro, especicar para
qual tipo de variável ele irá apontar.
I Os ponteiros são declarados com um * antes do nome da
variável. Sintaxe
int *aux; float *temp; char *pont;
I aux, temp e pont são
variáveis que armazenam endereços de memória e não valores do tipo int, oat, char.
I * é usado quando deseja-se
acessar o valor que está na posição de memória e não ao endereço da memória.
Operador & e Operador *
I O operador & e o operador * são utilizados quando se
trabalha com ponteiros. Operador &
I Obtém sempre o endereço de uma variável (endereço de). I Como os ponteiros também são variáveis eles também ocupam
memória.
I Pode-se obter o endereço do ponteiro e ter ponteiros para
ponteiros (múltiplos *). Operador *
I O operador * faz o contrário do operador &.
I Dado um ponteiro, o operador * acessa o conteúdo apontado
1 #include<stdio.h>
2 int main(int argc, char *argv[]){ 3 int x=10;
4 int *p1=&x; //ponteiro para um inteiro 5 6 printf("x = %d\n\n", x); 7 *p1=20; //ou p1[0]=20; 8 9 printf("p1 = %u\n", p1); 10 printf("x = %d\n", x); 11 printf("*p1 = %d\n", *p1); 12 printf("p1[0] = %d\n\n", p1[0]); 13 return 0; 14 } //end main
Operador & e Operador *
Exemplo 02 - Ponteiro de Ponteiro que referencia um inteiro
1 int main(int argc, char *argv[]){ 2 int x=10;
3 int *p1=&x; //ponteiro para um inteiro
4 int **p2=&p1; //ponteiro de ponteiro para um inteiro 5 6 printf("x = %d\n\n", x); 7 **p2=30; //ou p2[0][0]=30; 8 9 printf("p2 = %u\n", p2); 10 printf("x = %d\n", x); 11 printf("**p2 = %d\n", **p2); 12 printf("p2[0][0] = %d\n\n", p2[0][0]); 13 return 0; 14 } //end main
Exercício 01 - Ponteiro de ponteiro de ponteiro que referencia um inteiro
Faça um programa:
1. Declare uma variável x do tipo inteiro e atribua o valor 10.
2. Declare uma variável p3 que seja do tipo ponteiro de ponteiro de ponteiro para um inteiro.
3. A variável p3 deve referenciar um ponteiro, que referencia um outro ponteiro, que referencia a variável inteira x.
4. Modique o valor da variável inteira x para 40 a partir de p3.
Operador & e Operador *
Resposta do Exercício 01
1 int main(int argc, char *argv[]){ 2 int x=10;
3 int *p1=&x; //ponteiro para um inteiro
4 int **p2=&p1; //ponteiro de ponteiro para um inteiro
5 int ***p3=&p2; //ponteiro de ponteiro de ponteiro para um inteiro 6 7 printf("x = %d\n\n", x); 8 ***p3=40; //ou p3[0][0][0]=40; 9 10 printf("p3 = %u\n", p3); 11 printf("x = %d\n", x); 12 printf("***p3 = %d\n", ***p3); 13 printf("p3[0][0][0] = %d\n", p3[0][0][0]); 14 return 0; 15 }//end main
I Os ponteiros são necessários na implementação da técnica de
alocação dinâmica.
I Alocação Dinâmica: é a técnica para a alocação e
desalocação de espaço de memória, através de funções pré-denidas pela linguagem C.
I O controle de alocar e desalocar espaço na memória é de
responsabilidade do programador.
I A alocação estática libera automaticamente o espaço alocado
em memória quando o programa sai do escopo (da chave), onde a variável foi declarada.
I A linguagem C fornece funções denidas na biblioteca
<stdlib.h> para alocar e desalocar memória: malloc(), sizeof() e free().
malloc()
I É responsável por procurar um local livre na memória. I Aloca um bloco de memória com um tamanho de bytes. I Retorna um ponteiro para o bloco alocado.
I O ponteiro deve sempre ser convertido (typecast) para o tipo
de ponteiro usado.
Sintaxe: void *malloc(size_t size); Exemplo:
sizeof(tipo)
I Devolve o número de bytes necessários para representar os
valores de um tipo de dado. Sintaxe 1: sizeof(tipo);
Sintaxe 2: sizeof(nomeVariavel);
int *idade=(int *) malloc(sizeof(int)); double sal=1234.5;
free()
I Desaloca a memória que foi alocada com o malloc, cujo
endereço se encontra em um ponteiro.
I Se perder o endereço (ponteiro) para onde a memória foi
alocada (pelo malloc), o espaço cará perdido (sem utilização) até que o programa termine.
I Quando o programa estiver usando toda memória RAM, será
iniciado o uso da memória virtual (swap).
I A memória virtual (swap) utiliza o disco para simular memória
RAM, deixando o programa mais lento. Sintaxe free()
void free(void *ptr); Exemplo
Exemplo
1 int main(int argc, char *argv[]){
2 int i;
3 char *buffer;
4 for(i=0; i<(100*1024); i++){
5 buffer=(char *)malloc(1024*sizeof(char)); 6 }//end for
7 free(buffer);
8 system("sleep 10");
9 return 0;
Vetores
Alocação estática de um vetor int v[10];
Alocação dinâmica de um vetor
int *v=(int *) malloc(10 * sizeof(int));
I Ambas alocações são iguais, ou seja, vai ser alocado na
memória 10 posições para v.
I Diferença: na alocação dinâmica é necessário desalocar (free)
1 int main(int argc, char *argv[]){
2 int i;
3 int *v1; //aloca um vetor de dimensão 10 4 srand(time(NULL));
5
6 //alocacao de um vetor de dimensao 10 7 v1=(int *) malloc(10 * sizeof(int)); 8
9 //atribuição e impressao 10 for(i=0; i<10; i++){ 11 v1[i]=rand()%100;
12 printf("[%d=%d] ", i, v1[i]); 13 }//end for
14 printf("\n"); 15
Matrizes
Alocação estática da matriz int v[3][4];
Alocação dinâmica de um vetor int i;
int **v=(int **) malloc(3*sizeof(int*)); for(i=0; i<3; i++)
1 int main(int argc, char *argv[]){
2 //declara uma matriz de dimensao 10x20 3 int **m2;
4 int i, j;
5 //alocacao da matriz 10x20
6 m2=(int**)malloc(10*sizeof(int*)); 7 for(i=0; i<10; i++){
8 m2[i]=(int*)malloc(20*sizeof(int)); 9 }//end for
10 //atribuicao e impressao 11 for(i=0; i<10; i++){ 12 for(j=0; j<20; j++){ 13 m2[i][j]=rand()%100;
Matrizes Exemplo
Alocação dinâmica da matriz Cont.
15 }//end for j 16 printf("\n"); 17 }//end for i 18 printf("\n"); 19 20 //desalocacao da matriz 10x20 21 for(i=0; i<10; i++){
22 free(m2[i]); 23 }//end for 24 free(m2); 25 return 0; 26 } //end main
Exercício
1. Faça um programa que declare uma matriz tridimensional de inteiros de dimensão 10 × 20 × 30 chamada m3.
2. A matriz m3 deve ser alocada dinamicamente na memória.
3. Deve-se atribuir e imprimir valores à matriz m3.
4. A matriz m3 deve ser desalocada antes que o programa termine.
Exercício Resposta
Alocação dinâmica da matriz
1 #include<stdio.h>
2 int main(int argc, char *argv[]){ 3 int i, j, k;
4 int ***m3; //declaracao da matriz tridimensional 5
6 //alocacao da matriz de dimensao 10x20x30 7 m3=(int***) malloc(10 * sizeof(int **)); 8 for(i=0; i<10; i++){
9 m3[i]=(int**) malloc(20 * sizeof(int *)); 10 for(j=0; j<20; j++){
11 m3[i][j]=(int*) malloc(30 * sizeof(int)); 12 }//end for j
Alocação dinâmica da matriz Cont.
14 //atribuicao e impressao da matriz de dimensao 10x20x30 15 for(i=0; i<10; i++){
16 for(j=0; j<20; j++){ 17 for(k=0; k<30; k++){ 18 m3[i][j][k]=rand()%100; 19 printf("[%d,%d,%d=%d] ", i, j, k, m3[i][j][k]); 20 }//end for k 21 printf("\n\n"); 22 }//end for j 23 printf("\n"); 24 }//end for i 25 printf("\n");
Exercício Resposta
Alocação dinâmica da matriz Cont.
26 //desalocacao da matriz de dimensao 10x20x30 27 for(i=0; i<10; i++){
28 for(j=0;j<20;j++){ 29 free(m3[i][j]); 30 }//end for j 31 free(m3[i]); 32 }//end for i 33 free(m3); 34 return 0; 35 }//end main
I O ponteiro de void é um tipo especial de ponteiro. I Ele representa a ausência de um tipo de dado.
I Com o uso do ponteiro para void não é possível acessar
diretamente o valor referenciado.
I É necessário que seja feito uma conversão de tipo de dado.
Sintaxe
Ponteiro para void Exemplo
Exemplo
1 #include<stdio.h>
2 int main(int argc, char *argv[]){
3 int i;
4 void *aluno = malloc(10*sizeof(byte)); 5 char *nome = (char *) aluno;
6 int *matricula = (int *) aluno; 7 *matricula = 1234;
8 printf("matricula = %d\n", *matricula); 9 for(i=0; i<10; i++){
10 printf("[%d]", ((char*)aluno)[i]); 11 }//end for i
Exemplo Cont.
12 strcpy(nome, "Joao");
13 printf("nome = %s\n", nome); 14 for(i=0; i<10; i++){
15 printf("[%d]", ((char*)aluno)[i]); 16 }//end for i
17 free(aluno); 18 return 0; 19 }//end main
Ponteiro Nulo
I O ponteiro nulo (NULL) é um valor especial que indica que
um ponteiro de qualquer tipo não está apontando para qualquer referência válida ou endereço de memória.
I Este valor é o resultado de typecasting do valor inteiro zero
para qualquer tipo de ponteiro.
I A diferença de ponteiro nulo e ponteiro para void.
I Ponteiro nulo: representa um valor nulo em um ponteiro de
qualquer tipo, ou seja, não foi atribuído nenhum endereço de memória para a variável.
I Ponteiro para void: é um ponteiro para uma região de
memória sem tipo. Sintaxe
char *buffer=NULL; int *idades=NULL; void *limbo=NULL;
1 #include<stdio.h>
2 typedef unsigned char byte; 3 int main(int argc, char *argv[]){
4 int i;
5 byte *buffer=NULL;
6 ...
7 if(buffer == NULL){
8 buffer=(byte*) malloc(10*sizeof(byte)); 9 }//end if
10 for(i=0; i<10; i++){ 11 buffer[i]='a' + i;
12 printf("[%c]", buffer[i]); 13 }//end for i
Ponteiro Nulo
Exemplo - NULL Cont.
15 if(buffer != NULL){ 16 free(buffer); 17 }//end if 18 return 0; 19 }//end main
da estrutura podem ser acessados através do operador ponto (.).
I O operador ponto (.) conecta o nome de uma variável
estrutura a um membro da estrutura. Sintaxe para acesso
nomeVariavel.nomeMembro = dados; Exemplo da Estrutura e Acesso
1 typedef struct{ 2 char nome[20]; 3 int idade; 4 }t_aluno; 5 t_aluno a1; 6 strcpy(a1.nome, "Joao");
Acesso aos Dados Dinâmicos
I Quando a variável do tipo estrutura é um ponteiro, os dados
são acessados usando o operador ponteiro >. Sintaxe para acesso
nomeVariavel>nomeMembro = dados; Exemplo da Estrutura e Acesso
1 typedef struct{ 2 char nome[20]; 3 int idade; 4 }t_aluno;
5 t_aluno *a1 = (t_aluno *) malloc(sizeof(t_aluno)); 6 strcpy(a1->nome, "Joao");
e seta (>) 1 #include<stdio.h> 2 typedef struct{ 3 char nome[20]; 4 int temp; 5 double preco; 6 }t_seriesTV;
7 int main(int argc, char *argv[]){ 8 t_seriesTV s1; //alocacao estatica 9 //alocacao dinamica
10 t_seriesTV *s2=(t_seriesTV *) malloc(sizeof(t_seriesTV)); 11 strcpy(s1.nome,"Lost");
12 s1.temp=5;
Estrutura
Exemplo - Acesso membro de estrutura com ponto (.) e seta (>) Cont.
14 printf("Nome=%s Temporada=%d Preco=%.2f\n",
15 s1.nome, s1.temp, s1.preco);
16 strcpy(s2->nome,"Big Bang Theory"); 17 s2->temp=3;
18 s2->preco=98.76;
19 printf("Nome=%s Temporada=%d Preco=%.2f\n", 20 s2->nome, s2->temp, s2->preco); 21 free(s2);
22 return 0; 23 }//end main
I Existem duas operações aritméticas que podem ser usadas
com ponteiros:
I Adição (incremento). I Subtração (decremento).
I Quando um ponteiro é incrementado ele passa a apontar para
o próximo valor do mesmo tipo para o qual o ponteiro aponta.
I Se um ponteiro para inteiro for incrementado, esse ponteiro
passa a apontar para o próximo inteiro.
I Isso justica a necessidade do compilador conhecer o tipo de
um ponteiro.
I Se um ponteiro para char * é incrementado, ele anda 1 byte
na memória.
I Se um ponteiro para double * é incrementado, ele anda 8
Aritmética de Ponteiro
Exemplo - Aritmética de ponteiro
1 typedef unsigned char byte; 2 int main(int argc, char* argv[]){
3 int i,j;
4 byte *buffer = (byte*) malloc(60 * sizeof(byte)); 5 int *idade = (int *) buffer;
6 double *sal = (double *) buffer + sizeof(int); 7 char *nome = (char *) buffer + sizeof(int) +
8 sizeof(double);
9 *idade=18; //ou idade[0]=18; 10 *sal=510.0; //ou sal[0]=510.0; 11 strcpy(nome,"Joao");
12 printf("Nome = %s Idade = %d Sal = %f\n",
13 nome, *idade, *sal);
14 printf("Nome = %s Idade = %d Sal = %f\n", 15 nome, idade[0], sal[0]);
Aritmética de Ponteiro Cont. . .
16 //impressao de buffer
17 for(i=0; i<60; i++){
18 printf("[%3d]", buffer[i]); 19 if(((i+1)%10)==0){
20 printf("\n");
21 for(j=i-9; j<=i; j++){ 22 printf(" %3d ", j); 23 }//end for 24 printf("\n"); 25 }//end if 26 }//end for 27 printf("\n"); 28 free(buffer); 29 return 0; 30 }//end main
Aritmética de Ponteiro
Exemplo - Aritmética de ponteiro
1 typedef unsigned char byte; 2 int main(int argc, char* argv[]){
3 int i,j;
4 byte *buffer=(byte*) malloc(60 * sizeof(byte)); 5 int *idade1=(int *) buffer;
6 int *idade2=(int *) buffer + sizeof(int); //idade2=idade1+1; 7 char *nome=(char *) buffer + (2*sizeof(int)); //ou
8 //nome=(char*)idade1+2;
9 double *sal1=(double *) buffer + (2*sizeof(int)) + 8; 10 double *sal2=(double *) buffer + (2*sizeof(int)) + 8 +
11 sizeof(double);
12 *idade1=18; //ou idade1[0]=18;
13 *idade2=25; //ou idade2[0]=25; ou idade1[1]=25; 14 *sal1=123.4; //ou sal1[0]=123.4;
15 *sal2=666.66; //ou sal2[0]=666.66; ou sal1[1]=666.66; 16 strcpy(nome,"Itajuba"); //ou strcpy(nome[0],"Itajuba");
17 printf("Nome=%s Idade1=%d Idade2=%d Sal1=%f Sal2=%f\n", 18 nome, *idade1, *idade2, *sal1, *sal2);
19 printf("Nome=%s Idade1=%d Idade2=%d Sal1=%f Sal2=%f\n", 20 nome, idade1[0], idade2[0], sal1[0], sal2[0]); 21 for(i=0; i<60; i++){ //impressao de buffer
22 printf("[%3d]", buffer[i]); 23 if(((i+1)%10)==0){
24 printf("\n");
25 for(j=i-9; j<=i; j++){ 26 printf(" %3d ", j); 27 }//end for 28 printf("\n"); 29 }//end if 30 }//end for 31 free(buffer); return 0;