Alocação dinâmica de memória em C

Esta artigo objetiva mostrar com se faz alocação dinâmica de memória para programas em C (utilizando o malloc). A alocação dinâmica é um recurso muito utilizado, em especial para as linguagens de alto nível.

[ Hits: 66.134 ]

Por: Carlos Roberto S. Junior em 18/04/2008


Alocação dinâmica em C - alocando uma matriz bidimensional



Há duas formas de se alocar uma matriz xd (sendo x uma variável natural e diferente de zero).

1ª forma: aloca dois vetores, um vetor grande com todas a linhas e colunas da matriz multiplicadas e outro somente com o número de linhas, porém este último deve ser um ponteiro de ponteiros. Depois faz-se a distribuição do vetor maior para o menor.

#include <stdio.h>
#include <malloc.h>

int main(void)
{
       unsigned short int linhas, colunas, i;
       int *vetor, **matriz; /*um vetor grande e um ponteiro para ponteiros que será a matriz*/

       printf("\nDigite o numero de linhas e colunas: ");
       scanf("%d,%d",&linhas,&colunas);

       vetor= malloc( linhas * colunas * sizeof(int) );
       *matriz= malloc( linhas * sizeof(int) );

       for(i=0;i<linhas;i++)
              matriz[i]= &vetor[ i * colunas];

                    /*a partir deste ponto pode ser usado matriz[a][b] sendo a o número da linha e b o número da coluna para qualquer parte do programa*/

        free(vetor);
        free(matriz);  /*faz a liberação da memória alocada*/

        return 0;
}

2ª forma: aloca-se uma matriz, sendo esta ponteiro para ponteiro, primeiramente aloca-se o número de linhas e depois aloca-se o número de colunas, utilizando loops para isso. Desta forma:

#include <stdio.h>
#include <malloc.h>
/*includes*/

int main(void)
{
      unsigned short int linhas, colunas, i;
      int **matriz;

      printf("\nDigite o número de linhas e colunas: ");
      scanf("%d,%d",&linhas, &colunas);

      *matriz= malloc( linhas * sizeof( int ) );
      for(i=0;i<linhas;i++)
              matriz[i]= malloc( colunas * sizeof( int ) );

      /*a partir deste ponto pode ser usado matriz[a][b] sendo a o número da linha e b o número da coluna para qualquer parte do programa*/

        for(i=0; i<linhas; i++)
                É uma free(matriz[i]);
        free(matriz);  /*faz a liberação da memória alocada*/

        return 0;
}

Estes são os dois métodos para fazer a locação de uma matriz dinamicamente, para se aumentar o número de dimensões não é difícil, basta aumentar o número de ponteiros, ou seja, para 3d teríamos a seguinte declaração ***matriz (para o segundo método) ou uma matriz intermediária para o primeiro método.

Página anterior    

Páginas do artigo
   1. Introdução
   2. Alocação dinâmica em C - alocando uma matriz bidimensional
Outros artigos deste autor

Estudando recursividade direta e indireta

Leitura recomendada

SDL e C - Uma dupla sensacional

lib cURL - Trabalhe com URLs em C

Parâmetros interessantes do scanf e do printf em C

Criando aplicativos para o iPhone no Linux (sem Xcode e MacOS X)

Compilando o Mono 2.2 no Ubuntu 8.10

  
Comentários
[1] Comentário enviado por elgio em 18/04/2008 - 10:00h

Oi. legal esta tua iniciativa de se escrever um artigo sobre malloc, mas veja que algumas de suas afirmações, mesmo que corretas, podem induzir ao erro se o inexperiente programador não souber contextualizá-las (e o experiente não precisaria ler este artigo ;-)

Primeiro, quando se programa em C ANSI deve-se cuidar do respeito aos padrões ANSI. A forma de alocação que sugeriste de alocar um espaço em relação à uma variável não funciona em todos os casos, logo para que se arriscar a usar:


printf("\nDigite o tamanho da string: ");
scanf("%d",&valor);

char string[valor];

E se o cara digitar -1 para valor? (-1 será interpretado como 2.147.483.647, ou seja, alocaria 2G, aproximadamente!!!). Induz ao erro. Eu prefiro JAMAIS, em HIPÓTESE ALGUMA ensinar estas coisas para quem está iniciando.

Outra indução ao erro é que SEMPRE que se faz malloc deve-se testar o seu retorno. Pode ser que tu não consigas alocar a memória que solicitou:

printf("\nDigite o tamanho da string: ");
scanf("%d",&tamanho);

string= malloc( tamanho * sizeof(char) ); /*o sizeof ajuda a aumentar a portabilidade*/

printf("\nDigite a string: ");
scanf("%s",string);
(e poderiamos ainda discutir o problema de buffer overflow que o scanf permite. Eu ensinaria direto o fgets)

E se DENOVO, o usuário digitar -1? Ou mesmo 1000000 e não se tem memória? Veja que o programa continua e vais escrever em uma área NÃO ALOCADA o que é GRAVÍSSIMO! Sempre, sempre, sempre, sempre se deve testar se o malloc funcionou:

