A generic dynamic array in C that stores no capacity and needs no struct
A generic dynamic array in C that stores no capacity and needs no struct
C 语言中一种无需结构体且不存储容量的通用动态数组
A generic dynamic array in C that stores no capacity and needs no struct. The following header shows a way to make a generic dynamic array in C with an array of two pointers: the first pointer stores the length of the dynamic array; the second pointer points to the data. 在 C 语言中,有一种无需结构体且不存储容量的通用动态数组实现方式。以下头文件展示了一种利用两个指针的数组来创建通用动态数组的方法:第一个指针存储动态数组的长度,第二个指针指向数据本身。
So, int *vec[2] = { 0 }; is an empty dynamic array of ints. struct person *people[2] = { 0 }; is an empty dynamic array of people. (uintptr_t)vec[0] is the length of the array, vec[1] is the array. The vec_push macro pushes a value at the end of the dynamic array and returns true on success. This code is C23 with statement expressions (a GNU C feature).
因此,int *vec[2] = { 0 }; 就是一个空的整型动态数组,而 struct person *people[2] = { 0 }; 则是一个空的 person 结构体动态数组。其中 (uintptr_t)vec[0] 表示数组长度,vec[1] 指向数组内容。vec_push 宏用于在动态数组末尾添加一个值,并在成功时返回 true。这段代码基于 C23 标准,并使用了语句表达式(GNU C 的一项特性)。
Why is this interesting? First of all, structs aren’t used so you don’t have to invent names for them (e.g. there is no IntVec). Since a pointer is used to store the length of the dynamic array (as a uintptr_t), this relies on implementation-defined behavior, that is the uintptr_t length read from a pointer must be the same length that was stored.
为什么这种方法很有趣?首先,由于不使用结构体,你无需为它们命名(例如,不需要定义 IntVec)。由于使用指针来存储动态数组的长度(作为 uintptr_t),这依赖于实现定义的行为,即从指针中读取出的 uintptr_t 长度必须与存储时的长度一致。
Second of all, capacity isn’t stored at all. Instead, it’s computed on demand when the length of the vec is either zero or a power of two. In this case realloc is called with capacity equal to the next power of two greater than the length. The drawback is that it’s more difficult to “reserve” elements: during pushing, when the length reaches a power of two, realloc is called for the next power of two no matter what, so a larger manual reservation is effectively discarded.
其次,这种方法完全不存储容量信息。相反,当数组长度为零或 2 的幂时,容量会按需计算。在这种情况下,程序会调用 realloc,将容量调整为大于当前长度的下一个 2 的幂。其缺点在于难以“预留”元素:在执行 push 操作时,一旦长度达到 2 的幂,无论如何都会触发 realloc 来分配下一个 2 的幂大小的内存,因此手动进行的更大规模预留实际上会被丢弃。