Programação C

malloc em linguagem c

malloc em linguagem c
Você pode vir aqui por dois motivos: ou deseja alocar conteúdo dinamicamente ou deseja saber mais sobre como funciona o malloc. Em qualquer caso, você está no lugar certo! A alocação dinâmica é um processo que acontece muito, mas geralmente não o usamos nós mesmos: a grande maioria das linguagens de programação gerenciam memória para você, pois é um trabalho difícil e se você não fizer isso corretamente, há implicações de segurança.

No entanto, se você estiver trabalhando em C, C ++ ou código assembly, ou se implementar um novo módulo externo em sua linguagem de programação favorita, você mesmo precisará gerenciar sua alocação de memória dinâmica.

O que é alocação dinâmica? Por que eu preciso de malloc?

Bem, em todos os aplicativos, quando você cria uma nova variável - muitas vezes é chamado de declaração de uma variável - você precisa de memória para armazená-lo. Como o seu computador está nos dias modernos, ele pode rodar mais de um aplicativo ao mesmo tempo e, portanto, cada aplicativo deve informar ao seu sistema operacional (aqui Linux) que precisa dessa quantidade de memória. Quando você escreve este tipo de código:

#incluir
#incluir
#define DISK_SPACE_ARRAY_LENGTH 7
void getFreeDiskSpace (int statsList [], size_t listLength)
Retorna;

int main ()
/ * Contém o espaço livre em disco dos últimos 7 dias. * /
int freeDiskSpace [DISK_SPACE_ARRAY_LENGTH] = 0;
getFreeDiskSpace (freeDiskSpace, DISK_SPACE_ARRAY_LENGTH);
return EXIT_SUCCESS;

O array freeDiskSpace precisa de memória, então você precisará pedir a aprovação do Linux para obter alguma memória. No entanto, como é óbvio ao ler o código-fonte que você precisará de um array de 7 int, o compilador automaticamente pede ao Linux por ele e o aloca na pilha. Isso basicamente significa que este armazenamento é destruído quando você retorna a função onde a variável está declarada. É por isso que você não pode fazer isso:

#incluir
#incluir
#define DISK_SPACE_ARRAY_LENGTH 7
int * getFreeDiskSpace ()
int statsList [DISK_SPACE_ARRAY_LENGTH] = 0;
/ * POR QUE ESTAMOS FAZENDO ISSO?! statsList será DESTRUÍDO! * /
return statsList;

int main ()
/ * Contém o espaço livre em disco dos últimos 7 dias. * /
int * freeDiskSpace = NULL;
freeDiskSpace = getFreeDiskSpace ();
return EXIT_SUCCESS;

Você vê mais facilmente o problema agora? Então, você deseja concatenar duas strings. Em Python e JavaScript, você faria:

newStr = str1 + str2

Mas como você sabe, em C não funciona assim. Portanto, para construir um URL, por exemplo, você precisa concatenar duas strings, como caminho de URL e nome de domínio. Em C, temos strcat, certo, mas só funciona se você tiver um array com espaço suficiente para ele.

Você ficará tentado a saber o comprimento da nova corda usando strlen, e você estará certo. Mas então, como você pediria ao Linux para reservar esta quantidade desconhecida de memória? O compilador não pode ajudá-lo: o espaço exato que você deseja alocar só é conhecido em tempo de execução. É exatamente onde você precisa de alocação dinâmica e malloc.

Escrevendo minha primeira função C usando malloc

Antes de escrever o código, uma pequena explicação: malloc permite que você aloque um número específico de bytes para o uso do seu aplicativo. É muito simples de usar: você chama malloc com o número de bytes que você precisa e ele retorna um ponteiro para sua nova área que o Linux reservou para você.

Você tem apenas 3 responsabilidades:

  1. Verifique se malloc retorna NULL. Isso acontece quando o Linux não tem memória suficiente para fornecer.
  2. Libere suas variáveis ​​uma vez não utilizadas. Caso contrário, você desperdiçará memória e tornará seu aplicativo lento.
  3. Nunca use a zona de memória depois de liberar a variável.

Se você seguir todas essas regras, tudo correrá bem e a alocação dinâmica resolverá muitos problemas. Como você escolhe quando liberar a memória, também pode retornar com segurança uma variável alocada com malloc. Só não se esqueça de liberá-lo!

Se você quer saber como liberar uma variável, é com a função free. Chame-o com o mesmo ponteiro que malloc retornou para você, e a memória é liberada.

Deixe-me mostrar o exemplo de concat:

