【问题标题】:Why I need different declarations for **ptr and *ptr[]? [duplicate]为什么我需要为 **ptr 和 *ptr[] 声明不同的声明? [复制]
【发布时间】:2020-07-22 09:57:59
【问题描述】:

我认为char *ptrs[];char **strs; 应该是同一个东西。 至少我可以将两者都用作字符串数组。

当我尝试编译 char **strs 时,这很好,但 *ptrs[] 出于某种原因想要被初始化或者至少它想要一个固定的大小。

char ptrs[];
char **strs;

我得到错误:

gcc: "error: array size missing in ‘ptrs’"

【问题讨论】:

  • 首先你忘记了char ptrs[];中的星号。其次,您不能将非参数变量定义为没有大小的数组。第三,C 和 C++ 是两种不同的语言,它们有不同的规则,例如使用未调整大小的数组(C 标准允许在 一个 位置使用,但 C++ 标准不允许这样做)。
  • 数组和指针不是一回事

标签: c pointers


【解决方案1】:

我认为char *ptrs[];char **strs; 应该是同一个东西。

你想错了。首先是一个未指定大小的指针数组。第二个是指向指针的指针。数组不是指针,指针也不是数组。

您可能对函数参数感到困惑。函数参数不能是数组,如果你写一个数组参数,它被调整为指向该数组元素的指针。因此,在参数声明中,第一个被调整为与第二个相同。这种调整只发生在参数声明中,其他地方都没有。

【讨论】:

    【解决方案2】:

    数组和指针是两种不同的派生类型。

    如果你声明一个具有自动存储持续时间的对象,那么它应该有一个完整的类型。对于数组,这意味着数组中元素的数量应该是已知的(显式指定或根据提供的初始化计算)。

    所以编译器发出错误

    gcc: "error: array size missing in ‘ptrs’"
    

    对于这个具有自动存储时长的数组的声明

    char *ptrs[];
    

    (当您比较这两个声明 char *ptrs[];char **strs; 时,我认为您的意思是类型说明符 char * 而不是 char),因为它无法确定为数组分配多少内存。

    另一方面,指针总是完整的对象类型。来自 C 标准(6.2.5 类型,p.#20)

    指针类型是一个完整的对象类型。

    因此编译器总是知道指针的大小。

    如果这个声明

    char *ptrs[];
    

    具有文件范围,则允许这种不完整的声明并命名为暂定定义。编译器会像这个声明一样解释它

    char *ptrs[1];
    

    出现在翻译单元的末尾。

    表达式中使用的数组被隐式(除了极少数例外)转换为指向其第一个元素的指针。因此,在表达式中使用的这个数组指示符 ptrs 例如函数参数被转换为类型为 char ** 的右值。

    来自 C 标准(6.3.2.1 左值、数组和函数指示符)

    3 除非它是 sizeof 运算符的操作数或一元 & 运算符,或者是用于初始化数组的字符串文字, 具有“类型数组”类型的表达式被转换为 类型为“pointer to type”的表达式,指向初始 数组对象的元素并且不是左值。如果数组对象 有注册存储类,行为未定义。

    【讨论】:

      【解决方案3】:

      我认为char *ptrs[];char **strs; 应该是同一个东西。至少我可以将两者都用作字符串数组。

      您的假设不正确,这两者都不能用作“字符串数组”。在我看来,一个字符串数组(如果这个术语无论如何都合适的话)是一个chars 的数组数组,其中可以存储一个字符串chars 的每个数组中,因此它又是数组数组的一个元素。指针不能存储字符串。它只能指向一个。

      char **strs; - strs 是指向char 的指针。

      char *ptrs[]; - ptrs 是一个指向 char 的指针数组,其中包含未指定数量的元素。除了作为函数参数之外,其他任何地方都不允许这样做。

      由于函数参数char *ptrs[] 等于char **ptrs 并表示指向char 的指针,但它本身也不存储任何字符串。

      如果你像往常一样使用char *ptrs[] 声明,编译器需要知道数组中指针元素的数量。

      这就是您收到错误消息的原因

      错误:‘ptrs’中缺少数组大小

      使用 GCC。

      【讨论】:

        【解决方案4】:

        这两个声明是等价的只有作为函数参数声明:

        void foo( char *ptrs[], char **strs ) { ... }
        

        因为T a[N]T a[] 类型的任何参数都“调整”为T *a。这是因为在大多数情况下,数组表达式“衰减”为指针表达式 - 当您将数组表达式作为函数参数传递时,函数实际接收的是指针表达式。

        然而,作为常规变量声明,两者等价。数组定义必须指定大小或具有初始化器:

        char *ptrs[] = {"foo", "bar", "bletch", "blurga", ... };
        

        在这种情况下,数组大小将取自初始化器中的元素数。

        【讨论】:

          猜你喜欢
          • 2021-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-11-15
          • 2016-08-21
          • 1970-01-01
          相关资源
          最近更新 更多