4

是否可以在纯 ANSI-C 中复制通用数组?

我有这个结构,它包含一个数组(目前用于浮点数)和一些变量,如数组中突变的大小和容量。

typedef struct _CustomArray
{
    float* array; //the array in which the objects will be stored
    int size; //the current size of the array
    int capacity; //the max capacity of the array
} CustomArray; 

我使用这个结构,所以我可以在纯 C 中创建一个数组,我可以在其中添加/删除项目,在需要时动态扩展数组大小等等。“标准”数组所做的所有事情,除了它仅在 C 中制作。现在我想做这个,这样当你初始化这个结构时,你可以设置它应该保存的元素的数据类型,此时它只能存储浮点数据类型,但我想让它可以存储任何数据类型/其他结构。但我不知道这是否可能。

此时制作这个数组的函数是:

CustomArray* CustomArray_Create(int initCapacity, /*type elementType*/)
{
    CustomArray* customArray_ptr; //create pointer to point at the structure
    float* internalArray = (float*)malloc(sizeof(float) * initCapacity); //create the internal array that holds the items
    if(internalArray != NULL)
    {
        CustomArray customArray = { internalArray, 0, initCapacity }; //make the struct with the data
        customArray_ptr = &customArray; //get the adress of the structure and assign it to the pointer
        return customArray_ptr; //return the pointer
    }
    return NULL;
}

是否可以将数据类型作为参数提供,以便我可以为该数据类型分配内存并将其动态转换为数组中的给定数据类型?

提前致谢,

马尼克斯·范·赖斯韦克

4

5 回答 5

8

您的代码有一个严重的问题...您正在返回局部变量(CustomArray)的地址,并且当函数返回该变量时,该变量被破坏,因此您无法继续将其与指针一起使用。您还必须 malloc 该结构,以便在函数返回后内存仍然可用。

关于使类型成为参数,您可以使用宏获得一些接近...例如:

#include <stdlib.h> 
#define DefArray(type) \
typedef struct T_##type##Array {\
    type *array; \
    int size, capacity; \
} type##Array; \
static type##Array *type##ArrayCreate(int capacity)\
{\
    type##Array *s = malloc(sizeof(type##Array));\
    if (!s) return NULL;\
    s->array = malloc(sizeof(type) * capacity);\
    if (!s->array) { free(s); return NULL; }\
    s->size=0; s->capacity = capacity;\
    return s;\
}

然后你可以这样使用它

#include "customarray.h"
DefArray(float);
DefArray(double);

void foo()
{
    floatArray *fa = floatArrayCreate(100);
    ...
}

请注意,您必须使用宏来定义所有自定义函数。另请注意,这种方法将复制每个模块中的代码(我会说这不是一个大问题,但如果您不能使用 C++,那么您的目标平台可能非常小)。使用稍微复杂一点的方法,您可以为实现生成单独的 .h 文件和 .c 文件。

于 2010-12-12T18:10:19.393 回答
3

男孩,这听起来确实像是 C++ 的工作。

我认为在 C 中最接近这一点的是不传递类型,而是传递大小(sizeof(type))。

您可以使您的函数更通用,以便它可以做它需要做的事情,如果它只知道数组中每个项目的大小。这就是像 bsearch() 这样的函数的工作方式。

于 2010-12-12T17:56:46.200 回答
2

实现此目的的一种方法是使用所谓的X-macros

是使用这种技术的(可能是错误的)通用向量实现。

然后它被用作

// defining generic parameters
#define PREFIX tv
#define ITEM token
#define NAME token_vector
#include "vector.h"

...
token_vector tv = tv_new(100);
*(tv.front) = some_token;
tv_push_back(&tv, other_token);
于 2010-12-12T18:04:49.813 回答
0

几年前,我在 C 语言中搞砸了泛型编程,只是为了它。

基本上,我最终利用了预处理器。我想我有点成功:我确实为几个最重要的通用数据结构完成了一些宏表示法。

我绝对没有完成(至少以任何自动方式)是递归运行宏 - 即创建一个数组数组或哈希数组等。这是由于 C 预处理器有趣的咳嗽疯狂咳嗽语义宏。

如果你有兴趣,这里的代码:https ://github.com/christianfriedl/CGenerics/blob/master/src/cgArray.h

于 2015-09-02T09:55:03.773 回答
0

因此,对于没有自己声明类型的对象,存在“有效类型”的概念。(正如它所动摇的那样,那些几乎只包含“*alloc 指针的另一端”和一些奇怪的联合规则)基本上,这样一个对象的“有效类型”就是你最后用来分配给它的任何东西,不计算是charchar[]因为原因的次数。

一种有趣的交互与声明结构类型的规则有关。也就是说,您可以自由地重新声明相同的标签名称(或缺少标签名称),并且每个声明都引入了一个全新的类型(过去的名称被遮蔽,但具有旧类型的对象不会被重新解释)。

所以你可以做这样的事情:

# define DECL_VECTOR(NAME,TYPE,SIZE) PUN_STRUCT(NAME,TYPE,SIZE)  INIT_STRUCT(NAME,TYPE,SIZE) 

# define PUN_SIZE sizeof(void*)+sizeof(int)*2


# define PUN_STRUCT(NAME,TYPE,SIZE)                      \
   struct {                                              \
      TYPE (*p)[(SIZE)];                                 \
      int size;                                          \
      int capacity;                                      \
   } *NAME = malloc(PUN_SIZE);                        


# define INIT_STRUCT(NAME,TYPE,SIZE)  do {               \
   if (!NAME) {                                          \
        perror("malloc fail");                           \
        abort();                                         \
   }else {                                               \
        NAME->size = (SIZE);                             \
        NAME->capacity = 0;                              \
        NAME->p = malloc(sizeof(*NAME->p));              \
        if (!NAME->p) {                                  \
            perror("malloc fail");                       \
            abort();                                     \
        }                                                \
        NAME->p = (TYPE(*)[(SIZE)])(NAME->p);            \
   }                                                     \
   }while(false)


int main(int argc, char *argv[]) 
 {

   DECL_VECTOR(vec1,int,8);


    printf("size of handle struct:  %zu,\n\
size of vector array:   %zu,\n\
size of vector element: %zu\n\
address of handle struct: %p,\n\
address of vector array:  %p\n",  sizeof(*vec1),       \
                                  sizeof(*vec1->p),    \
                                  sizeof(*vec1->p[0]), \
                                  vec1,                \
                                  vec1->p);
   free(vec1->p);
   free(vec1);
   return 0;
 }

(however, people may accuse you of abusing your macro privileges, and they may not be entirely wrong)

于 2019-05-07T07:50:12.900 回答