【问题标题】:When is pointer to array useful?指向数组的指针什么时候有用?
【发布时间】:2011-01-03 12:56:16
【问题描述】:

我可以声明:

int (*ap)[N];

所以ap 是指向大小为 N 的 int 数组的指针。为什么这很有用?如果我将它传递给函数,它可以用它做什么有用的事情,它不能只用一个普通的指向数组内容的指针来做?

C 常见问题解答说:

2.12:如何声明指向数组的指针?

通常,您不想这样做。

【问题讨论】:

  • 一个指向 int 的指针,但是很有用。
  • 在我用 C 编程的 25 年多的时间里,我认为我不需要使用指向数组的指针进行编码。(我只使用过三重指针 - SomeType * **var - 几次,并更改代码以尽快避免它们。)
  • @reinier:当然,但我没有问过这个
  • 这不是指向数组的指针。那是一个int指针数组。数组本身就是一个指针。
  • @Dave,它不是一个 int 指针数组,它是一个指向 N 个 int 的指针。

标签: c pointers


【解决方案1】:

一个指向数组的指针可以用来动态分配一个多维数组N,其中N-1维是已知的。下面创建一个 Nx3 数组。

int (*ap)[3];
ap = malloc(N * sizeof(*ap));
/* can now access ap[0][0] - ap[N-1][2] */

@Adam E/Cruachan,这与指向指针的指针不同。 ap 是指向包含三个连续整数的内存块的单个指针。 ap++ 会将指针地址推进到下一个三个整数块。对于int **pp;,pp指向一个整数指针,每个指针都可以指向内存中任意位置的整数。

         +-----+                +------+    +-----+
 ap ---> | int |   vs.  pp ---> | int* | -> | int |
         | int |                +------+    +-----+
         | int |        pp+1 -> | int* | -\
         +-----+                +------+   \   +-----+
 ap+1 -> | int |                  :  :      -> | int |
         | int |                               +-----+
         | int |
         +-----+
           : :  

【讨论】:

  • 但可以说 ap 只是一个二维数组。
  • 是的,但它与“int ap[4][3];”不同。它允许动态分配第二维。
  • 啊,我明白了,在这种情况下,我承认我的错误并撤回我的答案。
【解决方案2】:

如果增加指针,它将指向下一组 N 元素的开始。

这没什么大不了的,它的使用取决于开发人员。

【讨论】:

  • 天哪,你见过这个用过吗?
  • 很高兴看到有人知道这两者不一样 =)
  • @bmargulies:我已经将它用于一个 MD5 校验和数组,其中每个校验和为 16 个字节。
【解决方案3】:

通常,您唯一会看到指向数组的指针 (T (*a)[N]) 是作为函数参数,其中 a 是二维数组:

void foo(int (*a)[N], size_t count)
{
  size_t i;
  for (i = 0; i < count; i++)
      a[i][j] = ...;
  ...
}

void bar(void)
{
  int arr[M][N];
  foo(arr, M);
}

请注意,对于函数参数声明,int a[][N] 等价于 int (*a)[N],但对于函数参数声明为真:

void foo (int a[][N], size_t count) {...}

指向数组的指针通常不如指向基类型的指针有用,因为您需要知道数组大小才能正确声明指向它的指针(指向 10 元素 int 数组的指针与指向 20 个元素的 int 数组的指针)。就个人而言,在 20 多年的编程中,我没有发现它们有多大用处。

请记住,在大多数情况下,数组表达式(例如上面的 arr)将其类型从“T 的 N 元素数组”隐式转换为“指向 T 的指针”(除非数组表达式是操作数sizeof&amp;,或者该数组是在声明中用作初始值设定项的字符串文字)。在这种情况下,对 foo 的调用中的arr 的类型隐式地从“int 的 N 元素数组的 M 元素数组”转换为“指向 int 的 N 元素数组的指针”。

鉴于声明T a[M][N],以下所有表达式都将计算到相同的位置(数组中第一个元素的地址),但类型将不同,如下所示:

表达式类型隐式转换为 ---------- ---- ------------ 一个 T [M][N] T (*)[N] 一个[0] T [N] T * &a T (*)[M][N] &a[0] T (*)[N] &a[0][0] T *

