Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.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
C 指向固定大小数组的指针数组_C_Arrays - Fatal编程技术网

C 指向固定大小数组的指针数组

C 指向固定大小数组的指针数组,c,arrays,C,Arrays,我试图将两个固定大小的数组分配给指向它们的指针数组,但编译器警告我,我不明白为什么 int A[5][5]; int B[5][5]; int*** C = {&A, &B}; 此代码编译时带有以下警告: 警告:从不兼容的指针类型初始化[默认启用] 如果我运行代码,它将引发错误。但是,如果我动态地分配A和B,它就可以正常工作这是为什么?数组与C中的多维指针不同。在大多数情况下,数组的名称会被解释为包含它的缓冲区的地址,而不管您如何索引它。如果A被声明为inta[5][5],那么

我试图将两个固定大小的数组分配给指向它们的指针数组,但编译器警告我,我不明白为什么

int A[5][5];
int B[5][5];
int*** C = {&A, &B};
此代码编译时带有以下警告:

警告:从不兼容的指针类型初始化[默认启用]


如果我运行代码,它将引发错误。但是,如果我动态地分配
A
B
,它就可以正常工作这是为什么?

数组与C中的多维指针不同。在大多数情况下,数组的名称会被解释为包含它的缓冲区的地址,而不管您如何索引它。如果
A
被声明为
inta[5][5]
,那么
A
通常意味着第一个元素的地址,即它被有效地解释为
int*
(实际上是
int*[5]
),而不是
int**
。地址的计算恰好需要两个元素:
A[x][y]=A+x+5*y
。这是执行
a[x+5*y]
的一种便利,它不会将
a
提升到多维缓冲区

如果你想要C语言中的多维指针,你也可以这样做。语法将非常相似,但它需要更多的设置。有几种常见的方法

使用单个缓冲区:

int **A = malloc(5 * sizeof(int *));
A[0] = malloc(5 * 5 * sizeof(int));
int i;
for(i = 1; i < 5; i++) {
    A[i] = A[0] + 5 * i;
}
int**A=malloc(5*sizeof(int*);
A[0]=malloc(5*5*sizeof(int));
int i;
对于(i=1;i<5;i++){
A[i]=A[0]+5*i;
}
每行有一个单独的缓冲区:

int **A = malloc(5 * sizeof(int *));
int i;
for(i = 0; i < 5; i++) {
    A[i] = malloc(5 * sizeof(int));
}
int**A=malloc(5*sizeof(int*);
int i;
对于(i=0;i<5;i++){
A[i]=malloc(5*sizeof(int));
}

数组和指针的等价性让您感到困惑

当您声明像
A[5][5]
这样的数组时,因为您已经声明了两个维度,所以C将连续为25个对象分配内存。也就是说,内存将按如下方式分配:

A00, A01, ... A04, A10, A11, ..., A14, A20, ..., A24, ...
int A[5][5];
int B[5][5];
int (*C)[5][5] = &A;
int A[5][5];
int B[5][5];
int (*C[])[5][5] = {&A, &B};
结果对象
A
,是指向该内存块开始的指针。它的类型是
int*
,而不是
int**

如果需要指向数组的指针向量,则需要将变量声明为:

int   *A[5], *B[5];
这将给你:

A0, A1, A2, A3, A4
所有类型都是
int*
,您必须使用
malloc()
或其他方法填充


或者,您可以将
C
声明为
int**C

或者您应该声明第三个数组,如

int A[5][5];
int B[5][5];
int ( *C[] )[N][N] = { &A, &B };
这是一个指向二维数组的指针数组

比如说

#include <stdio.h>

#define N   5

void output( int ( *a )[N][N] )
{
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < N; j++ ) printf( "%2d ", ( *a )[i][j] );
        printf( "\n" );
    }
}

int main( void )
{
    int A[N][N] =
    {
        {  1,  2,  3,  4,  5 },
        {  6,  7,  8,  9, 10 },
        { 11, 12, 13, 14, 15 },
        { 16, 17, 18, 19, 20 },
        { 21, 22, 23, 24, 25 }
    };
    int B[N][N] =
    {
        { 25, 24, 23, 22, 21 },
        { 20, 19, 18, 17, 16 },
        { 15, 14, 13, 12, 11 },
        { 10,  9,  8,  7,  6 },
        {  5,  4,  3,  2,  1 }
    };

/*
    typedef int ( *T )[N][N];
    T C[] = { &A, &B };
*/

    int ( *C[] )[N][N] = { &A, &B };

    output( C[0] );
    printf( "\n" );

    output( C[1] );
    printf( "\n" );
}        
#include <stdio.h>

