Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 为什么2D数组的行为类似于指针的一维数组,而不是整数的一维数组?_Arrays_C_Pointers_Multidimensional Array_Implicit Conversion - Fatal编程技术网

Arrays 为什么2D数组的行为类似于指针的一维数组,而不是整数的一维数组?

Arrays 为什么2D数组的行为类似于指针的一维数组,而不是整数的一维数组?,arrays,c,pointers,multidimensional-array,implicit-conversion,Arrays,C,Pointers,Multidimensional Array,Implicit Conversion,我一直在研究和测试我在C语言方面的知识(我是一名计算机工程的新生),但遇到了一个我无法解决的问题 在尝试将2D数组传递给函数时,我了解到不能使用动态分配的数组,因为编译器需要知道数组[][列]。但是,我了解到二维数组存储在一维数组中,其中每一新行的元素都紧跟在前一行的元素之后。当我将数组名作为指向数组的指针传递给函数时,情况似乎就是这样,我的代码运行良好。但是,在声明2D数组的函数中,它的行为类似于指针数组 #include <stdio.h> void printArray(in

我一直在研究和测试我在C语言方面的知识(我是一名计算机工程的新生),但遇到了一个我无法解决的问题

在尝试将2D数组传递给函数时,我了解到不能使用动态分配的数组,因为编译器需要知道数组[][列]。但是,我了解到二维数组存储在一维数组中,其中每一新行的元素都紧跟在前一行的元素之后。当我将数组名作为指向数组的指针传递给函数时,情况似乎就是这样,我的代码运行良好。但是,在声明2D数组的函数中,它的行为类似于指针数组

#include <stdio.h>

void printArray(int *A, int* dimA) {
    for(int i = 0; i < dimA[0]; ++i) {
        for(int j = 0; j < dimA[1]; ++j) {
            printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
        }
    printf("\n\n");
    }
return;
}

