Linux slogan
Visite também: BR-Linux.org · Dicas-L · Doode · NoticiasLinux · SoftwareLivre.org · UnderLinux



» Screenshot
» Login
Login:
Senha:

Se você ainda não possui uma conta, clique aqui.

Esqueci minha senha



Artigo

Alocação dinâmica de memória em C
Linux user
carlosjr
18/04/2008
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.
Por: Carlos Roberto S. Junior
[ Hits: 46451 ]
Conceito: 7.7   3 voto(s)3 voto(s)3 voto(s)3 voto(s)3 voto(s) + quero dar nota ao artigo

Introdução

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:

tipoDoPonteiro= malloc(valorParaAlocação * tamanhoDoTipo);

Por exemplo:

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

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.

    Próxima página >>




Páginas do artigo

Outros artigos deste autor

Leitura recomendada

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
#include
/*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 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 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
#include
int main(){
int i,j, l,c;
float *m;
scanf("%d%d",&l,&c);
m = malloc( l*c*sizeof(float) );
for( i=0; i for(j=0;j scanf("%f",m+(i*c+j) );

for( i=0; i for(j=0;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
#include
#include

//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;
}



Contribuir com comentário


  
Para executar esta ação você precisa estar logado no site, caso contrário, tudo o que for digitado será perdido.
Responsável pelo site: Fábio Berbert de Paula - Conteúdo distribuído sob licença GNU FDL
Site hospedado por:

Viva o Linux

A maior comunidade Linux da América Latina! Artigos, dicas, tutoriais, fórum, scripts e muito mais. Ideal para quem busca auto-ajuda em Linux.