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.
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.
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:
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.
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;
}
/*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;
}
#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.
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);