Search code examples
cpointerscalloc

Allocate array in main inside a function which is defined outside of main


I'm trying to use calloc on array inside a function but it doesn't work. When trying to debug I found that inside the function the pointer points to the allocated memory but when leaving the function it points to NULL again. Tried all kinds of variations but can't seem to find a solution.

This is my code:

int main(int argc, char *argv[]) {
    int *rows = NULL, *solvedRows = NULL;
    int **board = NULL, **solvedBoard = NULL;
    allocateMemory(dim, &(*rows), &(*board));
    allocateMemory(dim, &(*solvedRows), &(*solvedBoard));
}

void allocateMemory(int dim, int** rows, int*** board) {
    rows = calloc(dim*dim,sizeof(int));
    board = calloc(dim, sizeof(int*));
    if (rows == NULL || board == NULL) {
        printf("Error: calloc has failed\n");
        exit(1);
    }
}

Need help to understand what's wrong and how to fix it.

EDIT

I tried:

*rows = calloc(dim*dim,sizeof(int));
*board = calloc(dim, sizeof(int*));

Still have same problem.

Also tried:

allocateMemory(dim, &rows, &board);

for line 4 and (5 the same) and in doesn't compile with the error: "error: passing argument 2 of 'allocateMemory' from incompatible pointer type [-Werror=incompatible-pointer-types] allocateMemory(dim, &rows, &board); ^" error: passing argument 3 of 'allocateMemory' from incompatible pointer type [-Werror=incompatible-pointer-types] allocateMemory(dim, &rows, &board); ^

EDIT

For anyone who encounters this problem and checks this page, this last try is in fact correct, as Michael answered below. The errors are for a mistake in the corresponding header file, and were fixed when fixing the header file.


Solution

  • Let's focus on your rows variable:

    rows is a pointer, which is a variable holding a memory address. Now you want alocateMemory to write into rows the address of a block of memory, to hold your data. Easy enough:

    size_d dim = 10;
    int* rows = 0;
    rows = calloc(1, sizeof(int) * dim);
    

    However, if you put this code into a function like

    void allocateMemory(size_t dim, int* rows) {
        rows = calloc(1, sizeof(int) * dim);
    }
    

    Now if you call this function like

    int* actualRows = 0;
    allocateMemory(3, actualRows);
    

    The value of actualRows (namely 0) will be copied into a new variable rows which you manipulate in allocateMemory. When you write into rows, its value changes, but when allocateMemory is left, rows will be destroyed. Never will actualRows be altered.

    What you want is that allocateMemory sets the value of actualRows o a memory address. To do this, you have to provide allocateMemory with the address of actualRows like

    allocateMemory(3, &actualRows);
    

    &atualRows is the memory address of actualRows and its type is int** (pointer to a pointer to int).

    Now you have to adapt the signature of allocateMemory appropriately:

    void allocateMemory(size_t dim, int** rows) {
        rows = calloc(1, sizeof(int) * dim);
    }
    

    And, since rows now is a pointer and you want to change its target, you need to dereference it before assigning it:

    *rows = calloc(1, sizeof(int) * dim);
    

    Yielding all in all:

    void allocateMemory(size_t dim, int** rows) {
        *rows = calloc(1, sizeof(int) * dim);
    }
    
    ...
    int* actualRows = 0;
    allocateMemory(3, &actualRows);
    ...
    

    For your board, its the same in principle. Try

    #include <stdio.h>
    #include <stdlib.h>
    
    void allocateMemory(int dim, int** rows, int*** board) {
        *rows = calloc(dim * dim,sizeof(int));
        *board = calloc(dim, dim * sizeof(int*));
    
        if (rows == NULL || board == NULL) {
            printf("Error: calloc has failed\n");
        }
    
        for(size_t i = 0; i < dim; ++i) {
            (*board)[i] = calloc(1, sizeof(int) * dim);
    
            if ((*board)[i] == NULL) {
                printf("Error: calloc has failed\n");
            }
        }
    
    }
    
    int main(int argc, char *argv[]) {
    
        size_t dim = 10;
    
        int *rows = NULL;
        int **board = NULL;
        allocateMemory(dim, &rows, &board);
    
        rows[0] = 10;
        rows[1] = 11;
    
        for(size_t i = 0; i < dim; ++i) {
            printf("%i ", rows[i]);
        }
    
        printf("\n\n\n");
    
        board[0][0] = 11;
        board[9][0] = 99;
        board[9][9] = 101;
    
        for(size_t i = 0; i < dim; ++i) {
    
            for(size_t k = 0; k < dim; ++k) {
    
                printf("%i ", board[i][k]);
            }
            printf("\n");
        }
    
        printf("\n");
    
        for(size_t i = 0; i < dim; ++i) free(board[i]);
        free(board);
    
        free(rows);
    }