printf("\nDigite o tamanho da string: ");
scanf("%d",&tamanho);

string= malloc( tamanho * sizeof(char) );

if (string == NULL){
fprintf(stderr, "ERRO NO MALLOC\n");
return(1);
}

printf("\nDigite a string: ");
fgets(string, tamanho, stdin);

[2] Comentário enviado por removido em 18/04/2008 - 10:04h

Para gerar matrizes dinamicamente, talvez seja mais indicado o uso de calloc:

void *calloc(size_t nmemb, size_t size);

Que está definido em stdlib.h. Nele você especifica quantos membros terá na sua matriz e qual o tamanho deles.

[3] Comentário enviado por elgio em 18/04/2008 - 10:06h

calloc é praticamente um define:

calloc (3,4) == malloc(3*4)

[4] Comentário enviado por elgio em 18/04/2008 - 10:09h

"A desvantagem da alocação dinâmica está no rompimento da pilha de memória, o que causaria o fechamento do programa e também, com a alocação dinâmica, o programa torna-se mais lento, pois ela requer muito do processamento. "


Como assim?
rompimento de pilha? malloc não usa a pilha para alocação e este rompimento e fechamento de um programa é somente se não conseguiu alocar e o programador não testou. Usado de forma correta não há nenhum rompimento e nenhum fechamento de programa!

E mais lento?
Nada disso.
Depois de alocado o acesso é na mesma velocidade do que vetores estáticos. A lentidão existe no momento de alocar, pois a alocação é uma tarefa onerosa (que pode envolver até - PASMEM - defragmentação de memória).

Abraços.

[5] Comentário enviado por ulissescosta em 18/04/2008 - 19:47h

scanf("%d",&valor);
char string[valor];

Isto não é alocação dinâmica de memória!
No máximo podes alocar 2GB que é o tamanho máximo da stack relativa a variáveis.

[6] Comentário enviado por maran em 20/04/2008 - 14:54h

caramba, olha os cara meu, aula de programação....
Isso ae show de bola o artigo e os comentarios

[7] Comentário enviado por FelipeAbella em 24/04/2008 - 19:29h

calloc(a,b) é igual a malloc (a*b)
com exceção de que calloc zera a memória alocada.

É possível evitar um buffer overflow no scanf:

char str[16];
scanf("%15s", str);

Boa iniciativa.

[8] Comentário enviado por elgio em 24/04/2008 - 19:51h

calloc: Correto!
Eu prefiro não perder este tempo extra com esta inicialização

scanf: Correto também, mas o fgets é muito mais intuitivo.

Com fgets o tamanho pode ser um #define ou mesmo uma variável:

#define MAX 200
...
fgets(str, MAX, stdin);

Porque isto NÃO FUNCIONA:

scanf("%MAXs", str);

Não funciona até porque teria que ser MAX-1 (para o fgets tu passa o tamanho do buffer e ele já sabe que precisa de um para o 0. Já no scanf é quantos cars e ele não reserva 1 para o zero.)

O scanf permite inclusive livrar-se do inconveniente de não ler espaços em branco:

scanf("%[^\n]s", str);

Mas ai já é coisa par aum artigo avançado (poderes ocultos do scanf...)

[9] Comentário enviado por odavai em 28/04/2008 - 08:50h

gostei vou utilizalo depois enviarei se deu tudo certo nos meus estudos de c e c++

[10] Comentário enviado por gdm.arc em 31/10/2008 - 12:47h

Senhores(as)
Saudações
Gostaria de dizer que o código está com alguns problemas, segue abaixo o código modificado visto não ter funcionado o inicial apresentado no presente artigo, aliás muito interessante.

Os seguintes pontos de erro foram encontrados:
1) tipo da variável de entrada via scanf não era compativel com unsigned short int, visto estar retornando sempre zero ao invés do valor digitado.
2) a sintaxe do malloc() omitia o casting. A função malloc() retorna um ponteiro 'void', que precisa ser 'moldado' ao ser atribuido.
3) atribuição do valor ao invés do endereço para a variável "matriz" na chamada ao malloc() na primeira dimensão.
4) comentário incorreto na chamada da função free() para a segunda dimensão.
5) o sizeof() deve ser usado para o ponteiro e não para o valor apontado pelo ponteiro

Agradecido.
Parabéns pela iniciativa

gdm.arc

#include <stdio.h>
#include <stdlib.h>
/*includes*/

int main(void)
{
int linhas, colunas, i; /* (1) */
int **matriz;

printf("\nDigite o número de linhas e colunas: ");
scanf("%d,%d",&linhas, &colunas);
matriz= (int **) malloc( linhas * sizeof( int *) ); /* (2),(3),(5) */
for(i=0;i<linhas;i++)
matriz[i]= (int *) malloc( colunas * sizeof( int ) ); /* (2) */

/*a partir deste ponto pode ser usado matriz[a][b] sendo a o número da linha e b o número da coluna para qualquer parte do programa*/

for(i=0; i<linhas; i++)
free(matriz[i]); /* (4) */
free(matriz); /*faz a liberação da memória alocada*/

return 0;
}

