¿Una forma clara de manejar el error de malloc sin verificar si se devolvió NULL después de cada llamada a malloc?

En mi código, casi todas las funciones tienen una o más llamadas malloc, y cada vez tengo que hacer algo como:

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

eso es cuatro líneas adicionales de código y si las agrego cada vez que uso un malloc, la longitud de mi código boostá mucho … así que, ¿hay una manera elegante de lidiar con esto?

¡¡Muchas gracias!!

Lo sentimos, pero no hay nada que puedas hacer al respecto en C. Excepto … jadeo … envuelve todo en una macro que automatizará el chequeo if y te permitirá escribir códigos personalizados de manejo de errores cada vez. Ahí lo dije.

En serio, C no está destinado a proporcionar comodidades como esta. Si no le importa salir del progtwig en el momento, puede envolverlo en una función que, por supuesto, termina cuando falla la asignación, pero esa no es una solución general.

Por lo general, no tiene mucho sentido tratar de encontrar cuándo se consume toda la memoria. También podría dejar de fumar:

 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; } 

Podrías usar macros. Esto es más barato que agrupar este código en una función porque las macros no tienen la sobrecarga en la que incurre una función. Las macros se expanden en la etapa de comstackción del preprocesador y se pueden verificar con la opción ‘-E’ en gcc. Ahora digamos que tenemos 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 

Cuando no tiene un manejo real de errores (excepto la impresión de algo y la salida), la solución simple y establecida es definir una función safe_malloc que incorpore el cheque. (Edición: O, por supuesto, una macro. Lo que sea que oscile su barco.)

Si la condición de error siempre es así de simple (mensaje de error de impresión y devolución), puede volver a escribir para guardar líneas.

 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); 

C runtime debe limpiar todos los recursos, incluidos archivos abiertos, buffers y datos asignados. Aun así, me gusta usar int atexit( void(*)(void)) que llamará a las funciones registradas en una salida normal. También salga inmediatamente si atexit devuelve un valor distinto de cero, lo que significa que su función no se registró.

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

Luego salga en la falla de Malloc.

 #include  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 ; } 
 #define my_malloc_macro(size, ptr) do { \ ptr = malloc(size); \ if(!ptr) { \ printf("malloc failed\n"); \ return -1; \ } \ } while(0) 

O podrías usar un extern.

Define una función en 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); } 

Cualquier archivo que la memoria de mallocs agregue como lo haría una statement de reenvío:

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

Ahora escribe malloc como:

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

El vínculo entre el lugar en su código donde está la memoria malloc’d y main.c que maneja la excepción es generado por el vinculador entre bambalinas; asigna llamadas a la función con la función aunque las dos existen en archivos de origen diferentes.