【问题标题】:How static initialize a 2D array to a pointer to pointers?如何将二维数组静态初始化为指向指针的指针?
【发布时间】:2019-03-20 00:57:26
【问题描述】:

我有一个结构,比如foo,看起来像这样,

struct foo {
    size_t n;
    size_t **point;
};

结构中还有其他成员对问题不重要。现在,我想静态初始化结构。

int main(void)
{
    struct foo *bar = &(struct foo){
                       .n=4,
    /* ERROR HERE */   .point=(size_t[][n]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
    };
    return 0;
}

指示的行中有两个问题。首先,可以理解的是,编译器无法识别n,有没有什么办法可以在不创建变量的情况下做类似的事情?其次,也是最重要的,我意识到我不知道如何创建一个二维数组并将其静态分配给指向指针的指针。请帮忙。我尝试了以下变体,但没有任何效果。

/* Variation 1 */   .point=(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 2 */   .point=(size_t**)(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 3 */   .point=&(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}

【问题讨论】:

  • 您正在尝试获取临时地址(未定义的行为),并且您正在尝试将指向指针的指针视为二维数组(它们不是二维数组)。
  • @SergeyA 获取地址可能不是问题。复合文字有一个封闭块的存储时间,标准至少有一个在这种情况下取​​地址的例子。
  • @user694733 虽然复合文字可以,但从它创建的foo 类型的临时变量却没有。

标签: c arrays pointers struct


【解决方案1】:

请注意,这在技术上不是二维数组,而是指针到指针的数组。但由于复合文字不能具有可变长度数组类型,而且您似乎不想使用硬编码维度,这可能是唯一的方法。

您需要将数组拆分为大小未知的一维数组,并为它们使用单​​独的复合文字:

struct foo * bar = &(struct foo){
    .n = 4,
    .point = (size_t*[]){
        (size_t[]){1, 2, 3, 4}, 
        (size_t[]){5, 6, 7, 8}
    }
};

【讨论】:

    【解决方案2】:

    首先,size_t **point 仅在您打算指向 size_t* 的数组时才有意义。此处似乎并非如此,因此您需要将类型更改为二维数组或数组指针。

    下一个问题是 C 在这里相当麻烦 - 坦率地说,你不能有一个“静态动态”数组,它也必须是。你可以有这个:

    #define N 4
    
    struct foo {
      size_t n;
      size_t (*point)[N]; // pointer to first array of an array of size_t[4]
    };
    
    struct foo bar = 
    {
      .n=N,
      .point= (size_t[][N]){ {1, 2, 3, 4}, {5, 6, 7, 8} }
    };
    
    ...
    bar.point[x][y] = ...; // access element of the 2D array
    

    或者也可以是指针数组形式的灵活数组成员,如下所示:

    struct foo {
      size_t n;
      size_t* point[];
    };
    
    const size_t n = 4;
    struct foo* bar = malloc ( sizeof(*bar) + sizeof (size_t*[n]) );
    bar->n = n;
    bar->point[0] = (size_t []) { 1, 2, ... /* any number of elements*/ };
    bar->point[1] = ...
    ...
    bar->point[0][0] = 0; // access element in the lookup-table
    ...
    free(bar);
    

    这些都不是特别好的替代方案,语法混乱且容易出错。这里的语言严重缺乏。

    【讨论】:

      【解决方案3】:

      为了静态初始化指针,需要声明您指向的实体。只有在极少数情况下,例如在编译时您知道某物的地址的嵌入式系统,您才会知道要静态初始化的指针的实际值。

      我发现您的操作存在一些问题: 1)当您尝试使用它来声明数组的大小时,编译器无法解析 n 的值。与 C# 不同,数组需要在其声明中提供大小。 2) 结构的“point”成员是指向指针的指针,但您正尝试使用数组数组对其进行初始化。如果要指向数组数组,只需要[0][0]元素的地址,所以*point不是**point。从那里您可以使用数组表示法来访问元素。

      你需要做这样的事情:

      struct foo
      {
          size_t n;
          size_t *point;
      };
      
      
      size_t values[2][4] = {{1,2,3,4}, {5,6,7,8}};
      
      struct foo bar = 
      {
          4,
          &values
      }
      

      然后你可以通过以下方式访问数组:

      size_t kk;
      kk = bar.point[ii][jj];
      

      如果您确实需要指向指针的指针,那么初始化值必须是地址引用 (&name) 或被强制转换为指针的值,但我不建议这样做。

      如果您确实需要可变大小的数组,那么您需要动态分配内存,然后使用从该结构返回的地址初始化结构中的指针。

      【讨论】:

        猜你喜欢
        • 2010-10-11
        • 2016-08-16
        • 2015-04-28
        • 2014-07-12
        • 2017-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多