【问题标题】:Correct way to access to 2D Array - C访问二维数组的正确方法 - C
【发布时间】:2019-12-02 03:30:28
【问题描述】:

假设我有这个动态分配的二维数组:

//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 

我现在的问题是:如果编译器无论如何都会接受arr[0][5] = 1;,那么声明:int arr[3][2]; 有什么意义?

我正在使用 GCC 编译器

【问题讨论】:

  • 多维数组语法带来的问题多于解决的问题。

标签: c arrays multidimensional-array


【解决方案1】:

一般来说,不要写超出您分配的内存范围。

默认情况下,Clang 会对这两个示例发出警告,而 GCC 会在没有实际使用变量的情况下发出警告(这是死代码消除器的错误)。如果变量被使用或声明为volatile,您可以使用-O2 -Wall -Wextra 启用警告。

使用 GCC 和 Clang,这样做有点“安全”;每次都会发生同样的事情。

但是,这是未定义的行为,所以这是个坏主意。对于这样的程序来使您的计算机长腿并走开,这是完全有效的。

完成分配的等效方法是:

arr[2][1] = 1;

这是基于数组元素按顺序存储在内存中的假设。

所以,&arr[5][0] 在技术上与&arr[2][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;

这是保证安全的。

【讨论】:

  • 有什么方法可以让 GCC 来警告我吗?例如一些特殊的标志?因为即使不使用变量也会警告我这一点。
  • @Santiago 我发现最简单的方法是将变量 (printf("%d\n", arr[0][5]);) 与 -O2 -Wall -Wextra 结合使用。
  • @Santiago 如需更多信息,请参阅Why isn't gcc complaining about array bounds even if requested?
【解决方案2】:

在我的电脑 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-03
    • 2021-10-11
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    相关资源
    最近更新 更多