C automatic-expandable array of pointers
QUESTION ANSWERED AT END OF PAGE. FULLY WORKING CODE.
Hello, I would like to do in C what I have asked in the title, however, I don't know how to accomplish it. I have done this in C++ thanks to templates but à la C. Here is the fully functional C++ code: List.h (simple database)
*I wonder now if with void pointers I can emulate the code. The problem is that I've seen a link stating that void * should be avoided because it can cause more trouble than it can solve.
Basically it is a "smart-array" that stores pointers to the variables themselves. If I know the size of each pointer and the size of each structure pointed to, simple mallocs and reallocs should do right?
typedef struct
{
void **list;
// internal
开发者_如何学Python 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");
If I alloc everything outside and just pass the pointers to the List I guess the only problem is the void **.
Is List_add possible? Only with callbacks that do the alloc of the element and / or copy it?
Is List_assign possible? I don't want to have a lot of work and end up with unreliable software.
Thanks a lot and sorry for the convolution in the writing :p
You can avoid void*
with something like this:
#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;
}
That's a poor man's template =)
I've used Trinidad's method since I wasn't sure void **
would work and it's pretty nice xD
It works perfectly but it is complicated to avoid circular dependencies (including a header in another that results in "multiple reference") without encumbering too much the interface, so I gave up that approach although I've uploaded it too @SourceForge, then I made everything again, this time with void pointers and it works perfectly ;) No worrying about including a header twice, etc. Just works.
Btw, here's the link, use it at your liking: List - the smart && generic container
In any doubt use the help forums, when I have time I'll document it, but for now I'm using it for my projects.
精彩评论