初始化匿名指针数组

时间:2016-08-03 10:54:45

标签: c arrays pointers arduino initialization

我正在做一个关于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]'

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

4 个答案:

答案 0 :(得分:1)

使用Thing* things[] = {NULL}

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

一旦声明了数组,就无法更改此数组 - 无论是大小还是地址。

你唯一可以改变的是这个数组的内容,即第一个(也是唯一的)元素。

答案 1 :(得分:1)

我希望things指向大小为2的已分配数组,您必须编写3个语句:

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

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

编辑:鉴于对问题的重新修改,答案很简单:全局things数组必须定义为包含2个元素,并且可以在{{1}中初始化有两个陈述:

setup

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

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;
}

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

答案 2 :(得分:1)

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

其次,即使您可以在C中分配一个数组(让我们说它复制了所有元素),您尝试做的事情仍然无法工作,因为您将分配不同数组类型之间 - 大小是数组类型的一部分。 Thing *[1]Thing *[2]是完全不同的类型。如果您有一个数组类型的变量,则在编译时硬编码大小。您的变量things的类型为Thing *[1],并且在编译时硬编码,并且无法更改。 (对于C99 VLA,您可以使用一个数组变量,其大小在编译时不是硬编码的,但在定义数组变量时是固定的,并且在变量的生命周期内仍然无法更改。)

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

答案 3 :(得分:0)

例如,您可以使用静态初始化做很多事情(这是一个双重链接列表):

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);

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

BTW:这不是DoublyLinkedList,(偏移看起来不对),但你明白了......