int main(){
    int A[2][2] = {{1,2},{3,4}};
    int dimA[2] = {2,2};//dimensions of the array
    int i, j; 

    for(i = 0; i < dimA[0]; ++i) {
        for(j = 0; j < dimA[1]; ++j) {
            printf("%3d", *(A[i] + j)); //This would work if the elements of A[] are pointers
        }
        printf("\n\n");
    }

    for(i = 0; i < dimA[0]; ++i) {  //Same code as printArray function
        for(j = 0; j < dimA[1]; ++j) {
            printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
        }
        printf("\n\n");
    }

    printArray(A, dimA);
    return 0;
}
#包括
无效打印数组(int*A,int*dimA){
对于(int i=0;i

当数组被视为指针数组时,以下代码在main()中正确输出该数组,但当数组被视为1D整数数组时则不正确。但是,当我将同一数组作为指针传递给printary函数时,我可以将其视为一维整数数组,并且它可以工作。任何帮助都将不胜感激(我已经知道我可以使用指针数组,但我真的想知道问题出在哪里)。谢谢

根据C标准(6.3.2.1左值、数组和函数指示符)

3除非它是sizeof运算符或一元数的操作数& 运算符,或是用于初始化数组的字符串文本, 类型为“”的数组“”的表达式转换为 类型为“指向类型的指针”且指向初始值的表达式 数组对象的元素,并且不是左值。如果数组 对象具有寄存器存储类,行为未定义

因此,在第一个for循环中

for(i = 0; i < dimA[0]; ++i) {
    for(j = 0; j < dimA[1]; ++j) {
        printf("%3d", *(A[i] + j)); //This would work if the elements of A[] are pointers
    }
    printf("\n\n");
}
表达式
A[i*dimA[1]+j]
的类型为
int*
,并指向数组的
i*dimA[1]+j
“行”,即指向数组之外的行。所以这个循环没有意义

函数声明为like

void printArray(int *A, int* dimA);
叫做像

printArray(A, dimA);
类型为
int[2]
的第二个参数实际上转换为指向数组第一个元素的类型为
int*
的指针

对于第一个参数,它也被转换为指向其第一个元素的指针。数组的元素是什么?此二维数组的元素是
int[2]
类型的一维数组。因此,指向此类型对象的指针将具有类型
int(*)[2]

指针
int*
int(*)[2]
不兼容,因此编译器应发出诊断消息

函数的正确声明应该如下所示

void printArray(int ( *A )[2], int *dimA);

编译代码时会给出一个警告,提示正在发生的事情:

main.c:27:27: warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
            printf("%3d", A[i*dimA[1] + j]);//This would work if the elements of A[] are the rows of a 2D array mapped into a 1D array
                    ~~~   ^~~~~~~~~~~~~~~~
main.c:32:16: warning: incompatible pointer types passing 'int [2][2]' to parameter of type 'int *' [-Wincompatible-pointer-types]
    printArray(A, dimA);
               ^
main.c:3:22: note: passing argument to parameter 'A' here
void printArray(int *A, int* dimA) {
声明数组时:

int A[2][2] = {{1,2},{3,4}};
如您所述,这将存储为一个连续的内存块。在内存中,这相当于:

int A[4] = {1,2,3,4};
但是,无论何时根据类型查找/取消引用值,编译器都会隐式地为您做一些簿记。对于第二种情况:

int A[4] = {1,2,3,4};

A[0] = *(&A + 0) = 1
A[1] = *(&A + 1) = 2
...
非常简单,索引只是基址的偏移量。然而,对于第一种情况:

      y  x
int A[2][2] = {{1,2},{3,4}};
                     y   x
A[0][0] = *(&A + 2 * 0 + 0) = *(&A + 0) = 1
A[1][0] = *(&A + 2 * 1 + 0) = *(&A + 2) = 3
...
事情开始看起来有点混乱

首先要注意的是,由于该类型被声明为
int[2][2]
,因此必须对其取消引用两次。这就是第一个警告所抱怨的。因为它只被解引用一次,所以您的
int**
变成了
int*
,这与
int
不同

第二件要注意的事情是,由于类型被声明为多维数组,编译器将为您做一些簿记。由于数组在第一维度上被取消引用,因此要跨步到正确位置的第二维度的大小已经被考虑在内,因此您实际上得到的不是
col*j+i
,而是
col*(col*j+i)+i
,这不是您想要的

要获得所需效果,您可以:

  • A
    转换为
    int*
    。这就是调用
    printary
    函数时发生的情况,也是它工作的原因

  • 从最低维度访问阵列。不要说
    A[i*dimA[1]+j]
    ,而是说
    A[0][i*dimA[1]+j]
    。这将正确地取消对
    int
    的引用,并有效地绕过簿记

  • 在尝试将2D数组传递给函数时,我了解到不能使用动态分配的数组,因为编译器需要知道数组[][列]

    这是正确的,因为不能将任何数组传递给函数。您甚至不能用C语言表达这样的概念,尽管您可以编写在普通人看来是这样的代码。在几乎所有对数组求值的表达式出现的上下文中(包括函数调用表达式),数组值都被poin替换
          y  x
    int A[2][2] = {{1,2},{3,4}};
                         y   x
    A[0][0] = *(&A + 2 * 0 + 0) = *(&A + 0) = 1
    A[1][0] = *(&A + 2 * 1 + 0) = *(&A + 2) = 3
    ...
    
    // Dynamically allocating a 2D array of runtime-determined dimensions:
    unsigned rows = calculate_number_of_rows();
    unsigned columns = calculate_number_of_columns();
    int (*matrix)[columns] = malloc(rows * sizeof(*matrix));
    
    void do_something(unsigned rows, unsigned columns, int matrix[rows][columns]);
    
    void do_something(unsigned rows, unsigned columns, int matrix[][columns]);
    
    void do_something(unsigned rows, unsigned columns, int (*matrix)[columns]);