Yes. It is illegal in C. In fact by doing so you are laying to your compiler. p is pointing to the element arr[2][2] (and is of pointer to int type), i.e, 3rd element of third row. The statement p=p+3; will increment the pointer p to arr[2][5], which is equivalent to arr[3][0].
But this will fail whenever memory is allocated as a power of 2 ( 2n ) on some architechture. Now in this case the memory allocation would round up to 2n, i.e, in your case, each row would round up to 64 bytes.
See a test program in which the memory allocated is 5 allocations of 10 integers. On some machines, memory allocations are a multiple of 16 bytes, so the 40 bytes requested is rounded up to 48 bytes per allocation:
#include
#include
extern void print_numbers(int *num_ptr, int n, int m);
extern void print_numbers2(int **nums, int n, int m);
int main(void)
{
int **nums;
int n = 5;
int m = 10;
int count = 0;
// Allocate rows
nums = (int **)malloc(n * sizeof(int *));
// Allocate columns for each row
for (int i = 0; i < n; i++)
{
nums[i] = (int *)malloc(m * sizeof(int));
printf("%2d: %p\n", i, (void *)nums[i]);
}
// Populate table
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
nums[i][j] = ++count;
// Print table
puts("print_numbers:");
print_numbers(&nums[0][0], n, m);
puts("print_numbers2:");
print_numbers2(nums, n, m);
return 0;
}
void print_numbers(int *nums_ptr, int n, int m)
{
int (*nums)[m] = (int (*)[m])nums_ptr;
for (int i = 0; i < n; i++)
{
printf("%2d: %p\n", i, (void *)nums[i]);
for (int j = 0; j < m; j++)
{
printf("%3d", nums[i][j]);
}
printf("\n");
}
}
void print_numbers2(int **nums, int n, int m)
{
for (int i = 0; i < n; i++)
{
printf("%2d: %p\n", i, (void *)nums[i]);
for (int j = 0; j < m; j++)
printf("%3d", nums[i][j]);
printf("\n");
}
}
Sample output on Mac OS X 10.8.5; GCC 4.8.1:
0: 0x7f83a0403a50
1: 0x7f83a0403a80
2: 0x7f83a0403ab0
3: 0x7f83a0403ae0
4: 0x7f83a0403b10
print_numbers:
0: 0x7f83a0403a50
1 2 3 4 5 6 7 8 9 10
1: 0x7f83a0403a78
0 0 11 12 13 14 15 16 17 18
2: 0x7f83a0403aa0
19 20 0 0 21 22 23 24 25 26
3: 0x7f83a0403ac8
27 28 29 30 0 0 31 32 33 34
4: 0x7f83a0403af0
35 36 37 38 39 40 0 0 41 42
print_numbers2:
0: 0x7f83a0403a50
1 2 3 4 5 6 7 8 9 10
1: 0x7f83a0403a80
11 12 13 14 15 16 17 18 19 20
2: 0x7f83a0403ab0
21 22 23 24 25 26 27 28 29 30
3: 0x7f83a0403ae0
31 32 33 34 35 36 37 38 39 40
4: 0x7f83a0403b10
41 42 43 44 45 46 47 48 49 50
Sample output on Win7; GCC 4.8.1:
