C - 动态数组处理建议

时间:2014-12-31 00:20:15

标签: c arrays realloc

我目前正在学习C,作为一个有更多高级语言经验的人。

  

在考虑了你的一些评论并做了一些测试和改进之后,我想出了一个更好的解决方案(向下滚动)。

     

但建议和评论仍然非常受欢迎。

那就是说,我在C中使用动态数组处理有点挣扎。我把它归结为一点,我非常喜欢,只需用NULL终止每个数组并在必要时使用realloc

基本上我正在寻求建议:除了显而易见的(不能使用NULL值作为数据值)之外,是否存在任何缺点(请参见下面的示例代码)?

#include "stdlib.h"

int array_length(void* array)
{
    int i;
    for (i = 0; ((void**)array)[i]; i++);
    return i;
}

void array_add(void* array, void* item)
{
    int size = array_length(array);
    realloc(array, sizeof(item) * (size + 2));

    ((void**)array)[size] = item;
    ((void**)array)[size + 1] = NULL;
}

void* array_new(){
    void** array = malloc(sizeof(NULL));
    array[0] = NULL;
    return array;
}

#include "stdio.h"

void print_items(char** array){
    printf("%i - [", array_length(array));
    for (int i = 0; array[i]; i++){
        printf("\"%s\"", array[i]);
        if (array[i+1])
            printf(", ");
    }
    printf("]\n");
}

int main(){
    char** str_list = array_new();

    print_items(str_list);
    array_add(str_list, "Something!");
    print_items(str_list);
    array_add(str_list, "Another Thing.");
    print_items(str_list);
}

更好的版本(更新!)

在阅读完答案并自己调试之后,我想出了一个新版本,主要基于下面提到的struct方法。

看看,告诉我,我现在做错了什么。 :)

#include "stdlib.h"
#include "assert.h"

typedef void* Any;

typedef struct {
    Any* items;
    int count;
} List;

List* list_new(){
    List* list = malloc(sizeof(List));
    list->items = NULL;
    list->count = 0;
    return list;
}

void list_add(List* list, Any element){
    int count = list->count + 1;
    list->items = realloc(list->items, count * sizeof(element));
    list->items[count-1] = element;
    list->count = count;
}

void list_free(List* list){
    if (list){
        if (list->items) free(list->items);
        free(list);
    }
}

void list_each(List* list, void (*callback)(List*, Any, int)){
    for (int i = 0; i < list->count; i++){
        callback(list, list->items[i], i);
    }
}

// Sample usage

#include "stdio.h"

void debug_item(List* list, Any item, int index){
    if(index > 0) printf(", ");
    printf("\"%s\"", item);
}

void debug(List* list){
    printf("%i : [", list->count);
    list_each(list, debug_item);
    printf("]\n");
}

int main(){
    List* cats = list_new();
    debug(cats);
    list_add(cats, "Baltazar");
    list_add(cats, "Scar");
    list_add(cats, "Garfield");
    debug(cats);
    list_free(cats);
}

2 个答案:

答案 0 :(得分:2)

你的array_length是O(N)。如果在数组中添加大量项目,这将导致二次运行时间,这可能会非常慢。

你可以这样使用结构来存储数组的大小

struct dyn_array {
    size_t array_size; // how many elements fit in the array?
    size_t nelems;     // how much array space are we using now? 
    int *elems; //or void*, you know the drill...
}

此方法的一个好处是您不再需要使用NULL终止符。它还允许您使用int(或其他任何)数组,而不仅仅是指针数组。

答案 1 :(得分:0)

这就是羊角面包的意思:

#define NULL 0 // in some include file.

这很不寻常,但可能。现在假设0是一个4字节的int,而void **数组是一个8字节的指针:

void* array_new(){
    void** array = malloc(sizeof(NULL)); // this works
    array[0] = NULL;                     // this write 8 bytes
    return array;
}

array[0]=NULL将0解释为8字节指针,并将其写入分配的4个字节以及更高的字节。