#define N   5

void output( int ( *a )[N] )
{
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < N; j++ ) printf( "%2d ", a[i][j] );
        printf( "\n" );
    }
}

int main( void )
{
    int A[N][N] =
    {
        {  1,  2,  3,  4,  5 },
        {  6,  7,  8,  9, 10 },
        { 11, 12, 13, 14, 15 },
        { 16, 17, 18, 19, 20 },
        { 21, 22, 23, 24, 25 }
    };
    int B[N][N] =
    {
        { 25, 24, 23, 22, 21 },
        { 20, 19, 18, 17, 16 },
        { 15, 14, 13, 12, 11 },
        { 10,  9,  8,  7,  6 },
        {  5,  4,  3,  2,  1 }
    };

/*
    typedef int ( *T )[N];
    T C[] = { A, B };
*/

    int ( *C[] )[N] = { A, B };

    output( C[0] );
    printf( "\n" );

    output( C[1] );
    printf( "\n" );
}        
或者

int A[5][5];
int B[5][5];
int ( *C[] )[N] = { A, B };
这是指向二维数组的第一个元素的指针数组

比如说

#include <stdio.h>

#define N   5

void output( int ( *a )[N][N] )
{
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < N; j++ ) printf( "%2d ", ( *a )[i][j] );
        printf( "\n" );
    }
}

int main( void )
{
    int A[N][N] =
    {
        {  1,  2,  3,  4,  5 },
        {  6,  7,  8,  9, 10 },
        { 11, 12, 13, 14, 15 },
        { 16, 17, 18, 19, 20 },
        { 21, 22, 23, 24, 25 }
    };
    int B[N][N] =
    {
        { 25, 24, 23, 22, 21 },
        { 20, 19, 18, 17, 16 },
        { 15, 14, 13, 12, 11 },
        { 10,  9,  8,  7,  6 },
        {  5,  4,  3,  2,  1 }
    };

/*
    typedef int ( *T )[N][N];
    T C[] = { &A, &B };
*/

    int ( *C[] )[N][N] = { &A, &B };

    output( C[0] );
    printf( "\n" );

    output( C[1] );
    printf( "\n" );
}        
#include <stdio.h>

#define N   5

void output( int ( *a )[N] )
{
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < N; j++ ) printf( "%2d ", a[i][j] );
        printf( "\n" );
    }
}

int main( void )
{
    int A[N][N] =
    {
        {  1,  2,  3,  4,  5 },
        {  6,  7,  8,  9, 10 },
        { 11, 12, 13, 14, 15 },
        { 16, 17, 18, 19, 20 },
        { 21, 22, 23, 24, 25 }
    };
    int B[N][N] =
    {
        { 25, 24, 23, 22, 21 },
        { 20, 19, 18, 17, 16 },
        { 15, 14, 13, 12, 11 },
        { 10,  9,  8,  7,  6 },
        {  5,  4,  3,  2,  1 }
    };

/*
    typedef int ( *T )[N];
    T C[] = { A, B };
*/

    int ( *C[] )[N] = { A, B };

    output( C[0] );
    printf( "\n" );

    output( C[1] );
    printf( "\n" );
}        
这取决于您将如何使用第三个阵列

使用typedefs(在演示程序中如注释所示)简化数组的定义

至于这个声明,

int*** C = {&A, &B};
int A[5][5];
然后在左侧声明了一个类型为
int***
的指针,它是一个标量对象,而在右侧声明了一个具有不同类型
int(*)[N][N]
的初始化器列表


因此编译器会发出一条消息。

尽管数组和指针密切相关,但它们根本不是一回事。人们有时会对此感到困惑,因为在大多数上下文中,数组值会衰减为指针,而且数组表示法可以在函数原型中用于声明实际上是指针的参数。此外,许多人认为的数组索引表示法实际上执行指针算术和解引用的组合,因此它对指针值和数组值同样有效(因为数组值会衰减为指针)

根据声明

int*** C = {&A, &B};
int A[5][5];
变量
A
指定一个由五个
int
数组组成的数组。它在衰减的地方衰减为
int(*)[5]
类型的指针,即指向5
int
数组的指针。另一方面,指向整个多维数组的指针具有类型
int(*)[5][5]
(指向5个数组的数组的指针
int
),这与
int***
(指向
int
)的指针完全不同。如果要声明指向如下多维数组的指针,可以这样做:

