【问题标题】:Initialize anonymous array of pointers初始化匿名指针数组
【发布时间】:2016-12-09 01:20:51
【问题描述】:

我正在为一个 Arduino 爱好项目做恶作剧,但我遇到了一个我无法解决的情况。

基本上,我有一个指向 Thing 的全局(因为 Arduino)指针数组。我不想在声明期间对其进行初始化,但我想利用好的数组初始化语法。

请注意,这是一个 Arduino 项目,因此使用了不寻常的 C 和 C++ 组合,因为 Arduino。 从一些基础研究来看,如果它可以在 C 或 C++ 中工作,看起来像这样没有库,它可以解决这个问题。

注意:我使用 NULL 作为一种在循环遍历数组时检测数组结尾的方法,在代码的其他地方。

类似这样的:

struct Thing {
  int i;
};
Thing * MakeThing() {
  return new Thing;
}
Thing * things[] = {
  NULL
};
void setup() {
  things = (Thing*[]){
    MakeThing(),
    NULL
  };
}

但是,这让我得到了error: incompatible types in assignment of 'Thing* [2]' to 'Thing* [1]'

我试过了:

  Thing* _things[] {
    MakeThing(),
    NULL
  };
  things = _things;

同样的错误。

我试过了:

  things =  new Thing*[] {
    MakeThing(),
    NULL
  };

同样的错误。

我试过了:

  things = new Thing** {
    MakeThing(),
    NULL
  };

得到error: cannot convert '<brace-enclosed initializer list>' to 'Thing**' in initialization

我试过了:

  things = new Thing*[] {
    MakeThing(),
    NULL
  };

得到error: incompatible types in assignment of 'Thing**' to 'Thing* [1]'

这是怎么回事?我怎样才能让它发挥作用?

【问题讨论】:

  • 注意:C 中没有new 运算符。
  • 我要把标签从c改成c++
  • 您不能分配数组。我不认为 C++ 有复合文字。
  • @chqrlie 重新标记不正确。这是一个 Arduino 项目,AFAIK 仅是 C。我的 C 足够模糊,以至于我认为 new 是其中的一个东西。
  • 我使用new 重新标记并删除了该示例。感谢您提供帮助。

标签: c arrays pointers arduino initialization


【解决方案1】:

Thing* things[] = {NULL}:

您将变量 things 声明为单个元素的数组(Thing* 类型)。

一旦你声明了这个数组,你就不能改变它——无论是它的大小还是它的地址。

您唯一可以更改的是该数组的内容,即第一个(也是唯一一个)元素。

【讨论】:

    【解决方案2】:

    你想让things指向一个分配的大小为2的数组,你必须写3条语句:

    things = new Thing*[2];
    things[0] = MakeThing();
    things[1] = NULL;
    

    C++ 不支持新样式的 C99 复合文字语法,或者仅作为某些 C++ 编译器的扩展,但这仍然不符合您的目的,因为数组将具有自动或静态的生命周期,而不是动态的。

    编辑:鉴于对问题的重新表述,答案很简单:全局 things 数组必须定义为具有 2 个元素,并且可以在 setup 中使用 2 个语句进行初始化:

    struct Thing {
      int i;
    };
    Thing *MakeThing(void) {
        Thing *t = calloc(sizeof(t));
        return t;
    }
    Thing *things[2];  // implicitly initialized to { NULL, NULL };
    void setup(void) {
        things[0] = MakeThing();
        things[1] = NULL;
    }
    

    或者,如果您以牺牲可读性为代价绝对坚持使用 C99 复合文字,您可以使用:

    void setup(void) {
        memcpy(things, (Thing*[]){ MakeThing(), NULL }, sizeof things);
    }
    

    但我不确定 Arduino 编译器是否支持这种语法。 Arduino-C 既不是 C 也不是 C++。

    【讨论】:

    • 嗨,这就是为什么它只标记为 C,而不是 C C++。
    【解决方案3】:

    首先,所有这些都无法编译,因为在 C 中分配给数组(给数组类型的变量)是非法的。

    其次,即使您可以分配给 C 中的数组(假设它复制所有元素),您尝试执行的操作仍然不起作用,因为您将在不同的数组类型之间分配 - 大小是数组类型的一部分。 Thing *[1]Thing *[2] 是完全不同的类型。如果你有一个数组类型的变量,大小在编译时是硬编码的。您的变量things 的类型为Thing *[1],并且在编译时是硬编码的,无法更改。 (使用 C99 VLA,您可以拥有一个数组变量,其大小在编译时不是硬编码的,但在定义数组变量时是固定的,之后在变量的生命周期内仍然无法更改。)

    因此,如果您希望有一个变量在变量的生命周期内引用不同大小的数组,则它不能具有数组类型。您必须将其声明为指针类型(在本例中为 Thing **)。然后必须动态分配指针指向的元素的数组,并且您必须对分配进行内存管理。这基本上就是chrqlie的答案所显示的。我不确定您正在使用的这个 Arduino 中使用了什么动态分配机制,因为您说它是多种语言的混合,但在 C++ 中您将使用 new []/delete [] 而在 C 中您将使用 @ 987654328@/free动态分配。

    【讨论】:

      【解决方案4】:

      你可以只用静态初始化做很多事情,例如(这是一个双向链表):

      struct list {
              struct list *prev;
              struct list *next;
              int val;
              };
      
      struct list arr[] =
      { {arr+1, arr+2, 1} 
      , {arr+3, arr+4, 2} 
      , {arr+5, arr+6, 3} 
      , {arr+3, arr+4, 4} 
      , {arr+3, arr+5, 5} 
      , {arr+4, arr+6, 6} 
      , {arr+5, arr+6, 7} 
              };
      

      如果你想在数组中有额外的空间,你可以使用哨兵来让你的代码对未使用空间的开始处进行罚款:

      struct list arr[ 100] =
      { {arr+1, arr+2, 1}
      , {arr+3, arr+4, 2}
      , {arr+5, arr+6, 3}
      , {arr+3, arr+4, 4}
      , {arr+3, arr+5, 5}
      , {arr+4, arr+6, 6}
      , {arr+5, arr+6, 7}
      , { NULL, NULL, -1}
              };
      

      ...或者滥用预处理器作为行计数器:

      struct list arr[ 100] =
      # /* reset preprocessor line counter */
      # 0 "omg"
      { {arr+1, arr+2, 1}
      , {arr+3, arr+4, 2}
      , {arr+5, arr+6, 3}
      , {arr+3, arr+4, 4}
      , {arr+3, arr+5, 5}
      , {arr+4, arr+6, 6}
      , {arr+5, arr+6, 7}
              };
      unsigned watermark = (__LINE__ -1);
      

      ...当然,上面的内容可以改变,使用指定的初始化语法。

      顺便说一句:这不是一个 DoublyLinkedList,(偏移量看起来不对),但你明白了......

      【讨论】:

      • 谢谢!如果我想这样做,但将 arr 分配在堆上而不是堆栈上,我该怎么做?
      • 那是不可能的。堆分配需要代码,你需要调用malloc(),或者至少是brk()。同样:您不能在初始化程序中使用代码(调用函数)。 (除了有时在 c++ 中,使用构造函数)
      猜你喜欢
      • 2018-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-28
      相关资源
      最近更新 更多