【问题标题】:What is the difference between pointer to array and pointer to pointer?指向数组的指针和指向指针的指针有什么区别?
【发布时间】:2014-12-03 12:06:11
【问题描述】:

我是编程和学习数组指针的新手。我现在有点困惑。看看下面的程序:

#include <stdio.h>
int fun();
int main()
{
    int num[3][3]={23,32,478,55,0,56,25,13, 80};
    printf("%d\n",*(*(num+0)+1));
    fun(num);
    printf("%d\n", *(*(num+0)+1));
    *(*(num+0)+0)=23;
    printf("%d\n",*(*(num+0)));
    return 0;
}
int fun(*p)  // Compilation error
{
    *(p+0)=0;
    return 0;
}

这是我老师笔记中写的程序。在main() 函数中,在printf() 函数中,取消引用运算符被使用了两次,因为num 是指向数组的指针,所以第一次取消引用运算符将​​给出指向int 的指针,然后第二个将给出值指针指向的那个。

我的问题是,当我将数组名称作为参数传递给函数fun() 时,为什么要使用*p;为什么**p 不是num 是指向数组的指针?

第二件事为什么使用*(p+0) 来改变数组的第零个元素的值;为什么不 *(*(p+0)+0)=0 就像 main() 函数中的 *(*(num+0)+0) 用于更改第零个元素的值?

整个事情让我很困惑,但无论如何我都必须理解它。我对此进行了搜索,发现指向数组的指针和指向指针的指针之间存在差异,但我不太了解。

【问题讨论】:

  • 多维数组是flat。以消除有关它们如何实施的困惑。
  • 你会从这个问题的答案中得到答案stackoverflow.com/questions/14100240/…
  • 你不会得到编译错误,原型/函数不匹配吗?为什么你问 +0+0 而不是 +0?为什么要在代码中添加静态 0?
  • 我没有收到任何编译错误。
  • int fun(*p) { ... } 不应该编译。您使用的是什么编译器(带有什么标志)?

标签: c pointers function-pointers memory-address pointer-arithmetic


【解决方案1】:

诀窍是数组指针-衰减:当您提到数组的名称时,几乎在所有上下文中,它都会衰减为指向其第一个元素的指针。那就是num 只是一个由三个整数组成的三个数组的数组(type = int [3][3])。

让我们分析表达式*(*(num + 1) + 2)

当您在表达式 *(num + 1) 中提及 num 时,它会衰减为指向其第一个元素的指针,该元素是三个整数的数组(类型 = int (*)[3])。在此指针上执行指针运算,并将指针指向的任何大小添加到指针的值中。在这种情况下,它是三个整数数组的大小(在许多机器上是 12 个字节)。取消引用指针后,您将得到int [3] 的类型。

然而,这个解引用只涉及类型,因为在解引用操作之后,我们看到表达式*(/*expression of type int[3]*/ + 2),所以内部表达式衰减回指向第一个数组元素的指针。此指针包含与num + 1 产生的指针相同的地址,但它具有不同的类型:int*。因此,对该指针的指针算术将指针推进两个整数(8 字节)。所以表达式*(*(num + 1) + 2) 产生了偏移量为12 + 8 = 20 字节的整数元素,这是数组中的第六个整数。


关于您对fun() 的调用的问题,该调用实际上已中断,并且仅因为您的老师未在fun() 的前向声明中包含参数而起作用。代码

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    fun(num);
}

会由于错误的指针类型而产生编译时错误。您老师的代码“有效”,因为指向num 中第一个数组的指针与指向num 中第一个数组的第一个元素的指针相同,即。 e.他的代码相当于

int fun(int* arg);

int main() {
    int num[3][3] = ...;
    ...
    //both calls are equivalent
    fun(num[0]);
    fun(&num[0][0]);
}

编译不会出错。

【讨论】:

    【解决方案2】:

    这个例子展示了一个矩阵,指向数组第一个整数的指针,以及指向指针的指针

    #include<stdio.h>
    int fun(int (*p)[3]);  /* p is pointer to array of 3 ints */
    int main()
    {
        /* matrix */
        int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
        /* three pointers to first integer of array */
        int *pnum[3] = {num[0], num[1], num[2]};
        /* pointer to pointer */
        int **ppnum = pnum;
        printf("%d\n", *(*(num+1)+2));
        fun(num);
        printf("%d\n", *(*(num+1)+2));
        pnum[1][2] = 2;
        printf("%d\n", *(*(num+1)+2));
        ppnum[1][2] = 3;
        printf("%d\n", *(*(num+1)+2));
        return 0;
    }
    int fun(int (*p)[3])
    {
        p[1][2]=1;
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      您实际上不需要任何指针来在这里打印任何内容。

      你的int num[3][3]实际上是一个由三个元素组成的数组,每个元素都是一个由三个整数组成的数组。因此num[0][0] = 23num[1][1] = 0 等等。因此你可以说printf("%d", num[0][0]) 来打印数组的第一个元素。

      【讨论】:

      • 我知道我可以做到,但我想用指针知道它,我的问题是为什么 *(p+0) 用于初始化 0 为什么不 *(*(p+0)+ 0) ?As num 是指向数组的指针
      • 如果你必须使用指针,那么就使用pp 已知是函数定义中的指针,所以你可以说 p = 0; 你不需要其他任何东西。试试看。
      【解决方案4】:

      指向变量的指针:

      指针是存储地址的变量(变量的)。每个人都知道这一点。


      指向数组的指针:

      数组是一个变量,它具有一组相同对象的起点(地址)。

      而指针是一个变量,它存储了一个数组的起点(地址)。

      例如:

      int iArray[3];
      

      iArray 是一个变量,其地址值为三个整数,内存是静态分配的。并且下面的语法是用典型的编程语言提供的。

      // iArray[0] = *(iArray+0);
      // iArray[1] = *(iArray+1);
      // iArray[2] = *(iArray+2);
      

      在上面的 iArray 是一个变量,通过它我们可以使用上面提到的任何语法访问三个整数变量。

      *(iArray+0); // 这里 iArray+0 是第一个对象的地址。和 * 是取消引用 *(iArray+1); // 这里 iArray+1 是第二个对象的地址。和 * 是取消引用

      这么简单,有什么好混淆的。


      以下几行供您理解

      int iArray1[3];
      int iArray2[3][3];
      
      int *ipArray = 0;
      
      ipArray = iArray1;        // correct
      ipArray = iArray2[0];     // correct
      ipArray = iArray2[2];     // correct
      int **ippArray = iArray2; // wrong
      

      根据上面最后一行,编译器不会将其视为有效赋值。所以 **p 没有被使用。

      由于分配内存的方式,指针运算不能应用于双精度数组。

      【讨论】:

      • 您在回答中根本没有谈到指向数组的指针。
      猜你喜欢
      • 1970-01-01
      • 2016-12-02
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-22
      相关资源
      最近更新 更多