【问题标题】:C difference between *[] and **C *[] 和 ** 的区别
【发布时间】:2011-05-11 15:24:32
【问题描述】:

这可能是一个基本的问题,但是写 char * [] 和 char ** 有什么区别?例如,在 main 中,我可以有一个 char * argv[]。或者,我可以使用 char ** argv。我认为这两种符号之间一定存在某种差异。

【问题讨论】:

  • 只是语法糖。
  • 当然,但我认为含义有所不同。例如,我可以声明 char ** 的东西。但不能声明 char * something[].
  • 这当然不是语法糖,为了理解差异,我建议 Peter van der Linden 的一本非常好的书“专家 C 编程”,它有一整节介绍了两者之间的差异。
  • 我在这个页面找到了类似的解释:lysator.liu.se/c/c-faq/c-2.html

标签: c arrays pointers


【解决方案1】:

在这种情况下,根本没有区别。如果您尝试使用数组类型作为函数参数,编译器会将其“调整”为指针类型(即,T a[x] 作为函数参数表示完全正确 与:T *a) 相同。

在正确的情况下(即,不是作为函数参数),使用数组和指针表示法之间可能存在差异。一种常见的是在extern 声明中。例如,假设我们有一个包含以下内容的文件:

char a[20];

我们想让它在另一个文件中可见。这将起作用:

extern char a[];

但这不会:

extern char *a;

如果我们把它变成一个指针数组:

char *a[20];

...同样如此——声明一个外部数组可以正常工作,但声明一个外部指针却不行:

extern char *a[]; // works

extern char **a;   // doesn't work

【讨论】:

  • 为什么extern 的行为会有这种差异?
  • @Lazer:类型调整发生在您将参数传递给函数时,但这里我们没有将参数传递给函数,因此不会发生类型调整。
  • 第一段中的声明有一个极端案例。如果T 是不完整类型,则不允许T a[x] 作为参数,但T *a 是。
【解决方案2】:

取决于上下文。

作为函数参数,它们的含义相同(对编译器而言),但编写它char *argv[] 可能有助于让程序员清楚地知道,传递的char** 指向@987654323 数组的第一个元素@。

作为变量声明,它们的含义不同。一个是指向指针的指针,另一个是指针数组,数组的大小未指定。所以你可以这样做:

char * foo[] = {0, 0, 0};

并得到一个由 3 个空指针组成的数组。三个char*s 与指向char* 的指针完全不同。

【讨论】:

  • 是的,我也是这么想的。即使在函数参数中,decl 也表达了语义,不是吗 - 例如。 char* argv[] ?
  • Townsend:是的,[] 表单强烈建议传递一个数组。不过,我不同意char** 的意思是它不 打算用作数组,因为有很多C 程序员(包括我在内)对此不屑一顾。 char* 通常并不意味着“只有一个字符”——它通常用于字符串。我不明白为什么char** 应该意味着“只有一个char*”。所以我想说char ** 的意思是“检查文档”,而char *[] 的意思是“检查文档”;-)
  • 对于char**,我同意它是特定于上下文的。如果那是一个函数参数,我将其读作“函数可以更改的字符串”。也就是说,这些天我主要是 C++,所以我会听从你的专业知识(当然还有文档)。
  • @Steve:嗯,这些天我主要是 Python,至少在我得到报酬的时候,所以我不确定我是否可以要求优先权。我想我的观点很明显,猜测是一项有风险的业务。
【解决方案3】:

您可以使用cdecl.org 将它们转换为英文:

  • char *argv[] = 将 argv 声明为指向 char 的指针数组

  • char **argv = 将 argv 声明为指向 char 的指针

