与起初看起来比后来看起来更可怕的一切一样,克服最初的恐惧的最佳方法是让自己陷入未知世界的不适中!毕竟,有时候是我们学习最多的时候。
不幸的是,有局限性。例如,当您仍在学习使用功能时,就不应扮演老师的角色。我经常从那些看似不知道如何使用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);当您完成它!