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.
A alocação dinâmica de memória trata-se de pegar um espaço na memória maior do que era esperado, ou simplesmente pegar um espaço quando não é possível prever. Há diversas formas de se fazer isso. Em C usamos uma função malloc(); já em C++ utilizamos uma palavra reservada "new".
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.
Alocação dinâmica em C
Os compiladores mais antigos (anterior a 1998) não aceitavam este trecho de código:
#include <stdio.h>
/*include*/
int main(void)
{
unsigned short int valor;
printf("\nDigite o tamanho da string: ");
scanf("%d",&valor);
char string[valor];
printf("\nDigite a string: ");
scanf("%s",string);
printf("%s",string");
return 0;
}
Este código nos novos compiladores simplesmente gerará uma aviso. Mas o programa será executado normalmente. É um tipo simples do alocação dinâmica, porém há funções que fazem isso um pouco melhor.
Utilizando o malloc(), a função está contida na biblioteca malloc.h e possui a seguinte sintaxe:
int main(void)
{
unsigned short int tamanho;
char *string; /*ponteiro para char, é necessário que seja uma ponteiro para ser alocado*/
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);
printf("\n%s",string);
free(string); /*libera a memória alocada*/
return 0;
}
A utilização do free() é altamente recomendada, pois ele devolve a memória alocada para o sistema, alguns sistemas operacionais fazem isso automaticamente quando o programa fecha, porém se ocorrer um erro você pode ficar com uma parte da memória sem utilização, tanto pelo sistema quanto pelos programas que você utiliza.
[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);