Reputation: 2753
I came across some "weird" behaviour in C, at least something I did not expect. Consider this following line of code:
int arrayB[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("%d\n", (arrayB+1)[1]);
This works fine as (arrayB + 1)[1]
translates to *(arrayB+1 +1)
which is the third element of arrayB
(thus it prints 3 as expected)
However, consider the below code where I initialize a 2D array called arrayA
(with 5 arrays of 10 ints, each {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
)
int ** arrayA = malloc(sizeof(int *) * 5);
for (int i = 0; i < 5; i++) {
arrayA[i] = malloc(sizeof(int) * 10);
for (int j = 0; j < 10; j++) {
arrayA[i][j] = j;
}
}
printf("%d\n", *(arrayA+1)[2]);
This code does not raise a warning, and it claims that *(arrayA+1)[2]
is an int type. However.. it seems that it should be (since array subscript has higher priority over dereference operator), *(arrayA+1)[2]
translates to *(arrayA+3)
which is of type int *
, since arrayA
is a int **
that Even further is that this is allowed after:
*(arrayA+1)[2] = 1;
But how is this possible? It seems as if I am assigning a int
to a int *
... which typically raises a warning.
Upvotes: 0
Views: 60
Reputation: 84521
In addition to the pointer correction, while you are free to declare a pointer-to-pointer-to-int (e.g. int **arrayA;
), and allocate pointers, then allocate memory and assign the block to each individual pointer, there is no need to do so when dealing with a fixed number of elements in each row. You can simply declare a pointer-to-array-of-type-no. (e.g. int (*arrayA)[10];
and allocate once. For example:
#include <stdio.h>
#include <stdlib.h>
#define ASZ 5
void *xmalloc (size_t s) {
void *memptr = malloc (s);
if (memptr == 0) {
fprintf (stderr, "xmalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
int main (void) {
int i, j;
int (*arrayA)[ASZ] = xmalloc (sizeof *arrayA * ASZ);
for (i = 0; i < ASZ; i++) {
for (j = 0; j < ASZ; j++) {
arrayA[i][j] = j+i;
}
}
for (i = 0; i < ASZ; i++) {
if (!i) putchar ('\n');
for (j = 0; j < ASZ; j++) {
printf (" %2d", arrayA[i][j]);
}
putchar ('\n');
}
printf("\n *(arrayA+1)[2] = %d\n\n", *(arrayA+1)[2]);
free (arrayA);
return 0;
}
(don't forget to validate your memory allocation. using a helper like xmalloc
can make life easier)
Example Use/Output
$ ./bin/arr2dderef
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
*(arrayA+1)[2] = 3
Don't forget to validate your memory use with a memory error checking program such as valgrind
on Linux, and don't forget to free the memory when it is no longer needed. (yes it is freed automatically on exit
, but get in the habit now of accounting for each byte, and you will save yourself a lot of grief later)
$ valgrind ./bin/arr2dderef
==28392== Memcheck, a memory error detector
==28392== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==28392== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==28392== Command: ./bin/arr2dderef
==28392==
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
*(arrayA+1)[2] = 3
==28392==
==28392== HEAP SUMMARY:
==28392== in use at exit: 0 bytes in 0 blocks
==28392== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==28392==
==28392== All heap blocks were freed -- no leaks are possible
==28392==
==28392== For counts of detected and suppressed errors, rerun with: -v
==28392== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
Upvotes: -1
Reputation: 230
We discuss about the int ** arrayA (2D).
arrayA is int ** , so arrayA+x is int ** too.
*arrayA or arrayA[i] is int *, and is a linear array(1D).
So, *(arrayA+1)[2], with any priority is a value not address.
Upvotes: 0
Reputation: 280181
it seems that ...
*(arrayA+1)[2]
translates to*(arrayA+3)
No, you dropped a *
. *(arrayA+1)[2]
translates to **(arrayA+3)
, which is indeed an int
.
Upvotes: 3