1

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?

4
  • 2
    Array *array = malloc(sizeof(Array *));->Array *array = malloc(sizeof(Array)); Commented Feb 20, 2018 at 17:24
  • I am a little surprised, because there is one case where you used the never wrong sizeof(*VARIABLE). For instance Array *array = malloc(sizeof(*array)) would never be wrong. Even if you change Array *array; to Array ****array;! Oh, and that's an interesting return type for a function, not to mention that it makes c a weird language. Commented Feb 20, 2018 at 17:26
  • @coderredoc - Hey, do you mind elaborating on why that will fix it? I'm not following... Commented Feb 20, 2018 at 17:27
  • 1
    @random_coder_101 It's not a pointer that you're allocating, it's an instance of the structure. sizeof(Array *) is equal to the size of any pointer, even sizeof(void *), so it's allocating either 4 or 8 bytes, depending on the platform and OS. But you really, need sizeof(Array) bytes to allocate. Commented Feb 20, 2018 at 17:30

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

It's also probably better to do a one-shot allocation of M*N entries and then split out those chunks into separate pointers, giving you a contiguous region of memory. Separate allocations may lead to fragmentation.
Unfortunately, that doesn't seem to have made any difference. My code is still segfaulting in the exact same way. Also, this still doesn't explain why the loop in createHashTable printed out the values correctly, right?
@random_coder_101, what OS are you working with? and remove that horrible return type, use a typedef or something! It's just a suggestion.
@IharobAlAsimi - macOS High Sierra v0.13.1
1
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.

2 Comments

What do you mean "it went wrong ... in my computer"? Are you aware of undefined behavior?
What I mean is it is undefined behavior, so the result by my compiler is different from @random_coder_101.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.