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.
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);
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:
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.
[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);
[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).
[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...)
[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
[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"};
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);