【问题标题】:Pointer variable pointing to a one dimensional array or two dimensional array?指向一维数组还是二维数组的指针变量?
【发布时间】:2021-10-23 03:22:09
【问题描述】:

我有以下代码用于一维数组:

#include <stdio.h>
int main()
{
    static int b[4] = {11, 12, 13, 14};
    int (*p)[4];

    p = b;
    printf("%d \n", *(p + 1));

    return 0;
}

即使我认为“b(数组名)”是一个指向一维数组的指针,我还是得到了一个编译错误

'=': cannot convert from 'int [4]' to 'int (*)[4]'

但是,如果我将 b 数组更改为二维数组“a(数组名称)”,则一切正常。这是否意味着,在 "int (*p)[4];" 的使用中,"*p" 必须如下表示 a[]:

static int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int (*p)[4];
p = a;

因此,"int (*p)[4]" 仅在二维数组的行数上提供了灵活性。

对此问题有何见解?

【问题讨论】:

  • p = b; -> p = &amp;b; 因为p 是一个指向数组的指针。就像int a; int *p = &amp;a;。在第二个二维数组示例中使用p = ap 指向a 中的第一个一维数组。
  • 我认为 b 本身就是一个地址,因为 b 是一个一维数组名。因此,p = b 而不是 p = &b。这里有什么问题?
  • @Cindy 不,b 是一个 数组。正如我的回答中提到的,数组可以衰减指向指针(指向它们的第一个元素),但它们本身不是指针(地址)。
  • @Cindy 和b 在您的示例中可以衰减为int *,但它仍然与int (*)[4] 不同。 &amp;bint (*)[4] 类型,所以它可以工作。 b(衰减为指针)和&amp;b具有相同的地址但仍然是不同的类型。
  • (*p)[4] .. only provides flexibility in the number of rows -- 是的。 C 数组是行优先的(匹配存储布局)。要计算行的地址,编译器需要列数;如果想要列灵活,需要去掉[4],自己计算行;例如:int *p = b; p[2*4+1] = 3; 将分配 row=2,col=1 值 3。或者如果您想将 b 视为 3 宽数组:p[2*3+1] = 3; 将分配 row=2,col=1 值 3 . 将繁琐的类型放入定义中可能会有所帮助,既可以澄清事情,也可以防止它看起来像 c++:.

标签: arrays c pointers multidimensional-array implicit-conversion


【解决方案1】:

数组自然衰减指向它们的第一个元素的指针,具体取决于上下文。也就是说,当这种衰减发生时,普通的b&amp;b[0] 相同,它们的类型为int *。由于pb(或&amp;b[0])的类型不同,你会得到一个错误。

至于a,这里也一样,它衰减为指向其第一个元素的指针,即a&amp;a[0]相同。 但是因为a[0] 是一个4 元素的数组,那么&amp;a[0] 是一个指向四个元素的数组的指针,即int (*)[4]。这也是第二个例子中p的类型。

【讨论】:

  • 所以,普通 b 的类型为 int*。如果 p 和 b 有不同的类型,那么 p 的类型是什么?
  • @Cindy 没有普通的b 确实具有int[4] 类型,但它可以衰减int *。并且p 的类型明确声明为int (*)[4],这与int * 非常不同。
  • 再次,p的类型是什么?是 int* 还是 a[] 等价的?
  • @Cindy p 被声明为int (*p)[4];,这意味着它的类型为int (*)[4]
  • 所以,编译器错误实际上是说我不能在 p(int* 类型)和 b 的原始类型(int[4] 类型)之间做等号,即使 b 的类型可以衰减到整数*?
【解决方案2】:

如果你有某种类型的对象 T 喜欢

T a;

然后声明一个指向对象的指针看起来像

T *p = &a;

您的数组b 的类型为int[4]。所以指向数组的指针看起来像

int ( *p )[4] = &b;

使用你应该写的指针输出数组的第二个元素

printf("%d \n", *( *p + 1 ) );

因此您的编译器发出了错误消息

无法从 'int [4]' 转换为 'int (*)[4]

因为至少不用写

int ( *p )[4] = &b;

你写的

int ( *p )[4] = b;

另一方面,在表达式中使用的数组指示符具有罕见的异常,它被隐式转换为指向其第一个元素的指针。例如在这个声明中

int *p = b;

用作初始化器的数组b 被转换为指向其第一个元素的指针。上面的声明等价于

int *p = &b[0];

还是一样

int *p = b + 0;

使用这个指针可以调用函数printflike

printf("%d \n", *(p + 1));

如果你有一个二维数组

int a[3][4];

然后在表达式中使用它被转换为指向它的第一个元素的指针,该元素的类型为int[4]。所以你可以写

int ( *p )[4] = a;

如果要将指向整个数组的指针声明为单个对象,可以编写

int ( *p )[3][4] = &a;

【讨论】:

    【解决方案3】:

    指向一维数组的指针,

    不,它直接指向第一个元素。同样:

    int *p = b;
    

    够了。

    4 这个数字实际上并不是任何类型的一部分;

     static int b[] = {11, 12, 13, 14};
    

    它可以在声明中省略。 (因为它是 first 维度,除非您将其设为 2D)


    这个(来自 AA)

    int (*p)[4] = &b;
    ...
    printf("%d \n", *( *p + 1 ) );
    

    只是一个混淆和改写的版本:

    int (*p)[] = &b;
    ...
    printf("%d \n", (*p)[1] );
    

    这会将b 替换为(*p),通常不是您想要的。

    【讨论】:

    • 这里的数字 4 并不是任何类型的一部分; 可以肯定的是。 int (*)[4] 不能指向长度为 5 的 int 数组。
    • 这里的“这里”是指一维案例。 gcc 说int *,OP 在消息中有int [4]。但是int (*)[4] 是二维的——4 是类型的一部分。
    • 数组不指向它的第一个元素。当它在表达式中使用而不是作为sizeof 的操作数、作为一元&amp; 的操作数或作为用于初始化一个数组。理解处理数组的这个单独步骤对于理解 C 语义很重要。数组不应被视为指针。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    相关资源
    最近更新 更多