Search code examples
cmultidimensional-arraydynamic-programming

Memory Limit Exceed in C dynamic array


I am trying to create a 3D array using memory allocation, and free it. However, it seems that my program exceed the memory limit. How can I optimize it? And what point do i miss?

function.h

unsigned*** new_3d_array(unsigned n,unsigned m,unsigned k);
void delete_3d_array(unsigned ***arr);

unsigned*** new_3d_array(unsigned n,unsigned m,unsigned k){
    unsigned*** array = (unsigned***)malloc(n * sizeof(unsigned**));
    for (int i = 0; i < n; i++) {
            array[i] = (unsigned**)malloc(m * sizeof(unsigned*));
            for (int j = 0; j < m; j++) {
                    array[i][j] = (unsigned*)malloc(k * sizeof(unsigned));
            }
    }

    return array;
}

void delete_3d_array(unsigned ***arr){
    unsigned long long int n = sizeof(arr)/sizeof(arr[0]); //Get individual general size
    unsigned long long int m = sizeof(arr[0])/sizeof(arr[0][0]);
    
    for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                 free(arr[i][j]);
            }
            free(arr[i]);
    }
    free(arr);
}

main.c

#include<stdio.h>
#include"function.h"

//Sample Input
//60 100 100 100 7122

unsigned random_seed=7122;
unsigned Random(){
    return random_seed=random_seed*0xdefaced+1;
}
int main(){
    int n,m,k,_;
    scanf("%d%d%d%d%u",&_,&n,&m,&k,&random_seed);
    while(_--){
        unsigned ***arr=new_3d_array(n,m,k);
        int i,j,l;
        for(i=0;i<n;++i){
            for(j=0;j<m;++j){
                for(l=0;l<k;++l){
                    arr[i][j][l]=Random();
                }
            }
        }
        for(i=0;i<5;++i){
            unsigned a,b,c;
            a=Random()%n;
            b=Random()%m;
            c=Random()%k;
            if(i)putchar(' ');
            printf("%u",arr[a][b][c]);
        }
        puts("");
        delete_3d_array(arr);
    }
    return 0;
}


I have tried to define it using for loop. Because the free function only pass the 3d array as argument, I can only find the size by dividing it.

Turned my program is not optimized enough.


Solution

  • First of all, I strongly recommend to ditch the pointer-to-pointer-to-pointer and instead allocate this all as a fast contiguous 3D array instead. Correctly allocating multi-dimensional arrays

    Because the free function only pass the 3d array as argument, I can only find the size by dividing it.

    No, you can't do that. There is no information stored anywhere regarding the size of the arrays, it is the programmer's job to keep track of that. sizeof is mostly a compile-time operator so it has no magical knowledge of how large some dynamic arrays are. What you get instead is the size in bytes of the pointers. For details see How to find the size of an array (from a pointer pointing to the first element array)?.

    So you need to declare delete_3d_array with 3 size parameters. Notably this wouldn't have been a problem if you had used a 3D array instead, then you could just free(array) on a single line.

    Quick fix (not tested):

    #include <stdio.h>
    #include <stdlib.h>
    
    unsigned random_seed=7122;
    unsigned Random(){
        return random_seed=random_seed*0xdefaced+1;
    }
    int main(){
        int x,y,z,_;
        scanf("%d%d%d%d%u",&_,&x,&y,&z,&random_seed);
        if(x==0 || y==0 || z==0)
            return 1;
    
        while(_--){
            unsigned (*arr)[y][z] = malloc( sizeof(unsigned[x][y][z]) );
            if(arr == NULL)
                return 1;
    
            for(int i=0;i<x;++i){
                for(int j=0;j<y;++j){
                    for(int k=0;k<z;++k){
                        arr[i][j][k]=Random();
                    }
                }
            }
            for(int i=0;i<5;++i){
                unsigned a,b,c;
                a=Random()%x;
                b=Random()%y;
                c=Random()%z;
                if(i)putchar(' ');
                printf("%u",arr[a][b][c]);
            }
            puts("");
            free(arr);
        }
        return 0;
    }