3

I have a segmentation fault when affecting a value to a[1][0], i thought my mallocs were correct but maybe there're not..

int main() {
    uint8_t **a;

    a = malloc(sizeof(uint8_t) * 6);
    *a = malloc(sizeof(uint8_t) * 2);

    a[0][0] = 1; // WORKS
    a[1][0] = 1; // DOES NOT WORK
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
aurel_lab
  • 149
  • 11

2 Answers2

2

Remember that the type of a is "pointer to pointer to uint8_t.

In your first malloc, it looks like you want a to point to an array of 6 uint8_t *. So your sizeof is wrong; you should do a = malloc(sizeof(uint8_t *) * 6).

Now a points to (the first element of) an array of 6 pointers, which are a[0] through a[5], each of which is uninitialized and probably doesn't point to anything useful.

In your second malloc, you allocate enough memory to hold 2 uint8_t, and set *a, which is the same as a[0], to point to that memory. Note that a[1], ..., a[5] still contain uninitialized pointers.

So accessing a[0][0] is fine, since a[0] does in fact point to valid memory.

a[1][0] is not fine, because a[1] doesn't point to valid memory. You never initialized a[1] with anything.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
0

i thought my mallocs were correct

They are not. We need a picture. You have two separate malloc blocks, one of size 6 (assuming sizeof(uint8_t) is 1); let's call it B1, and one of size 2 (call it B2). You also have two pointers: a that points to the first block, and *a that points to the second block.

a --> [*a, x, y]
        |
        |-> [w, z]

Let's assume you are on a 32-bit system, and sizeof(void*) is 4.

Line *a = malloc... initializes the first 4 bytes of B1 to point to B2, leaving the last 2 bytes of B1 (the x, y bytes) uninitialized.

Line a[0][0] = ... initializes the first byte of B2 (the w byte) to 1.

Line a[1][0] = ... uses 4 bytes at offset 4 in block B1 as a pointer.

The trouble is: the first two of these bytes (x, y bytes) are uninitialized, and the second two bytes are outsize of the allocated block altogether. So you have two bugs for the price of one.

You can clearly see that in e.g. valgrind output:

==9576== Invalid read of size 4
==9576==    at 0x804845A: main (/tmp/t.c:12)
==9576==  Address 0x420005c is 4 bytes inside a block of size 6 alloc'd
==9576==    at 0x402DBFA: malloc (valgrind/coregrind/m_replacemalloc/vg_replace_malloc.c:270)
==9576==    by 0x8048431: main (/tmp/t.c:8)
==9576== 
==9576== Use of uninitialised value of size 4
==9576==    at 0x804845C: main (/tmp/t.c:12)
==9576== 
==9576== Invalid write of size 1
==9576==    at 0x804845C: main (/tmp/t.c:12)
==9576==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

Now, it's not clear what the size of matrix you wanted to allocate is (where did the 6 come from?).

Assuming you wanted to create a dynamically allocated MxN array, the correct code to do so would be:

uint8_t **a;

a = malloc(M * sizeof(a[0]));
for (j = 0; j < M; ++j)
  a[j] = malloc(N * sizeof(a[0][0]));

// Now all M by N elements are accessible:
for (j = 0; j < M; ++j)
  for (k = 0; k < N; ++k)
    a[j][k] = 1;

// cleanup.
for (j = 0; j < M; ++j)
  free(a[j]);
free(a);
Employed Russian
  • 199,314
  • 34
  • 295
  • 362