与起初看起来比后来看起来更可怕的一切一样,克服最初的恐惧的最佳方法是让自己陷入未知世界的不适中!毕竟,有时候是我们学习最多的时候。
不幸的是,有局限性。例如,当您仍在学习使用功能时,就不应扮演老师的角色。我经常从那些看似不知道如何使用realloc
(即当前接受的答案!)的人那里读到答案,告诉其他人如何不正确地使用它,有时冒充他们忽略了错误处理,尽管这是一个常见的陷阱。需要提到的。这是解释如何realloc
正确使用的答案。请注意,答案是将返回值存储到另一个变量中,以便执行错误检查。
每次调用函数和每次使用数组时,都在使用指针。转换是隐式发生的,如果有的话甚至更可怕,因为我们看不到的东西通常会引起最多的问题。例如,内存泄漏...
数组运算符是指针运算符。array[x]
确实是的快捷方式*(array + x)
,可以分为:*
和(array + x)
。这很可能会使*
您感到困惑。我们可以通过假设x
为进一步消除问题中的加法0
,因此array[0]
成为*array
因为加法0
不会改变值...
...因此我们可以看到*array
等同于array[0]
。您可以在要使用另一个的地方使用它,反之亦然。数组运算符是指针运算符。
malloc
,realloc
并且朋友不会发明您一直使用的指针的概念;他们只是使用它来实现其他一些功能,这是存储时间的另一种形式,最适合您希望大小动态变化的情况。
令人遗憾的是,当前接受的答案也与StackOverflow上其他一些非常有根据的建议背道而驰,与此同时,错过了引入一个鲜为人知的功能的机会,该功能正是这种用例的亮点:灵活数组成员!这实际上是一个非常糟糕的答案... :(
定义时struct
,请在结构末尾声明数组,没有任何上限。例如:
struct int_list {
size_t size;
int value[];
};
这将使您可以将数组的数组与您的数组int
合并为一个数组,这样将count
它们绑定起来非常方便!
sizeof (struct int_list)
会表现得好像value
有一个大小为0,所以它会告诉你该结构的大小与空列表。您仍然需要添加传递到realloc
的大小以指定列表的大小。
另一个方便的技巧是记住它realloc(NULL, x)
等效于malloc(x)
,我们可以使用它来简化我们的代码。例如:
int push_back(struct int_list **fubar, int value) {
size_t x = *fubar ? fubar[0]->size : 0
, y = x + 1;
if ((x & y) == 0) {
void *temp = realloc(*fubar, sizeof **fubar
+ (x + y) * sizeof fubar[0]->value[0]);
if (!temp) { return 1; }
*fubar = temp; // or, if you like, `fubar[0] = temp;`
}
fubar[0]->value[x] = value;
fubar[0]->size = y;
return 0;
}
struct int_list *array = NULL;
我选择struct int_list **
用作第一个参数的原因似乎并不立即显而易见,但是如果您考虑第二个参数,value
则从内部进行的任何更改对于push_back
我们从中调用的函数都是不可见的,对吗?这同样适用于第一个参数,我们需要能够修改我们的array
,不只是在这里,但也可能在其它任何功能/ s,我们把它传递给 ...
array
开始指着什么都没有;它是一个空列表。对其进行初始化与对其进行添加相同。例如:
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
PS 请记住,free(array);
当您完成它!