C 以这种方式声明和初始化指针需要什么:int(*p)[n]

C 以这种方式声明和初始化指针需要什么:int(*p)[n],c,pointers,C,Pointers,我正在学习指针算法,有一个例子是关于精确地利用指针处理二维数组的列。为了做到这一点,代码向我展示了一个新的指针声明,下面是代码片段: inta[NUM_ROWS][NUM_COLS],(*p[NUM_COLS],i; ... for(p=&a[0];p

我正在学习指针算法,有一个例子是关于精确地利用指针处理二维数组的列。为了做到这一点,代码向我展示了一个新的指针声明,下面是代码片段:

inta[NUM_ROWS][NUM_COLS],(*p[NUM_COLS],i;
...
for(p=&a[0];p<&a[NUM_ROWS];p++)
(*p)[i]=0;
这个指针((*p)[NUM_COLS])的行为对我来说很奇怪,因为我刚刚了解到,递增指针的行为就像递增数组下标一样,允许您处理该指针指向的数组。所以这不是一个常规指针

大小(以字节为单位)是相同的,但是如果在for循环中赋值时它代表整行,那么该声明涉及到什么呢

 int (*p)[NUM_COLS];
本质上定义了一个指针
p
,它是指向带有
NUM\u COLS
元素的
int
s数组的指针

因此,它可以用作

 int arr[NUM_COLS] = {0};
 p = &arr;
它与所有其他指针具有相同的属性

  • 指针的类型是
    int(*)[NUM\u COLS]
  • 此指针指向的实例的大小是
    int[NUM\u COLS]
    ,即
    int
    的大小乘以
    NUM\u COLS
    • 类似于

       int (*p)[NUM_COLS];
      
      本质上定义了一个指针
      p
      ,它是指向带有
      NUM\u COLS
      元素的
      int
      s数组的指针

      因此,它可以用作

       int arr[NUM_COLS] = {0};
       p = &arr;
      
      它与所有其他指针具有相同的属性

      • 指针的类型是
        int(*)[NUM\u COLS]
      • 此指针指向的实例的大小是
        int[NUM\u COLS]
        ,即
        int
        的大小乘以
        NUM\u COLS

        • 正如@SouravHhosh所写,它定义了指向整数数组的指针。任何指针算法都是数组大小的乘积


          正如@SouravHhosh所写,它定义了指向整数数组的指针。任何指针算法都是数组大小的乘积

          p
          声明为指向
          T
          的N元素数组的指针。您主要在以下上下文中看到它们:

          • 由于高维数组表达式“衰减”为指针表达式
          • 为高维数组分配内存时

          作为前者的一个例子,考虑下面的代码:

          void foo( int (*p)[3] )
          {
            // do something with p
          }
          
          int main( void )
          {
            int arr[2][3];
          
            foo( arr );
          }
          
          除非它是
          sizeof
          或一元
          &
          运算符的操作数,或者是用于初始化声明中字符数组的字符串文字,否则“T的N元素数组”类型的表达式将被转换(“衰减”)为“指向
          T
          的指针”类型的表达式,表达式的值将是数组第一个元素的地址

          当您将表达式
          arr
          作为参数传递给
          foo
          时,它将从类型“int的3元素数组的2元素数组”(
          int[2][3]
          )转换为“指向int的3元素数组的指针”(
          int(*)[3]
          )。因此,函数实际上接收的是指针值,而不是数组

          由于指向数组的指针语法有点难看和麻烦,您可以交替使用

          void foo( int p[][3] ) { ... }
          
          用于声明,但仅在函数参数声明中

          作为后者的一个示例,如果要动态声明二维数组,可以执行以下操作:

          int (*p)[3] = malloc( 2 * sizeof *p );
          
          它为
          int
          的2x3数组分配空间,并将指向该空间的指针分配给
          p
          。表达式
          p
          的类型是“指向
          int
          的三元素数组的指针”,因此
          *p
          的类型是“int的三元素数组”

          请记住,数组下标操作
          a[i]
          定义为
          *(a+i)
          ——给定起始地址
          a
          ,从该地址偏移
          i
          元素(而非字节),并取消对结果1的引用。因此,可以得出如下结论:

          *p == *(p + 0) == p[0]
          
          意义

          (*p)[i] == (*(p + 0))[i] == (p[0])[i] == p[0][i]
          
          因此,在为
          p
          分配内存后,您可以像任何2D数组一样对其进行索引:

          for ( size_t i = 0; i < 2; i++ )
            for ( size_t j = 0; j < 3; j++ )
              p[i][j] = some_value;
          
          由于下标
          []
          和函数调用
          ()
          运算符的优先级高于一元
          *
          *a[i]
          将解析为
          *(a[i])
          *f()
          将解析为
          *(f())
          。如果要将
          a
          视为指向数组的指针,将
          f
          视为指向函数的指针,则必须使用括号-
          (*a)[i]
          (*f)(
          )将
          *
          运算符与标识符显式分组


        • C源于早期的语言B。在B中,数组有一个指向第一个元素的显式指针,该指针绑定到数组变量。因此,在B中,
          *(a+i)
          语法是有意义的,因为
          a
          始终是一个指针。当Ritchie设计C时,他不想在数组中保留显式指针,因此他引入了一条规则,即数组表达式“衰减”到指针,除非在特定情况下。

          p
          声明为指向
          T
          的N元素数组的指针。您主要在以下上下文中看到它们:

          • 由于高维数组表达式“衰减”为指针表达式
          • 为高维数组分配内存时

          作为前者的一个例子,考虑下面的代码:

          void foo( int (*p)[3] )
          {
            // do something with p
          }
          
          int main( void )
          {
            int arr[2][3];
          
            foo( arr );
          }
          
          除非它是
          sizeof
          或一元
          &
          运算符的操作数,或者是用于初始化声明中字符数组的字符串文字,否则“T的N元素数组”类型的表达式将被转换(“衰减”)为“指向
          T
          的指针”类型的表达式,表达式的值将是地址o