A00, A01, ... A04, A10, A11, ..., A14, A20, ..., A24, ...
int A[5][5];
int B[5][5];
int (*C)[5][5] = &A;
int A[5][5];
int B[5][5];
int (*C[])[5][5] = {&A, &B};
如果要声明此类指针的数组,则可以执行以下操作:

int (*D[2])[5][5] = { &A, &B };

增加:

这些区别以各种方式发挥作用,其中一些更重要的是数组值不会衰减为指针的上下文,以及与这些值相关的上下文。其中最重要的一个是当值是
sizeof
运算符的操作数时。鉴于上述声明,以下所有关系表达式的计算结果均为1(true):

此外,这些关系表达式的计算结果可能为1,但不能保证:

sizeof(C)       == sizeof(void *)
sizeof(D)       == 2 * sizeof(void *)

这是数组索引工作原理的基础,也是理解何时分配内存的关键。

如果您想要符合
a
B
现有声明的
C
,您需要这样做:

A00, A01, ... A04, A10, A11, ..., A14, A20, ..., A24, ...
int A[5][5];
int B[5][5];
int (*C)[5][5] = &A;
int A[5][5];
int B[5][5];
int (*C[])[5][5] = {&A, &B};
C
的类型被解读为“
C
是指向
int[5][5]
数组的指针数组”。由于无法分配整个数组,因此需要分配指向该数组的指针

通过此声明,
(*C[0])[1][2]
正在访问与
A[1][2]
相同的内存位置

如果您想要更简洁的语法,如
C[0][1][2]
,则需要执行其他人所述的操作,并动态分配内存:

int **A;
int **B;
// allocate memory for A and each A[i]
// allocate memory for B and each B[i]
int **C[] = {A, B};
您也可以使用莫斯科Vlad建议的语法:

int A[5][5];
int B[5][5];
int (*C[])[5] = {A, B};
C
的声明被理解为“
C
是指向
int[5]
数组的指针数组”。在这种情况下,
C
的每个数组元素的类型为
int(*)[5]
,数组的类型为
int[5][
int x = (*C[0])[i][j]; // x = A[i][j]
int y = (*C[1])[i][j]; // y = B[i][j]
int (*C[2])[5] = { A, B };
*a == *(a + 0) == a[0]
*C[i] == *(C[i] + 0) == C[i][0]
C[0] == A                      // int [5][5], decays to int (*)[5]
C[1] == B                      // int [5][5], decays to int (*)[5]

*C[0] == C[0][0] == A[0]       // int [5], decays to int *
*C[1] == C[1][0] == B[0]       // int [5], decays to int *

C[0][i] == A[i]                // int [5], decays to int *
C[1][i] == B[i]                // int [5], decays to int *

C[0][i][j] == A[i][j]          // int
C[1][i][j] == B[i][j]          // int
int a1[] = {1,2,3,4,5};
int *p1 = a1;            // Beginners intuition: If 'p1' is a pointer and 'a1' can be assigned
                         // to it then arrays are pointers and pointers are arrays.

p1[1] = 0;               // Oh! I was right
a1[3] = 0;               // Bruce Wayne is the Batman! Yeah.
int a2[][5] = {{0}};
int **p2 = a2;
int a3[][5][10] = {{{0}}};
int ***p3 = a3;             // "?"
int a1[] = {1,2,3,4,5};
int *p1 = a1;
int a2[][5] = {{0}};
int **p2 = a2;
int (*p2)[5] = a2;
int a3[][5][10] = {{{0}}};
int ***p3 = a3;
int (*p3)[5][10] = a3;
int A[5][5];
int B[5][5];
int*** C = {&A, &B};
int (*C[2])[5][5] = {&A, &B};
  int*** C = &A;
#define SIZE 5

typedef int  OneD[SIZE]; // OneD is a one-dimensional array of ints
typedef OneD TwoD[SIZE]; // TwoD is a one-dimensional array of OneD's
                         // So it's a two-dimensional array of ints!

TwoD a;
TwoD b;

TwoD *c[] = { &a, &b, 0 }; // c is a one-dimensional array of pointers to TwoD's
                           // That does NOT make it a three-dimensional array!

int main() {
    for (int i = 0; c[i] != 0; ++i) { // Test contents of c to not go too far!
        for (int j = 0; j < SIZE; ++j) {
            for (int k = 0; k < SIZE; ++k) {
//              c[i][j][k] = 0;    // Error! This proves it's not a 3D array!
                (*c[i])[j][k] = 0; // You need to dereference the entry in c first
            } // for
        } // for
    } // for
    return 0;
} // main()