7

In my code almost every function has one or more malloc calls, and each time I have to do something like:

char *ptr = (char *)malloc(sizeof(char) * some_int);
if (ptr == NULL) {
    fprintf(stderr, "failed to allocate memory.\n");
    return -1;
}

that's four extra lines of code and if I add them everytime after I use a malloc, the length of my code will increase a lot.. so is there an elegant way to deal with this?

Thank you so much!!

4
  • If the length of your code will increase a lot, you should think about why you're calling malloc so much. This probably indicates you're trying to translate a different language's idioms into C rather than using C properly... Commented Sep 18, 2011 at 15:45
  • 3
    Note that casting the return value of malloc in C is not needed and may hide an error the compiler would have caught without the cast. Commented Sep 18, 2011 at 17:07
  • @pmg you are talking about the (char *) right? What kind of errors does this cover up? Commented Jan 27, 2016 at 0:29
  • 1
    @cokedude: the error hiding happens if you do not include <stdlib.h> thereby using the function without a prototype. The compiler (wrongly) assumes malloc() returns a value of type int and, without the cast, complains with an error at the assignment because int* and int are not compatible. With the cast you force the compiler to shut up ... hiding the omission of the right #include. Commented Jan 27, 2016 at 8:54

8 Answers 8

5

There isn't usually much point in trying to stumble on when all memory is consumed. Might as well call it quits:

char* allocCharBuffer(size_t numberOfChars) 
{
    char *ptr = (char *)malloc(sizeof(char) * numberOfChars);
    if (ptr == NULL) {
        fprintf(stderr, "failed to allocate memory.\n");
        exit(-1);
    }
    return ptr;
}
Sign up to request clarification or add additional context in comments.

2 Comments

What about some clean up procedure? Deleting temporary files... etc.
You can use atexit()
3

Sorry, but there's nothing you can do about that in C. Except... gasp... wrap it all in a macro which will automate the if check and allow you to write custom error-handling code each time. There, I said it.

Seriously, C isn't meant to provide conveniences like this. If you don't mind exiting the program on the spot, you can wrap it in a function of course that does exit when the allocation fails -- but that's no general solution.

2 Comments

Or wrap it in a function instead of a macro.
@WTP: The problem with the function is that it can detect the condition, but not really handle it. At least not without your going to such great lengths that you 'd be better off with 4 lines of code at each call site. At least as far as I can tell.
3

You could use macros. This is cheaper than grouping this code into a function because Macros don't have the overhead a function call incurs. Macros are expanded by the preprocessor stage of compilation and can be verified by the '-E' option in gcc. Now say we have func1(), func2(), func3()

#define MY_MALLOC(_ptr,_count, _lbl) \
do { \
 if (NULL == (ptr = malloc(sizeof(char) * _count))) { \
    fprintf(stderr, "Failed to allocate memory.\n"); \
    goto _lbl; \
 } \
} while(0)

func1() {  
 char *ptr;
 MY_MALLOC(ptr,10,Error);
 ....
 ...
 return (0);
Error:
 return (1);
}


func2() {  
 char *ptr;
 MY_MALLOC(ptr,10,Error);
 ....
 ...
 return (0);
Error:
 return (1);
}


func3() {  
 char *ptr;
 MY_MALLOC(ptr,10,Error);
 ....
 ...
 return (0);
Error:
 return (1);
}

#undef MY_MALLOC

Comments

1

When you have no real error handling (except printing something and exiting), the simple and established solution is to define a function safe_malloc which incorporates the check. (Edit: Or, of course, a macro. Whatever rocks your boat.)

Comments

0

If you error condition is always that simple (print error message and return) you can rewrite to save lines.

int errmsg(const char *msg, int retval) {
    fprintf(stderr, "%s\n", msg);
    return retval;
}

if ((ptr = malloc(size)) == NULL) return errmsg("failed to allocate memory.", -1);
/* ... */
free(ptr);

Comments

0

C runtime should clean up any resources, including open files, buffers, and allocated data. Even so, I like to use int atexit( void(*)(void)) which will call registered functions upon a normal exit. Also exit immediately if atexit returns a non-zero value, meaning your function was not registered.

#include <stdlib.h>
void register_cleanup ( void ( *cleaner )( void ))
{
    if ( atexit ( cleaner ))
    {
        fprintf ( stderr, "Error, unable to register cleanup: %s\n",
                strerror ( errno )) ;
        exit ( EXIT_FAILURE ) ;
    }
}

Then exit on malloc failure.

#include <stdlib.h>
void *malloc_or_die ( size_t size )
{
    void *dataOut = malloc ( size ) ;
    if ( !dataOut )
    {
        fprintf ( stderr, "Error, malloc: %s\n", strerror ( errno )) ;
        exit ( EXIT_FAILURE ) ;
    }
    return dataOut ;
}
void main()
{
    register_cleanup ( cleaner_fnc ) ;
    ...
    void *data = malloc_or_die ( 42 ) ;
    do_stuff ( data ) ;
    return 0 ;
}

1 Comment

This does not take into account other data to be deallocated within the same funtion, or not taken care of in an atexit function. The macro from Anoop Menon would allow that. If error handling is different per-function, it would be more clear to not use a macro abstraction.
0
#define my_malloc_macro(size, ptr) do { \
    ptr = malloc(size); \
    if(!ptr) { \
        printf("malloc failed\n"); \
        return -1; \
    } \
} while(0)

Comments

0

Or you could use an extern.

Define a function in main.c:

 void sj_handleException(bool fatal, const char* msg, const char* libMsg){
  fprintf(stderr, msg);
  if(libMsg != NULL) fprintf(stderr, libMsg);

  if(fatal) exit(EXIT_FAILURE);    
}

Any file that mallocs memory add as you would a forward declaration:

extern void sj_handleException(bool fatal, const char* msg, const char* libMsg)

Now write malloc as:

char *ptr = (char *)malloc(sizeof(char) * some_int);
if (ptr == NULL) sj_handleException(true, "failed to allocate memory.\n", NULL);

The linkage between the place in your code where you malloc'd memory and main.c that handles the exception is generated behind the scenes by the linker; it maps calls to the function with the function even though the two exist in different source files.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.