Ir ao conteúdo

Posts recomendados

Postado

Em C usamos as funções malloc, calloc e realloc para alocar(reservar) ou realocar memória dinamicamente, mas estas funções podem falhar, logo sempre é necessário analisar o retorno destas funções para verificar se a memória foi alocada com sucesso.

 

Então, uma solução para não ter que ficar repetindo a verificação seria encapsular estas funções dentro de outra funções que tratam o caso de falha e nunca retornam um ponteiro nulo (NULL). Como em:

 

#include <stdio.h>
#include <stdlib.h>

void *allocateMemory(size_t size) {
    void *pointer = malloc(size);

    if(!pointer)
    {
        fprintf(stderr, "Could not allocate\n");
        exit(EXIT_FAILURE);
    }

    return pointer;
}

 

 

Mas essa função não ajudaria a diagnosticar onde o problema ocorreu no programa, logo uma melhoria seria fazer a função indicar o nome do arquivo e a linha do código onde o erro ocorreu.

 

E com isso em mente segue uma solução completa, com funções que verificam os casos de falha na alocação e indicam onde o erro ocorreu, e macros para chamar as funções usando os mesmos parâmetros das funções originais (malloc, calloc e realloc):

 

#include <stdio.h>
#include <stdlib.h>


#define VMALLOC(Size) allocateMemory(__FILE__, __LINE__, Size)

void *allocateMemory(const char *file, long line, size_t size) {
    void *pointer = malloc(size);

    if(!pointer)
    {
        fprintf(stderr, "Could not allocate: %zu bytes (%s:%ld)\n", size, file, line);
        exit(EXIT_FAILURE);
    }

    return pointer;
}


#define VCALLOC(NumberOfElements, ElementSize) allocateCleanMemory(__FILE__, __LINE__, NumberOfElements, ElementSize)

void *allocateCleanMemory(const char *file, long line, size_t numberOfElements, size_t elementSize) {
    void *pointer = calloc(numberOfElements, elementSize);

    if(!pointer)
    {
        fprintf(stderr, "Could not allocate: %zu bytes (%s:%ld)\n", numberOfElements * elementSize, file, line);
        exit(EXIT_FAILURE);
    }

    return pointer;
}


#define VREALLOC(MemoryBlock, NewSize) reallocateMemory(__FILE__, __LINE__, MemoryBlock, NewSize)

void *reallocateMemory(const char *file, long line, void *memoryBlock, size_t newSize) {
    void *pointer = realloc(memoryBlock, newSize);
    
    if(!pointer)
    {
        fprintf(stderr, "Could not allocate: %zu bytes (%s:%ld)\n", newSize, file, line);
        free(memoryBlock);
        exit(EXIT_FAILURE);
    }

    return pointer;
}

 

 

E para usá-las basta chamar o respectivo macro do mesmo modo que faria com a função original, com a diferença de que não há a necessidade de verificar o retorno.

 

Por exemplo:

size_t bytes = 10 * sizeof(int);
int forceFailure = 0;
int *anArray = NULL;

/* 
    Mude o respectivo 'forceFailure' para um valor diferente
    de zero para verificar como cada função se comporta quando
    não consegue alocar memória.
*/

// Verified malloc
forceFailure = 0;
if(forceFailure)
    bytes = -1;

anArray = VMALLOC(bytes);
free(anArray);

// Verified calloc
forceFailure = 0;
if(forceFailure)
    bytes = -1;
anArray = VCALLOC(1, bytes);

// Verified realloc
forceFailure = 0;
if(forceFailure)
    bytes = -1;
else
    bytes = 10 * bytes;
anArray = VREALLOC(anArray, bytes);
free(anArray);

 

 

OBS: Vale notar que as funções propostas aqui apenas geram a mensagem de erro e encerram o programa em caso de falha na alocação, mas há situações em que seria preferível tratar o erro de outra maneira que não faça com que o programa seja encerrado abruptamente, logo estas funções não são adequadas para esses casos e precisariam ser adaptadas.

 

  • Obrigado 3
  • Amei 1
  • isrnick alterou o título para Funções e macros para fazer alocação dinâmica de memória de forma prática
  • 2 meses depois...
  • Membro VIP
Postado

Genial!!!

 

Eu adaptei para funcionar com as syscalls, e ficou assim:

#define FATAL_ERROR(msg) error(msg, __FILE__, __LINE__)

void error(const char *msg, const char *file, long line)
{
	std::fprintf(stderr, "Fatal error: %s in %s:%ld: %s\n", msg, file, line, std::strerror(errno));
	std::exit(EXIT_FAILURE);
}

 

Exemplo de invocação:

if (close(fd) == -1)
  FATAL_ERROR("close()");

 

Exemplo do output gerado:

Fatal error: close() in src/classes/ServerManager/ServerManager.cpp:89: Bad file descriptor

 

  • Curtir 2
  • Amei 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!