有没有用于动态数组的标准C库?

huangapple go评论54阅读模式
英文:

Is there a standard C library for dynamic arrays?

问题

One of the greatest things about Python is the flexibility of dynamic arrays (lists).

It's so useful I find it hard to believe there isn't a library for this already included in C. This question indicates that there is no standard library for this. Apparently, glibc includes functionality for queues, but as I'm on a windows machine this is not helpful. As the question is 10 years old, I'm wondering if there's been an update.

Is implementing the functionality yourself still the only way to get something like a Python list or is there a standard C library that allows you to use dynamic arrays?

英文:

One of the greatest things about Python is the flexibility of dynamic arrays (lists).

It's so useful I find it hard to believe there isn't a library for this already included in C. This question indicates that there is no standard library for this. Apparently, glibc includes functionality for queues, but as I'm on a windows machine this is not helpful. As the question is 10 years old, I'm wondering if there's been an update.

Is implementing the functionality yourself still the only way to get something like a Python list or is there a standard C library that allows you to use dynamic arrays?

答案1

得分: 2

目前没有用于动态数组的标准库,但使用realloc()及其相关函数来实现这一功能并不难。

以下是一个你可以开始使用的示例代码:

struct dynamic_array {
    void *array;          
    size_t occupied_size;
    size_t allocated_size; 
};

参见:C中的动态数组

英文:

There is currently no standard library for dynamic arrays, but it's not hard to implement the functionality with realloc() and family.

Here's something you can start with:

struct dynamic_array {
    void *array;          
    size_t occupied_size;
    size_t allocated_size; 
};

See: Dynamic arrays in C.

答案2

得分: 1

C语言中有一种称为"灵活数组成员"的东西:

typedef struct 
{
    size_t size;
    size_t used; 
    int data[];
} int_arr;

int_arr *addsize(int_arr *arr, size_t inc)
{
    size_t newsize = 0;
    size_t newused = 0;

    if (arr)
    {
        newsize = arr->size + inc;
        newused = arr->used;
    }
    arr = realloc(arr, sizeof(*arr) + newsize * sizeof(arr->data[0]));
    if (arr)
    {
        arr->size = newsize;
        arr->used = newused;
    }
    return arr;
}
英文:

C language has something which is called flexible array members:

typedef struct 
{
    size_t size;
    size_t used; 
    int data[];
}int_arr;


int_arr *addsize(int_arr *arr, size_t inc)
{
    size_t newsize = 0;
    size_t newused = 0;

    if(arr)
    {
        newsize = arr -> size + inc;
        newused = arr -> used;
    }
    arr = realloc(arr, sizeof(*arr) + newsize * sizeof(arr -> data[0]));
    if(arr)
    {
        arr -> size = newsize;
        arr -> used = newused;
    }
    return arr;
}

答案3

得分: 1

这是我通常在我的代码中使用的实现:

#define DYNARRAY_GROW(_cell_type, _array, _need, _to_add) do {    \
               if (_array##_len + (_need) >= (_to_add)) {         \
                    _array##_cap += (_to_add);                    \
                    _cell_type *_aux = realloc(_array,            \
                              _array##_cap * sizeof _array[0]);   \
                    if (!_aux) {                                  \
                        /* 错误检查代码 ... */             \
                        ERR("Error growing array " #_array "\n"); \
                    } else {                                      \
                        _array = _aux;                            \
                    }                                             \
               }                                                  \
           } while (0)

之后,我通过以下变量定义一个数组:

    MyCellType *A     = NULL;  /* 指向单元类型的指针 */
    size_t      A_len = 0,     /* 没有元素,空数组 */
                A_cap = 0;
#define ARRAY_A_GROW_INCREMENT        (20) /* 在需要时增长的元素数量 \
                                            * */
    ...
    /* 假设我需要为3个元素增长数组 */
    DYNARRAY_GROW(MyType, A, 3, ARRAY_A_GROW_INCREMENT);
    A[A_len++] = first_element;
    A[A_len++] = second_element;
    A[A_len++] = third_element;
    /* 如果A需要增长,那么给数组的新单元的数量不是3,而是ARRAY_A_GROW_INCREMENT的值(在本例中为20),因此您可以节省对realloc()的调用 */

英文:

Here is the implementation I normally use on my code:

#define DYNARRAY_GROW(_cell_type, _array, _need, _to_add) do {    \
               if (_array##_len + (_need) >= (_to_add)) {         \
                    _array##_cap += (_to_add);                    \
                    _cell_type *_aux = realloc(_array,            \
                              _array##_cap * sizeof _array[0]);   \
                    if (!_aux) {                                  \
                        /* error checking code ... */             \
                        ERR("Error growing array " #_array "\n"); \
                    } else {                                      \
                        _array = _aux;                            \
                    }                                             \
               }                                                  \
           } while (0)

later, I define an array by using the following variables:

    MyCellType *A     = NULL;  /* pointer to cell type */
    size_t      A_len = 0,     /* no elements, empty array */
                A_cap = 0;
#define ARRAY_A_GROW_INCREMENT        (20) /* NUMBER OF ELEMENTS \
                                            * TO GROW IN CASE OF NEED */
    ...
    /* ASSUME I NEED TO GROW THE ARRAY FOR 3 ELEMENTS */
    DYNARRAY_GROW(MyType, A, 3, ARRAY_A_GROW_INCREMENT);
    A[A_len++] = first_element;
    A[A_len++] = second_element;
    A[A_len++] = third_element;
    /* if A has need to grow, the number of new cells given to the array
     * is not 3, but the value of ARRAY_A_GROW_INCREMENT (in this case 20)
     * so you save calls to realloc() */

There's a drawback, although (but this also applies to any kind of array you
can have in this manner):

  • in the reallocation, it is possible that a new memory segment is completely allocated, and all the array contents to be moved to another place in memory. This makes that any other pointer reference that points into the array to be invalid from the reallocation time onwards... and it has been source of some errors I have learned the bad way. Always think that the elements can move, so be careful with pointers that happen to point to elements inside the array (this includes the pointers that are themselves inside the array)
  • If you test your code with a C++ compiler (let's say you use GTest or similar) then you need to cast the realloc() call return value, as the
    void * is not assignment compatible with any other type in that language, as C is. So, in that case, substitute the call to realloc to show as:
_cell_type *_aux = (_cell_type *) realloc(...

huangapple
  • 本文由 发表于 2023年3月15日 19:09:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75743905.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定