#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
 
#define allocate( type, n ) malloc( sizeof(type) * n )
#define clear_allocate( type, n ) calloc( n, sizeof(type) )
 
// total rows initialized in pool
#define NUM_ROWS (size_t)100
 
#define HEIGHT (size_t)3
#define WIDTH (size_t)4
 
int main() {
 
    typedef double Element;
    typedef Element* Row;
    typedef Row* Matrix;
 
    _Bool allocate_successfully = true;
    size_t failure_at = NUM_ROWS;
 
    // handle of all rows
    Row * allocated_rows = allocate( Row, NUM_ROWS );
    assert( allocated_rows != NULL ); // fatal error
    // init each rows ( allocate memory needed )
    for ( size_t i = 0; allocate_successfully && i != NUM_ROWS; ++i ) {
 
        allocated_rows[ i ] = allocate( Element, WIDTH );
 
        if ( allocated_rows[ i ] == NULL ) {
            allocate_successfully = false;
            failure_at = i;
        }
    }
 
    if ( allocate_successfully == false )
        goto after_use;
 
    size_t next = 0;
    Matrix a1 = allocate( Row, HEIGHT );
    assert( a1 != NULL ); // fatal error
    for ( size_t row = 0; row != HEIGHT; ++row ) {
        a1[ row ] = allocated_rows[ next++ ];
    }
 
    Matrix a2 = allocate( Row, HEIGHT );
    assert( a2 != NULL ); // fatal error
    for ( size_t row = 0; row != HEIGHT; ++row ) {
        a2[ row ] = allocated_rows[ next++ ];
    }
 
after_use:
    {
    Matrix matrices[] = { a1, a2 };
    for ( size_t i = 0; i != sizeof(matrices)/sizeof(matrices[0]); ++i )
        free( matrices[ i ] );
 
    // free the rows allocated in pool
    for ( size_t i = 0; i != failure_at; ++i )
        free( allocated_rows[ i ] );
    free( allocated_rows );
    }
    
    return EXIT_SUCCESS;
}