#incluir
#incluir
#incluir
/ *
* Ao chamar esta função, não se esqueça de verificar se o valor de retorno é NULL
* Se não for NULL, você deve chamar free no ponteiro retornado assim que o valor
* não é mais usado.
* /
char * getUrl (const char * const baseUrl, const char * const toolPath)
size_t finalUrlLen = 0;
char * finalUrl = NULL;
/* Verificação de segurança. * /
if (baseUrl == NULL || toolPath == NULL)
return NULL;

finalUrlLen = strlen (baseUrl) + strlen (caminho da ferramenta);
/ * Não se esqueça do '\ 0', daí o + 1. * /
finalUrl = malloc (sizeof (char) * (finalUrlLen + 1));
/ * Seguindo as regras do malloc… * /
if (finalUrl == NULL)
return NULL;

strcpy (finalUrl, baseUrl);
strcat (finalUrl, toolPath);
return finalUrl;

int main ()
char * googleImages = NULL;
googleImages = getUrl ("https: // www.Google.com "," / imghp ");
if (googleImages == NULL)
return EXIT_FAILURE;

puts ("URL da ferramenta:");
coloca (googleImages);
/ * Não é mais necessário, liberte-o. * /
grátis (googleImages);
googleImages = NULL;
return EXIT_SUCCESS;

Então você vê um exemplo prático de uso de alocações dinâmicas. Primeiro, evito armadilhas, como fornecer o valor de retorno getUrl direto para a função puts. Então, também aproveito para comentar e documentar o fato de que o valor de retorno deve ser liberado de maneira adequada. Eu também verifico os valores NULL em todos os lugares para que qualquer coisa inesperada possa ser detectada com segurança em vez de travar o aplicativo.

Finalmente, tomo o cuidado extra de liberar a variável e, em seguida, configuro o ponteiro para NULL. Isso evita a tentação de usar - mesmo por engano - a zona de memória agora liberada. Mas como você pode ver, é fácil liberar uma variável.

Você pode notar que usei sizeof em malloc. Permite saber quantos bytes um char está usando e esclarece a intenção do código para que seja mais legível. Para char, sizeof (char) é sempre igual a 1, mas se você usar uma matriz de int em vez disso, funciona exatamente da mesma maneira. Por exemplo, se você precisar reservar 45 int, basta fazer:

fileSizeList = malloc (sizeof (int) * 45);

Dessa forma, você vê rapidamente o quanto deseja alocar, por isso sempre recomendo seu uso.

Como funciona o malloc sob o capô?

malloc e free são, na verdade, funções incluídas em todos os programas C que se comunicam com o Linux em seu nome. Isso também tornará a alocação dinâmica mais fácil porque, no início, o Linux não permite que você aloque variáveis ​​de todos os tamanhos.

O Linux oferece duas maneiras de obter mais memória de fato: sbrk e mmap. Ambos têm limitações, e uma delas é: você pode alocar apenas quantidades relativamente grandes, como 4.096 bytes ou 8.192 bytes. Você não pode solicitar 50 bytes como eu fiz no exemplo, mas também não pode solicitar 5.894 bytes.

Isso tem uma explicação: o Linux precisa manter uma tabela onde informa qual aplicativo reservou qual zona de memória. E esta tabela também usa espaço, então se cada byte precisasse de uma nova linha nesta tabela, uma grande parte da memória seria necessária. É por isso que a memória é dividida em grandes blocos de, por exemplo, 4.096 bytes, e assim como você não pode comprar 2 laranjas e meia em uma mercearia, você não pode pedir meio bloco.

Então malloc pegará esses grandes blocos e lhe dará uma pequena fatia desses blocos de memória sempre que você chamá-los. Da mesma forma, se você liberou algumas variáveis, mas não o suficiente para justificar a liberação de um bloco inteiro, o sistema malloc pode manter blocos e reciclar zonas de memória quando você chamar malloc novamente. Isso tem a vantagem de tornar o malloc mais rápido, porém a memória reservada pelo malloc não pode ser usada em qualquer outro aplicativo, enquanto o programa não está usando atualmente na realidade.

Mas malloc é inteligente: se você chamar malloc para alocar 16 MiB ou uma grande quantidade, malloc provavelmente pedirá ao Linux blocos completos dedicados apenas para esta grande variável usando mmap. Dessa forma, quando você ligar gratuitamente, será mais provável evitar o desperdício de espaço. Não se preocupe, malloc está fazendo um trabalho muito melhor na reciclagem do que os humanos fazem com nosso lixo!

Conclusão

Acho que agora você entende melhor como tudo isso funciona. Claro, a alocação dinâmica é um grande tópico e acho que podemos escrever um livro completo sobre o assunto, mas este artigo deve deixá-lo confortável com o conceito em geral e com conselhos práticos de programação.

Instale o último jogo de estratégia OpenRA no Ubuntu Linux
OpenRA é um motor de jogo de estratégia em tempo real Libre / Free que recria os primeiros jogos Westwood como o clássico Command & Conquer: Red Alert...
Instale o emulador Dolphin mais recente para Gamecube e Wii no Linux
O Dolphin Emulator permite que você jogue seus jogos de Gamecube e Wii escolhidos em computadores pessoais Linux (PC). Sendo um emulador de jogo disp...
Como usar o GameConqueror Cheat Engine no Linux
O artigo cobre um guia sobre como usar o mecanismo de cheat GameConqueror no Linux. Muitos usuários que jogam no Windows costumam usar o aplicativo “C...