【问题标题】:Is int *array[32] a pointer to an array of 32 ints, or an array of 32 pointers to int? Does it matter?int *array[32] 是指向 32 个 int 数组的指针,还是指向 int 的 32 个指针数组?有关系吗?
【发布时间】:2010-11-25 04:58:08
【问题描述】:

如果我写

int *columns[32];

我是否定义了一个包含 32 个指向 ints 的指针的数组?
还是一个指向 32 个ints 数组的指针?

如何区分这两者?有区别吗?

【问题讨论】:

    标签: c arrays pointers multidimensional-array


    【解决方案1】:

    将评论扩展到另一个答案:

    阅读 C 声明有一个相当简单的过程。从声明器中最左边的标识符开始,然后逐步退出,记住[]() 绑定在* 之前。鉴于声明

    int *columns[32];
    

    把它分解为

         columns                  -- columns
         columns[32]              -- is a 32-element array
        *columns[32]              -- of pointers
    int *columns[32]              -- to int.  
    

    如果声明是

    int (*columns)[32];
    

    然后它会分解为

          columns                 -- columns
        (*columns)                -- is a pointer
        (*columns)[32]            -- to a 32-element array
    int (*columns)[32]            -- of int.  
    

    这也将帮助您建立复杂的声明。假设您要声明一个指向函数的指针数组,该函数返回指向 char 数组的指针:

              f                     -- f
              f[N]                  -- is an N-element array
             *f[N]                  -- of pointers
            (*f[N])()               -- to functions
           *(*f[N])()               -- returning pointers
          (*(*f[N])())[M]           -- to M-element arrays
         *(*(*f[N])())[M]           -- of pointers
    char *(*(*f[N])())[M];          -- to char
    

    cdecl 是一个不错的工具,但是在您完成了几次此练习之后,您就不需要它了。

    【讨论】:

    • 这是我希望 StackOverflow 具有“最喜欢的答案”功能的一个答案。 :-/ 分数 += 1;
    【解决方案2】:

    如有疑问 - 询问cdecl

    $> cdecl 
    Type `help' or `?' for help
    cdecl> explain int *columns[32]
    declare columns as array 32 of pointer to int
    

    编辑 回复 cmets:我在 Google Code Search 上找到了 cdecl 源。它需要GNU readline 库。我认为在 Mac OS X 或 Windows 上编译应该没有问题。

    【讨论】:

    • 出于好奇,您知道在哪里可以找到cdecl 吗? Apple 的资本主义猪并没有提供他们的开发工具。
    • @Chris Mac OS X 不包括 cdecl?我认为它是所有 Unix 的标准工具。您可以从任何 Linux 发行版中获取 cdecl 源并在 Mac OS X 上编译它 - 我认为它没有任何依赖项(好吧,也许是 readline)
    • 如果添加了cdecl下载页面的链接会非常有用。如果它还包括 Windows 下载,则奖励... :)
    • @Chris:它也不在 macports 和 fink 中。看起来你必须手动编译它。
    • @qrdl:网上还有一个版本的cdecl供公众使用:cdecl.org
    【解决方案3】:

    您正在定义一个包含 32 个指针的数组。

    要定义一个指向 32 个整数数组的指针,您必须这样做

    int (*columns)[32];
    

    前一个声明实例化了一个空间为 32 * sizeof(int) 的数组。另一方面,后者实例化了一个未初始化的指针,然后您可以按如下方式使用它:

    int myintegers[32] = {0, 1, 2, ..., 31};
    int (*columns)[32];
    
    columns = &myintegers;
    
    printf("%d\n", (*columns)[2]);
    

    我希望我能把区别说清楚一点。

    【讨论】:

      【解决方案4】:

      这是一个由 32 个指向 int 的指针组成的数组,是的,这很重要。

      C 语法规则指定数组访问 ([]) 比解引用 (*) 绑定更紧密,声明镜像使用。

      声明int *columns[32]; 表示表达式*columns[n](其中n 是0 到31 之间的数字)是int。此表达式与*(columns[n]) 相同。该声明为 32 个指针分配空间,但没有分配 ints 并且(假设这是一个函数局部声明)没有一个指针被初始化。

      如果声明为int (*columns)[32];,那么表达式(*columns)[n] 将是int,这意味着* 取消引用发生在数组访问之前,因此列将是指向32 @ 数组的指针987654334@s。声明将分配一个指针,但没有ints 的数组。

      【讨论】:

      • 我不是 C/C++ 用户,但我确实对这种语言感兴趣。这似乎有点违反直觉,可能是因为我来自 C# 背景。如果你声明 int (*columns)[32] 我希望你得到一个包含 32 个指针的数组。我的理解是括号中的表达式指定了一个指针类型,而数组说明符的意思是“左侧类型的 32 个实例”。因此 - 32 个指针。反过来也是如此——如果你说 int *columns[32] 并且括号绑定得更紧,那么直观的方法是一个 32 项的数组,然后是一个指向它的指针。
      • 为什么会反过来呢?我还在其他地方看到过括号语法,尤其是函数指针。这对我来说也没有意义。我应该如何思考它才有意义?
      • K&R 可能更适合回答“为什么”。 :) 不过,我同意你的直觉。
      • 原因是 C 声明遵循“声明匹配使用规则”。这意味着int *x 意味着被读取*xint。这只是描述语言的一种方式。我发现当你有二维数组时它真的很有帮助。如果您有int x[2][4],则意味着x[0][3] 是有效的int。必须颠倒声明和使用之间的索引限制会导致另一种混乱。
      • Charles 在这里很好地描述了理解如何阅读所有复杂 C 声明的关键。这一切都始于将int *x; 读取为“*xint”,不是xint *”。以正常顺序将所有“运算符”应用于标签,最终得到给定的基本类型。
      【解决方案5】:

      测试程序是说明性的,尤其是对于我们这些不是语言律师的人:

      $ gcc -x c -
      #include <stdio.h>
      
      int main(void) 
      {
          int *columns[32];
          printf("%lu\n%lu\n", sizeof(columns), sizeof(columns[0]));
          return 0;
      }
      $ ./a.out
      128
      4
      $
      

      它似乎是一个指针数组。

      【讨论】:

      • 我很难说理解声明需要“语言律师”身份。
      • 我知道,但我也记不起是哪一个,而且 OS X 没有安装好的cdecl 版本。
      • 我认为,如果不使用 cdeclgeordi 或其他作弊手段,大多数非律师将无法告诉您 void (*(*(*p)[N][M])[O])(char c) = 0; 声明的内容。
      • 其实有一个简单的程序可以分解毛茸茸的声明,但是评论字段的限制使其难以演示。简单地说,找到最左边的标识符并找出路,记住 [] 和 () 在 * 之前绑定。所以你从 p 开始,然后注意它是一个指针 (*p) 指向一个 N 元素数组 (*p)[N] 的 M 元素数组 (*p)[N][M] 的指针 (*(*p)[N][M]) 到 O 元素数组 (*(*p)[N][M])[O] 的指针 (*(*(*p)[N][M])[O])函数采用 char 参数 (*(*(*p)[N][M])[O])(char c) 并返回 void void (*(*(*p)[N][M])[O])(char c)
      • @John,最后一切都很容易。我个人应用“从右到左”的规则,它也很简单:p is a ") -> left" pointer to "( -> right " M 的 N 个数组的数组 ") -> 左" 指向 "( -> 右" O 的数组 ") -> 左" pointer to "( -> right" 函数获取 char "EOL -> left" 并返回 void但是 您首先必须了解这些规则以及它们如何与优先级等相互作用。所以我认为大多数非律师都迷失在括号中。
      【解决方案6】:

      这里有一些有趣的声明:

      int *arrayOfIntP[32];
      int (*pointerToArrayOf32)[32];
      

      要获得更多关于多维数组的乐趣,请查看以下帖子:

      Array of pointers to multidimensional arrays

      How do I declare a 2d array using new?

      【讨论】:

        【解决方案7】:

        一个技巧是从右到左阅读。

        给定 int* cols[32];

        1. 您首先看到 cols[32] :这是一个大小为 32 的数组。
        2. 接下来您会看到 int*:这是一个指针

        数组左边是数组中元素的类型。因此,我们将其读取为指向 int 的指针数组(计数为 32)。

        【讨论】:

          【解决方案8】:

          请参阅 Nigel Jones 的 A 'C' Test: The 0x10 Best Questions for Would-be Embedded Programmers 中的问题 #5*


          a) int a; // 一个整数

          b) 整数 *a; // 指向整数的指针

          c) int **a; // 一个指向整数的指针

          d) int a[10]; // 10 个整数的数组

          e) int *a[10]; // 一个包含 10 个整数指针的数组

          f) int (*a)[10]; // 指向 10 个整数数组的指针

          g) int (*a)(int); // 一个指向函数 a 的指针,它接受一个整数参数并返回一个整数

          h) int (*a[10])(int); // 一个包含 10 个指针的数组,指向接受整数参数并返回整数的函数


          *唉,embedded.com 上的原始文章无法在他们的网站上找到。

          【讨论】:

            猜你喜欢
            • 2021-02-07
            • 2021-07-28
            • 1970-01-01
            • 1970-01-01
            • 2017-09-03
            • 1970-01-01
            • 2013-07-11
            • 1970-01-01
            相关资源
            最近更新 更多