【问题标题】:C automatic-expandable array of pointersC 自动可扩展的指针数组
【发布时间】:2011-01-26 01:25:54
【问题描述】:

问题已在页尾回答。完全有效的代码。

你好,我想用 C 做我在标题中提出的问题,但是,我不知道如何完成它。由于模板,我在 C++ 中完成了这项工作,但 à la C。这是功能齐全的 C++ 代码:List.h (simple database)

*我现在想知道是否可以使用 void 指针来模拟代码。问题是我看到一个链接指出应该避免使用 void *,因为它可能造成的麻烦比它所能解决的要多。

基本上它是一个存储指向变量本身的指针的“智能数组”。 如果我知道每个指针的大小和指向的每个结构的大小,那么简单的 malloc 和 realloc 应该可以吗?

typedef struct
{
  void **list;

  // internal
  int last_item_index;
  size_t element_size; // size of each pointer
  int elements;        // number of currently allocated elements
  int total_size;      // >= #elements so that we don't have to always call malloc
  int tweak_request_size; // each time the list grows we add this # of elements

} List;
// a shot at an addCopy function
// it deepcopies the object you pass in
List_addCopy(List *db, void *ptr_to_new_element)
{
  ... // grow **list
  // alloc and copy new element
  db->list[db->last_item_index+1] = malloc(element_size); // WORKS?
  // HOW TO COPY THE ELEMENT TO HERE IF IT IS A STRUCTURE FOR INSTANCE???
  ...
}

or
// a shot at an assign function 
// (allocate the elements yourself then pass the pointer to the List)
List_assign(List *db, void *ptr_to_new_element)
{
  db->List = realloc(db->List, element_size*(elements+tweak_request_size));
  db->List[db->last_item_index+1] = ptr_to_new_element;
}

// Usage example

List db; // our database
struct funky *now = (funky*)malloc(sizeof(funky));

funky->soul = JamesBrown;

List_addCopy(db, funky);

if (list[0]->soul == JamesBrown)
  puts("We did It! :D");

如果我将所有内容分配到外部并仅将指针传递给列表,我想唯一的问题是 void **。

List_add 可能吗?仅使用执行元素分配和/或复制它的回调?

List_assign 可能吗?我不想做很多工作,最终得到不可靠的软件。

非常感谢并为写作中的卷积感到抱歉:p

【问题讨论】:

  • 如果你知道元素的大小,并且它是一个简单、扁平的数据结构(没有指向任何需要复制的东西的指针),只需 memcpy 结束。
  • @Pemdas:我相信我确实提到过。
  • 这不会造成问题吗?使用 void * * ?我看到一个帖子说 void * * 应该避免,因为结果可能会混合:c-faq.com/ptrs/genericpp.htmlThanks

标签: c pointers


【解决方案1】:

您可以通过以下方式避免void*

#include <stdio.h>
#include <stdlib.h>

#define List(T) \
    typedef struct { \
        T** items; \
        int count;  \
    } List_ ## T ;\
    \
    List_ ## T * List_ ## T ## _New() { \
        List_ ## T * list = (List_ ## T *) malloc(sizeof(List_ ## T)); \
        list->count = 0; \
        return list; \
    } \
    \
    void List_ ## T ## _Add(List_ ## T *list, T * data) { \
        printf("%d\n", ++list->count); \
    } \
    void List_ ## T ## _Del(List_ ## T *list, int index) { \
        printf("%d\n", --list->count); \
    }

/* define just one list per type */
List(int);
List(double);

int main()
{
    int a, b, c;
    double d, e;
    List_int *l1;
    List_double *l2;

    l1 = List_int_New();
    List_int_Add(l1, &a);
    List_int_Add(l1, &b);
    List_int_Add(l1, &c);
    List_int_Del(l1, 0);
    List_int_Del(l1, 0);
    List_int_Del(l1, 0);
    free(l1);

    l2 = List_double_New();
    List_double_Add(l2, &d);
    List_double_Add(l2, &e);
    List_double_Del(l2, 0);
    List_double_Del(l2, 0);
    free(l2);

    return 0;
}

这是一个穷人的模板 =)

【讨论】:

  • 谢谢!我明白了,它似乎很容易使用,只是实施起来很痛苦,但我想这很好,因为你只需要做一次;)
  • 我认为这并不难,只是一些额外的 ##\ 。调试它并跟踪编译时错误可能很困难,我认为最好像List_int 那样实现它并先对其进行测试,然后将其设为“模板”。这种方法的另一个问题是列表类型参数不能是指针,因为在生成过程名称时,编译器不会喜欢包含* 的名称,但这可以像我一样通过使指针隐式来解决。
【解决方案2】:

我使用了 Trinidad 的方法,因为我不确定 void ** 是否有效,而且非常好 xD

它工作得很好,但是要避免循环依赖(包括导致“多重引用”的另一个标题)又不妨碍接口太多,所以我放弃了这种方法,尽管我也上传了它@SourceForge ,然后我再次制作了所有内容,这次使用 void 指针,它工作得很好;)不用担心包含两次标题等。就可以了。

顺便说一句,这是链接,请随意使用:List - the smart && generic container

如果有任何疑问,请使用帮助论坛,当我有时间时,我会记录它,但现在我将它用于我的项目。

【讨论】:

    猜你喜欢
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 2014-02-26
    • 2015-11-08
    • 1970-01-01
    • 2014-07-01
    • 2017-06-20
    相关资源
    最近更新 更多