Arrays 理解高级指针算术语法有困难

Arrays 理解高级指针算术语法有困难,arrays,c,pointers,pointer-arithmetic,Arrays,C,Pointers,Pointer Arithmetic,假设我们获得了下一个设置: int (*p)[9]; 它是一个常规指针,还是指向9*sizeof(int)大的内存块的某种特殊指针 我如何引用这种语法 假设我有一个给定的矩阵: 例如,如果我们增加p,指针算术将如何工作 我该如何投出这样的类型 下一个代码的输出是25,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是21 你应该读书 int (*p)[9]; 作为指向int[9](9个整数)数组的指针。它是一个常规指针,类型为int[9] 指针算法的工作原理

假设我们获得了下一个设置:

int (*p)[9];
  • 它是一个常规指针,还是指向
    9*sizeof(int)
    大的内存块的某种特殊指针

  • 我如何引用这种语法

  • 假设我有一个给定的矩阵:

  • 例如,如果我们增加p,指针算术将如何工作

  • 我该如何投出这样的类型

  • 下一个代码的输出是
    25
    ,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是
    21

  • 你应该读书

     int (*p)[9];
    
    作为指向
    int[9]
    (9个整数)数组的指针。它是一个常规指针,类型为
    int[9]

    指针算法的工作原理与其他指针相同,取决于指针的大小,即
    sizeof(int[9])

    也就是说,对于另一个问题,如果有疑问,请检查数据类型

    int main()
    {
        int a[5] = {1,2,3,4,5};
        int *ptr = (int*)(&a+1);               
        printf("%d %d", *(a+1), *(ptr-1));
        return 0;
    }
    
    &a
    是if类型
    int(*)[5]
    ,因此指针算法将遵循该类型
    &a+1
    指向整个数组后的第一个元素


    因此,自然地,
    ptr
    指向最后一个元素地址之后的一个。因此,通过说
    *(ptr-1)
    可以得到最后一个元素的值,即
    5

    可以将&a看作是指向sizeof(int)的“项”的指针*5所以当你加1的时候,它会把你发送到数组后面的下一个元素,这个元素会被提升20字节的偏移量,所以你做-1,然后把它转换成int,得到数组的最后一个变量

  • 它是一个常规指针,还是指向
    9*sizeof(int)
    大的内存块的某种特殊指针
  • 它是指向类型为
    int[9]
    的数组的指针。这实际上是
    9*sizeof(int)
    bytes大

  • 我如何引用这种语法
  • 它们被称为数组指针或数组指针。您可以将其视为“指向整个数组的指针”,不要与“指向数组中第一个元素的指针”混淆

  • 假设我有一个给定的矩阵:
  • 例如,如果我们增加p,指针算术将如何工作

    与任何指针类型一样,
    p
    被分配给
    int[200][9]
    数组中第一个元素的点。第一个元素是数组
    int[9]
    ,指向这样一个数组的指针是
    int(*)[9]

  • 我该如何投出这样的类型
  • 与任何类型一样,尽管它们与指向不同大小或类型数组的指针不兼容,也与
    int*
    不兼容

  • 下一个代码的输出是
    25
    ,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是
    21
  • 通常,每当在表达式中使用时,数组都会衰减为指向第一个元素的指针。这就是这里发生的
    *(a+1)
    a
    衰减为
    int*
    ,指针算术+1让我们指向第二个元素

    此数组衰减规则的极少数例外之一是运算符的
    &
    地址的操作数。因此,在表达式
    &a
    中,数组
    a
    不会衰减。相反,我们以指向数组
    int(*)[5]
    的指针的形式获取它的地址

    &a+1
    然后给出指向数组的指针的指针算法。与任何指针算法一样,
    1
    表示指向项目的一个指针的大小,在本例中为
    sizeof(int[5])
    。因此,我们最终指向原始数组中的一个超出边界-这很好,我们可以指向那里,只要我们不去引用指针


    由于
    (int*)
    int(*)[5]
    不兼容,因此
    (int*)
    的演员阵容非常可疑且不好。但是,C允许我们进行任意和可疑的转换,只要我们不通过错误的类型取消引用数据。但是
    *(ptr-1)
    然后转到数组的最后一项并取消引用它。这滥用了C指针/类型系统中的一条特殊规则,该规则允许我们通过不同的指针类型访问(“左值访问”)实际对象,只要存储在该内存位置的内容实际上是用于访问的类型。由于实际存储在物理内存地址上的
    5
    是一个
    int
    ,因此它可以工作。

    以下是指针声明的基本规则:

    T *p;              // p is a pointer to T
    T *ap[N];          // ap is an array of pointers to T
    T *fp();           // fp is a function returning a pointer to T
    
    T (*pa)[N];        // pa is a pointer to an array of T
    T (*pf)();         // pf is a function returning a pointer to T
    
    T * const p;       // p is a const pointer to T - *p is writable, but p is not
    const T *p;        // p is a non-const pointer to const T - p is writable, but *p is not
    T const *p;        // same as above
    const T * const p; // p is a const pointer to const T - neither p nor *p are writable
    T const * const p; // same as above
    
    要阅读一个毛茸茸的声明,请找到最左边的标识符,并按照上面的规则解决问题,将它们递归地应用于任何函数参数。例如,以下是C标准库中
    信号
    函数的声明如何分解:

           signal                                       -- signal
           signal(                          )           -- is a function taking
           signal(    sig                   )           --   parameter sig
           signal(int sig                   )           --   is an int
           signal(int sig,        func      )           --   parameter func
           signal(int sig,      (*func)     )           --   is a pointer to
           signal(int sig,      (*func)(   ))           --     a function taking
           signal(int sig,      (*func)(   ))           --       unnamed parameter
           signal(int sig,      (*func)(int))           --       is an int
           signal(int sig, void (*func)(int))           --     returning void
         (*signal(int sig, void (*func)(int)))          -- returning a pointer to
         (*signal(int sig, void (*func)(int)))(   )     --   a function taking
         (*signal(int sig, void (*func)(int)))(   )     --     unnamed parameter
         (*signal(int sig, void (*func)(int)))(int)     --     is an int
    void (*signal(int sig, void (*func)(int)))(int);    --   returning void
    
    您可以通过替换构建更复杂的指针类型。例如,如果要声明一个返回数组指针的函数,可以将其构建为

    T     a     [N];    // a is an array of T
          |
      +---+----+
      |        |
    T (*  pa   )[N];    // pa is a pointer to an array of T 
          |
         ++--+
         |   |
    T (* fpa() )[N];    // fpa is a function returning a pointer to an array of T
    
     T *     p           ;       // p is a pointer to T
             |
             +----------+
             |          |
     T *     fp        ();       // fp is a function returning pointer to T
             |
         +---+-----+
         |         |
     T * (*  pf    )   ();       // pf is a pointer to a function returning pointer to T
             |
            ++---+
            |    |
     T * (* apf[N] )   ();       // apf is an array of pointers to functions returning pointer to T
    
    如果需要指向返回指向
    T
    的指针的函数的指针数组,则可以将其构建为

    T     a     [N];    // a is an array of T
          |
      +---+----+
      |        |
    T (*  pa   )[N];    // pa is a pointer to an array of T 
          |
         ++--+
         |   |
    T (* fpa() )[N];    // fpa is a function returning a pointer to an array of T
    
     T *     p           ;       // p is a pointer to T
             |
             +----------+
             |          |
     T *     fp        ();       // fp is a function returning pointer to T
             |
         +---+-----+
         |         |
     T * (*  pf    )   ();       // pf is a pointer to a function returning pointer to T
             |
            ++---+
            |    |
     T * (* apf[N] )   ();       // apf is an array of pointers to functions returning pointer to T
    

    指针运算是根据对象而不是字节来完成的。如果
    p
    存储类型为
    T
    的对象的地址,则
    p+1
    生成该类型的下一个对象的地址。如果
    pa
    存储
    T
    的N元素数组的地址,则
    pa+1
    产生
    T
    的下一个N元素数组的地址

    在代码中

    int main()
    {
        int a[5] = {1,2,3,4,5};
        int *ptr = (int*)(&a+1);
        printf("%d %d", *(a+1), *(ptr-1));
        return 0;
    }
    
    表达式
    &a+1
    产生
    a
    后面的
    int
    的下一个5元素数组的地址。此地址值被强制转换为
    int*
    ,因此它被视为
    a
    最后一个元素之后的第一个
    int
    的地址。图表可能有助于:

     int[5]        int           int *
     ------        ---           -----
            +---+        +---+        +---+
         a: |   |  a[0]: | 1 |   ptr: |   |
            + - +        +---+        +---+
            |   |  a[1]: | 2 |          |
            + - +        +---+          |
            |   |  a[2]: | 3 |          |
            + - +        +---+          |
            |   |  a[3]: | 4 |          |
            + - +        +---+          |
            |   |  a[4]: | 5 |          |
            +---+        +---+          |
     a + 1: |   |        | ? | <--------+
            + - +        +---+
            |   |        | ? |
            + - +        +---+
             ...          ...
    
    在表达式和声明中,后缀运算符
    []
    ()
    的优先级都高于un
     int[5]        int           int *
     ------        ---           -----
            +---+        +---+        +---+
         a: |   |  a[0]: | 1 |   ptr: |   |
            + - +        +---+        +---+
            |   |  a[1]: | 2 |          |
            + - +        +---+          |
            |   |  a[2]: | 3 |          |
            + - +        +---+          |
            |   |  a[3]: | 4 |          |
            + - +        +---+          |
            |   |  a[4]: | 5 |          |
            +---+        +---+          |
     a + 1: |   |        | ? | <--------+
            + - +        +---+
            |   |        | ? |
            + - +        +---+
             ...          ...
    
    printf( "indexed value = %d\n", (*pa)[i] );
    
    int (*pa)[N];
    
    Expression        Type
    ----------        ----
            pa        int (*)[N];
           *pa        int [N];
      (*pa)[i]        int
    
    *p == *(p + 0) == p[0]
    
    int mat[200][9];
    int (*p)[9] = mat;
    
    (*p)[j] == (*(p + 0))[j] == p[0][j]