【问题标题】:arrays with missing sizes vs pointers缺少大小的数组与指针
【发布时间】:2014-06-17 10:58:55
【问题描述】:

我普遍认为以下两个原型是可以互换的:

int main(int argc, char ** argv);
int main(int argc, char * argv[]);

总的来说,我认为char ** argvchar * argv[] 是可以互换的。但是,我也在互联网上遇到了一些声称您可以声明类似结构的东西

struct S {
  int size;
  int ar[];
};

然后适当地简单地 malloc 以便 ar 在运行时可以任意大。

但这对我来说似乎很奇怪。如果我改为声明

struct S {
  int size;
  int * ar;
};

我还能做同样的事情吗?我原以为这取决于你让ar 指向什么。

int * arint ar[] 在结构中使用时有何不同?函数原型中的char ** argvchar * argv[] 怎么样?与 C++ 相比,它们在 C 中的语义是否不同?

【问题讨论】:

  • @RedAlert:不,数组是数组,在大多数情况下,数组名称会衰减为指向其第一个元素的指针。尝试分配给数组!
  • @Deduplicator 只是为了扰乱你的想法:考虑 T(&)[]T*
  • @gha.st: 引用一个数组,还是我解析错了?
  • @Deduplicator 对大小未定义的数组的引用,而不是指向其第一个元素的指针,是的 ;)
  • @RedAlert:请不要告诉人们数组是指针。他们不是。阅读comp.lang.c FAQ 的第 6 部分。

标签: c++ c arrays


【解决方案1】:

对于看起来像数组的函数参数有一个特殊情况规则。任何此类参数都“调整”为指向(可能是合格的)元素类型的指针。

由于这条规则,这些定义:

int main(int argc, char **argv) { /* ... */ }

int main(int argc, char *argv[]) { /* ... */ }

完全等价。 (函数类型的参数也有类似的规则,调整为函数指针。)

此规则应用于参数声明。

一个恼人的后果是,如果你声明一个带有大小的数组参数,它会被默默地忽略:

void func(int array[42]);

真正的意思

void func(int *array);

(有static关键字的用法,在C99中添加,这里不再赘述。)

struct S {
    int size;
    int ar[];
};

这是一个灵活的数组成员,是 C99 中添加的一个特性。它声明ar 是一个未指定大小的数组(不是,我重复不是,一个指针)。要使用它,您必须分配足够的空间来容纳运行时需要的许多元素。这被添加到语言中,以替代 comp.lang.c FAQ 的问题 2.6 中描述的“struct hack”。

同一常见问题解答的第 6 节是解释数组和指针之间经常令人困惑的关系的绝佳资源。

【讨论】:

    【解决方案2】:

    在函数参数中使用数组类型有一个special 规则:它们变成指针类型。但是,该规则仅适用于函数参数。

    当您将未定义的大小替换为例如两个大小:

    void f(int x[2]); // equivalent to void f(int* x);
    
    struct A {
        int q[2]; // obviously not equivalent to int* q;
    };
    

    你使用的结构定义

    struct S {
        int size;
        int ar[];
    };
    

    的意思是说任意数量的ints 应该跟在size 成员之后——可能正好是size 元素。您不能只遗漏最后一个成员,因为这可能会导致错误 w.r.t.对齐和填充(假设 ardoubles 的数组,你会看到问题)。

    此语法是 an old trick 的演变,已添加到 C99 中。

    【讨论】:

      【解决方案3】:

      您可以将第一个和第二个布局用于相同的目的,但内存中的布局将不一样。对于第一个示例,您将拥有(假设是 32 位架构):

      [size (4 bytes)][ar (size bytes)]
      

      第二个:

      [size (4 bytes)][pointer to ar (4 bytes)][ar (size bytes)]
      

      所以第二种方案会浪费内存。

      【讨论】:

        【解决方案4】:

        char **char *[] 确实是一样的。事实上,以下内容将起作用:

        void foo(int a1[]) {
            int a2[3];
            a2 = 0; // ERROR: Can't assign to an array.
            a1 = 0; // OKAY: You can assign to it, because it's actually a pointer!
            ...
        

        不过,您展示的结构 S 使用的是灵活的数组成员。它不占用空间。你不能分配给它。基本上,int [] 的含义不同,具体取决于它是成员还是参数。但是,在您拥有指针的结构中,您基本上可以在任何地方指出这一点。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-15
          • 1970-01-01
          • 2022-01-02
          相关资源
          最近更新 更多