【讨论】:

    【解决方案4】:

    我认为这不仅仅是语法糖,它还提供了一种表达每种声明所隐含的(自愿)合同的语义信息的方法。

    char*[] 是说它打算用作数组。

    对于char**,您是说可以将其用作数组,但这不是它的预期使用方式。

    【讨论】:

      【解决方案5】:

      正如其他答案中提到的,char*[] 声明了一个指向 char 的指针数组,char** 声明了一个指向 char 指针的指针(可以用作数组)。

      一个区别是数组是常量,而指针不是。

      例子:

      int main()
      {
          char** ppc = NULL;
          char* apc[] = {NULL};
          ppc++;
          apc++; /* this won't compile*/
          return 0;
      }
      

      【讨论】:

      • 其实指针可以声明为常量,但它仍然不会和数组一样。您可以从错误中看到两者之间的区别:增加声明为 char * const a 的 a 将导致“只读值增量”错误,而增加声明为 char b[1] 的 b 将产生“需要左值作为增量操作数”。
      • 数组也不是常数。 (事实上​​,常量数组在 C 中是不可能的;声明为 const 的数组实际上是带有 const 元素的非常量数组)。 apc++ 无法编译的原因是因为++ 运算符被定义为仅适用于指针和非complex 数字类型,并且数组不是指针。
      【解决方案6】:

      这真的取决于声明发生的上下文。

      在函数参数定义之外,声明

      T a[];
      

      将a 声明为未知 大小的T 数组;数组类型是不完整,所以除非a在其他地方定义(在这个翻译单元或另一个链接的翻译单元中),否则不会为它留出存储空间(如果您尝试链接,您可能会收到“未定义的引用”错误,尽管我认为 gcc 的默认行为是使用 1 个元素定义数组)。它不能用作sizeof 运算符的操作数。它可以用作& 运算符的操作数。

      例如:

      /** 
       * module1.c
       */
      extern char *a[]; /* non-defining declaration of a */
      
      void foo()
      {
        size_t i = 0;
        for (i = 0; a[i] != NULL; i++)
          printf("a[%lu] = %s\n", (unsigned long) i, a[i++]);
      }
      

      module1.c 使用a 的非定义 声明来引入名称,以便可以在函数foo 中使用,但由于没有指定大小,因此没有存储空间在这个翻译单元中留出它。最重要的是,表达式a 不是指针类型;它是一个不完整的数组类型。在对printf 的调用中,它将按照通常的规则转换为指针类型。

      /**
       * module2.c
       */
      char *a[] = {"foo", "bar", "bletch", "blurga", NULL}; /* defining declaration of a */
      
      int main(void)
      {
        void foo();
      
        foo();
        return 0;
      }
      

      module2.c 包含a 的定义 声明(数组的大小是根据初始化程序中的元素数计算的),这会导致为数组分配存储空间。

      风格说明:请永远不要编写这样的代码。

      在函数参数声明的上下文中,T a[] 是 T *a 的同义词;在这两种情况下,a 都是指针类型。这仅在函数参数声明的上下文中为真。

      【讨论】:

      • T a[]; 被称为暂定定义。这不是 gcc 扩展;标准行为是,如果类型在翻译单元的末尾没有完成,那么就好像在 TU 的末尾添加了一行,说 T a[1];。
      【解决方案7】:

      正如保罗在上面的评论中所说,它是语法糖。 char* 和 char[] 都是相同的数据类型。在内存中,它们都将包含一个字符的地址。

      数组/索引表示法等同于指针表示法,无论是在声明中还是在访问中,但有时更直观。如果您正在创建一个 char 指针数组,您可能希望以一种或另一种方式编写它以阐明您的意图。

      编辑:没有考虑其他答案中提到的杰里的情况。看看那个。

      【讨论】:

      • 它们通常不是同一类型。 char *[] 只是在函数声明中衰减为 char **,因为你不能传递一个实际的数组。
      【解决方案8】:
          char *ptr[2]={"good","bad"}; //Array of ptr to char
          char **str;  //Refer ptr to ptr to char
          int i;
          //str = &ptr[0];  //work
          str = ptr;
      
          for(i=0;i<2;i++)  printf("%s %s\n",ptr[i],str[i]);
      

      它的o / p相同。使用它我们很容易理解。

      【讨论】:

        猜你喜欢
        • 2013-04-15
        • 2013-10-25
        • 2017-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-15
        • 2011-01-29
        • 2012-10-24
        相关资源
        最近更新 更多