A smart way to handle malloc errors without checking if NULL was returned after every malloc call?

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 there are four additional lines of code, and if I add them every time after using malloc, the length of my code will increase a lot. So is there an elegant way to handle this?

Thank you very much!

+6
source share
8 answers

Sorry, you can’t do anything about it in C. Except ... gasp ... wrap it all with a macro that automates if checking and allows you to write your own error handling code each time, I said that there.

Seriously, C is not intended to provide such amenities. If you don’t mind exiting the program in place, you can wrap it in a function, of course, which does exit when the distribution fails, but does not have a general solution.

+3
source

Usually it makes no sense to try to stumble when all memory is consumed. It is also possible that it is shutting down:

 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; } 
+5
source

You can use macros. This is cheaper than grouping this code into a function because macros do not have the overhead caused by calling the function. Macros expand at the compilation preprocessor stage and can be checked with the -E option in gcc. Now let's say that 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 
+3
source

If you do not have real error handling (other than printing anything and exiting), a simple and established solution is to define the safe_malloc function, which includes checking. (Edit: Or, of course, a macro. Whatever the stone of your boat.)

+1
source

If the error condition is always so simple (print the error message and return), you can rewrite to save the 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); 
0
source

C runtime should clean up any resources, including open files, buffers, and allocated data. However, I like to use int atexit( void(*)(void)) , which will call registered functions on normal output. Also exit immediately if atexit returns a nonzero value, i.e. your function has not been 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 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 ; } 
0
source
 #define my_malloc_macro(size, ptr) do { \ ptr = malloc(size); \ if(!ptr) { \ printf("malloc failed\n"); \ return -1; \ } \ } while(0) 
0
source

Or you can use extern.

Define the 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 adds mallocs memory, since you must forward the 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 link between the place in your code where you malloc'd memory and main.c, which handles the exception, is created behind the scenes by the linker; it maps function calls to a function, even if they exist in different source files.

0
source

All Articles