[11] Comentário enviado por inacioalves em 29/10/2009 - 23:16h

Reativando o tópico.

1. Me corrijam se eu estiver errado, mas pelo menos em C ANSI basta incluir a biblioteca stdlib.h para podermos usar malloc e sizeof.

2. Não se faz necessário trabalhar com ponteiros de ponteiros para usarmos "matrizes".
Considerem o código abaixo:

#include<stdio.h>
#include<stdlib.h>
int main(){
int i,j, l,c;
float *m;
scanf("%d%d",&l,&c);
m = malloc( l*c*sizeof(float) );
for( i=0; i<l; i++ )
for(j=0;j<c;j++ )
scanf("%f",m+(i*c+j) );

for( i=0; i<l; i++ ){
for(j=0;j<c;j++ )
printf("%8.2f",*(m+i*c+j) );
printf("\n");
}

return 0;
}

Ele trata muito bem um vetor como se este fosse uma matriz ;)

[12] Comentário enviado por ElisMacedo em 28/10/2011 - 22:21h

// Isso é um trecho de um programa,coloquei somente a parte que usamos para alocar dinamicamicana a quantidade de filas e a quantidade de cadeiras da primeira fileira de um teatro.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//DEFINIÇÕES DAS VARIAVEIS
#define MAX 26 //Numero máximo de filas
#define CASE_1 1 // Vender cadeira isolada
#define CASE_2 2 // Vender lote de cadeiras
#define CASE_3 3 //Consultar cadeiras com folga
#define CASE_4 4 // consultar cadeiras com vista livre
#define CASE_5 5 //Fechar bilheteria
#define CASE_6 6 //Mostrar ocupação total do teatro
#define CASE_7 7 //Sair do programa

//Protótipo das funções

int ** cria_fileiras_int(int , int); //Função para criar a matriz de alocação para criar as filas e cadeiras do teatro
void vender_cadeira(int **, float , int , int, char[]); // função para vender cadeiras isoladas
void vender_lote(int **, float , int , int, char[]); //Função pra vender cadeiras por lote
void teatro_total(int ** ,int ,int , char[]); //Função para exibir a matriz das cadeiras com folga
void vista_livre(int ** ,int ,int , char[]); //Funçao para exibir as caderias com vista livre
void fechar_bilheteria(int **, int , int , float, char[]); //Função para calcular o faturamento total da bilheteria, taxa de ocupação total e por fila
void ocupacao(int ** ,int ,int , char[]); //Função que mostra o teatro

//Início do prgrama
int main(){

int escolha; // guarda a opção do menu
int n; // guarda quantidade de fila
int c; // guarda a quantidade de cadeiras
int ** teatro; //vetor de ponteiro que aponta para a matriz teatro
float preco = 0;// guarda o preço

char * escolhas[] = {"Vender uma cadeira isolada",
"Vender um lote de cadeiras",
"Consultar cadeiras com folga",
"Consultar cadeiras com vista livre",
"Fechar bilheteria",
"Mostrar a ocupacao total do Teatro",
"Finalizar programa"};

char fileira[] = {'A','B','C','D','E',
'F','G','H','I','J',
'K','L','M','N','O',
'P','Q','R','S','T',
'U','W ','X','Y','Z'};


printf("Insira a quantidade de fileiras totais: "); //Solicita ao usuário que digite a quantidade de filas e cadeiras da primeira fila
scanf("%d", &n);
printf("Insira a quantidade de cadeiras da 1a fileira: ");
scanf("%d", &c);


while(n<2 || n>MAX){ // Verifica os parâmetros digitados
printf("Minimo de 2 e maximo de 26 fileiras no teatro!!\n");
printf("Insira a qtde de fileiras totais e cadeiras da 1a fileira): ");
scanf("%d %d",&n,&c);
}

//Função para criar a matriz de alocaçao para criar as filas e cadeiras do teatro

int ** cria_fileiras_int(int n, int c) {
int ** mat, i;
if((mat = (int **) calloc(n,sizeof(int *))) == NULL) {
return NULL;
}

for(i = 0; i < n ; i++) {
if((mat[i] = (int *) calloc(c + 2 * i, sizeof(int))) == NULL) return NULL; // c+2*iacrescentar 2 cadeiras a cada nova fileira
}
return mat;
}

[13] Comentário enviado por costadelima em 10/09/2015 - 15:49h

Não entendi como alocar dinamicamente uma matriz superior a NxN.
Tentei fazer assim:
int*** aloca(int n){
int i;
int*** vet;
vet = (int***)malloc(sizeof(int**)*n);

for(i=0; i<n; i++)
vet = (int**)malloc(sizeof(int*)*n);
for(i=0; i<=n; i++)
vet[i] = (int*)malloc(sizeof(int)*n);

return (vet);
}

alguem ajuda?


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts