redixhumayun
redixhumayun

Reputation: 1844

dereferencing pointer to array of pointers

I'm trying to understand how a pointer to an array of pointers works.

I have the following struct

typedef struct Array {
    int capacity;
    int size;
    void **items;
} Array;

and the following function which allocates memory for the struct and returns a pointer to it

Array *createArray(int capacity) {
    Array *array = malloc(sizeof(Array *));
    array->capacity = capacity;
    array->size = 0;
    void **items = malloc(sizeof(void *) * array->capacity *  sizeof *items);
    if(items == NULL) {
        exit(1);
    }
    array->items = items;
    return array;
}

Now, I want to initialize an array of pointers to this struct. Here's how I am doing that

Array *(*createHashTable(int size))[10] {
    Array *array[10]; 
    int i = 0;
    for(i = 0; i < size; i++) {
        array[i] = createArray(size);
    }
    Array *(*ptr)[10] = &array;
    for(i = 0; i < size; i++) {
        printf("%d\n", (*(ptr[0] + i))->capacity);
    }
    return ptr;
}

The print statement gives me what I expect: which is

10
10
10
10
10
10
10
10
10
10

Now, my main function

int main(int argc, char *argv[]) {
    Array *(*ptr)[10] = createHashTable(10);
    printf("%d\n", (*(ptr[0]+9))->capacity);
    return 0;
}

So far, everything makes sense to me, with the printf statement in main working fine. However, the part that confuses me is if I place a for loop inside my main function like so

int main(int argc, char *argv[]) {
    Array *(*ptr)[10] = createHashTable(10);
    int i = 0;
    for(i = 0; i < 10; i++) {
        printf("%d\n", (*(ptr[0] + i))->capacity);
    }
    return 0;
}

I get the following output,

10
10
Segmentation fault: 11

Why is my program seg faulting only when I loop? Am I missing something basic about returning a pointer to an array of pointers?

Upvotes: 1

Views: 645

Answers (2)

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53006

First. The problem appears to be that you are not allocating enough memory,

Array *array = malloc(sizeof(Array *));

allocates only sizeof(void *) bytes, and that's probably less than sizeof(Array)1

So when you try to initialize the returned array you are accessing memory that you did not allocate, thus invoking undefined behavior.

To be always right on the ammount of memory, use the following syntax

Array *array = malloc(sizeof(*array));

this way you ensure that you are allocating the correct size.

Second. If you see that the values were printed as expected, blame it on undefined behavior. Because your code has invoked it, it will not go away after you did, and the problem will appear sooner, later or perhaps never, but it's still there. That's the worst thing about undefined behavior, since it's undefined you cannot predict when or whether it will happen.


1In fact it's surely less, because you need at least sizeof(void *) + 2 * sizeof(int), that is if you ignore padding.

Upvotes: 2

Yang
Yang

Reputation: 91

Array *array = malloc(sizeof(Array *));

should be

Array *array = malloc(sizeof(Array));

sizeof(Array *) is just size of a pointer, while sizeof(Array) is size of the structure Array.

But I don't know exactly what happened in your code, as it went wrong at array->items = items; in my computer, maybe you can try printf("%d\n", &((*(ptr[0]+9))->capacity)); to get the address and work out what exactly is in this address with gdb.

Upvotes: 1

Related Questions