【讨论】:

    【解决方案4】:

    在某些情况下,您希望跨程序传递内存位置。例如,Windows API 可能希望您传递指向数据结构或数组的指针,因为您正在使用其他语言(例如 c#)进行编程。 Windows API 不关心目标语言如何处理数组,对于 Windows API,它只是内存中的一个字节流,它会填充它,将它发送回给你。在某些情况下,为了避免跨语言类型不匹配,我们使用指向数组的指针而不是隐式数组名称作为指针。此外,不能保证隐式数组名称是长指针,一些编译器可能会将其优化为带有段的相对值。指向数组的指针保证它是机器寄存器大小的顺序,并且您可以指向可用 RAM 中的任何位置。

    【讨论】:

      【解决方案5】:

      真的没用。但有时会使用指向数组的指针,例如在 Microsoft Windows API 中 - 我在那里见过很多这样的东西。

      【讨论】:

      【解决方案6】:

      这可能会变成主观/争论,但是......

      在我看来,指向数组的指针在语言中是因为它们属于语言。有指向其他所有可声明数据类型的指针,所以这些也在这里。我从未见过有人从他们那里得到真正有用的工作。假设,它们允许一个需要数组而不是指向元素的指针的原型,但是...

      【讨论】:

      • ...但它们是同一件事(指向(第一个)元素的指针和指向数组的指针)? :)
      • 它们评估到相同的位置,但类型不同,类型很重要。
      【解决方案7】:

      对我来说,做一个指向数组的指针似乎毫无用处。在 C 中,数组已经是指向该数据类型块的指针。

      int (*ap)[N];
      int **ipp;
      

      都是相同的数据类型(指向整数指针的指针)。唯一的区别是为 ap 分配了 N 个整数的空间。

      没有必要通过指向函数的指针传递数组,例如,为了更改该函数中数组的内容,因为它已经是一个指针。作为一般规则,我会说这是不必要的,只是创建了一个额外的需要来取消引用指针以获取数组中的数据。但是,我确信某处有一个程序或算法可以找到它的合法用途。

      【讨论】:

      • 不,它们不是同一种数据类型。所以你说ipp = ap;ap = ipp; 没问题(假设指针指向有用的地方)?
      • 他们不一样。试试++ap++ipp 看看你会得到什么。
      • 数组不是指针。在大多数情况下,数组 expression 可能会隐式转换为指针类型,但这不是一回事。在您的示例中,apipp 不是兼容类型;您不能将 ap 的值分配给 ipp,反之亦然(至少在没有显式转换的情况下不能)。
      【解决方案8】:

      以下代码是我文章的一部分:C C++ 中的指针和数组

      您可以查看@http://pointersandarrays.blogspot.com/

      指针和二维数组

      以下代码 sn-p 说明了如何声明和访问 2D 数组。二维数组下面是一个一维数组。玩过以下代码后,您将确定这一点。

      代码片段 #4

      
       #include<iostream&rt;  
          using namespace std;  
      
          int main()  
          {  
           cout<< "Understanding Pointers and 2 D Arrays"<<endl;  
           cout<< "----------------------\n"<<endl;  
      
          //Declaration of a 2D Array.  
          int tab[3][5];  
          //Total space required : 3*5 * sizeof(int) = 15 * sizeof(int)   
          //Funda : Since the amount of required space is known by compiler, contiguous 15 memory cells are allocated here.     
          //Hence the case is similar to a 1 D Array of size 15. Lets try this out!  
      
          //Array initialization using array name   
          for(int i=0; i<3;i++)  
           for(int j=0; j<5;j++)  
             tab[i][j]=i+2*j;  
      
          //Print array using array name   
          cout << "\nPrint array using array name ..."<<endl;    
          for(int i=0; i<3;i++)  
           {  
            for(int j=0; j<5;j++)  
             printf("%2d ",tab[i][j] );  
            printf("\n");  
           }  
      
          //Print array using a pointer. Proof of 1 D array being allocated  
          cout << "\nPrint array using a pointer. Proof of 1 D array being allocated ..." << endl;       
          int *tptr;  
          tptr = &tab[0][0]; // pointer tptr points at first element of the array.   
      
          for(int i=0; i<15;i++)  
           printf("%d ",*(tptr+i) );  
          tptr = &tab[0][0];  
          cout << "\nNotice that array is printed row by row in a linear fashion."<<endl;  
           return 0;  
          }  
      
      

      输出 #4:

      Understanding Pointers and 2D Arrays  
      
      Print array using array name ...  
       0  2  4  6  8   
       1  3  5  7  9   
       2  4  6  8 10   
      
      Print array using a pointer. Proof of 1 D array being allocated ...  
      0 2 4 6 8 1 3 5 7 9 2 4 6 8 10   
      Notice that array is printed row by row in a linear fashion.  
      

      【讨论】:

        【解决方案9】:

        我认为整个讨论的结论是从不。这里没有人真正展示了这种结构的用途,而其他东西无法以更易于理解的方式发挥作用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-16
          • 1970-01-01
          • 2016-12-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多