假设我有这个动态分配的2D数组:
//Example of a 3 row * 2 columns int array
int (*arr)[2] = malloc(sizeof(int[3][2]));
但是,我发现如果我这样做:
arr[0][5] = 1;
编译器不会抱怨,至少使用valgrind进行测试时,它也不会抱怨。除非我尝试访问超出已分配空间大小的空间,否则不会这样做。
我发现自动数组也会发生同样的情况:
int arr[3][2];
arr[0][5] = 1; //Code works without errors
我的问题是:例如,声明:int arr[3][2];
编译器是否仍将接受arr[0][5] = 1;
是什么意思?
我正在使用GCC编译器
在我的PC Gcc 8.1.0中
#include <stdio.h>
#include <stdlib.h>
int main(){
int i,j;
int (*arr)[2] = malloc(sizeof(int[3][2]));
printf("%p %d %d\n",arr,sizeof(int),sizeof(int[3][2]));
//in my computer print
//00C63E38 4 24
//legal memory from 00C63E38~00C63E4C
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%p ",&arr[i][j]);
}
printf("\n");
}
//00C63E38 00C63E3C
//00C63E40 00C63E44
//00C63E48 00C63E4C
printf("------------------\n");
for(i=0;i<3;i++){
for(j=0;j<2;j++){
printf("%p ",*(arr+i)+j);
}
printf("\n");
}
//00C63E38 00C63E3C
//00C63E40 00C63E44
//00C63E48 00C63E4C
//So arr[i][j] is equel *(arr+i)+j
printf("-------------\n");
for(i=0;i<6;i++){
printf("%p ",arr+i);
printf("\n");
}
printf("-------------\n");
//jump 4*2 pointer address per loop from 00C63E38
//00C63E38
//00C63E40
//00C63E48
//00C63E50
//00C63E58
//00C63E60
for(i=0;i<6;i++){
printf("%p ",arr[0]+i);
printf("\n");
}
//jump 4 pointer address per loop from 00C63E38
//00C63E38
//00C63E3C
//00C63E40
//00C63E44
//00C63E48
//00C63E4C
free(arr);
return 0;
}
通常,不要超出已分配的内存范围。
Clang默认会警告两个示例,而GCC不会警告两个示例,而不会实际使用变量(这是无效代码消除器的错误)。如果使用变量或将其声明为-O2 -Wall -Wextra
,则可以使用volatile
启用警告。
但是,这是(当然)未定义的行为,所以它总是一个坏主意。
一种(可能)等效的分配方式是:
arr[2][1] = 1;
这是基于数组元素顺序存储在内存中的假设。
我的建议:
int arr[3][2];
int x, y;
for( x = 0; x < 3; x++ )
for( y = 0; y < 2; y++ )
arr[x][y] = x * y;
保证安全。