是的。它在 C 语言中是非法的。事实上,这样做是在向编译器施加压力。 p 指向元素arr[2][2](并且是指向int 类型的指针),即第三行的第三个元素。语句p=p+3; 会将指针p 递增到arr[2][5],相当于arr[3][0]。
但是,只要在某些架构上将内存分配为 2 ( 2n ) 的幂,这就会失败。现在在这种情况下,内存分配将四舍五入到 2n,即,在您的情况下,每一行将四舍五入到 64 字节。
请参阅一个测试程序,其中分配的内存是 10 个整数的 5 次分配。在某些机器上,内存分配是 16 字节的倍数,因此每次分配请求的 40 字节向上舍入为 48 字节:
#include <stdio.h>
#include <stdlib.h>
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");
}
}
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
Win7 上的示例输出; GCC 4.8.1: