我正在做一个关于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]'
的
这是怎么回事?我怎样才能使它发挥作用?
答案 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,(偏移看起来不对),但你明白了......