是否可以在纯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;
}
是否可以将数据类型作为参数提供,以便我可以为该数据类型使用malloc内存并将其作为给定数据类型动态地转换为数组?
提前致谢,
Marnix van Rijswijk
答案 0 :(得分: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文件。
答案 1 :(得分:2)
男孩,这听起来像是C ++的工作。
我认为你在C中最接近的是不通过类型,而是传递大小(sizeof(type))。
您可以使您的函数更通用,以便它可以执行它需要做的事情,如果它只知道数组中每个项目的大小。这就是像bsearch()这样的函数的工作方式。
答案 2 :(得分:2)
实现这一目标的一种方法是使用所谓的X-macros。
Here是使用这种技术的(可能是错误的)通用矢量实现。
然后用作
// 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);
答案 3 :(得分:0)
基本上,我最终开发了预处理器。我想我有点成功:我确实为几个最重要的通用数据结构完成了一些宏表示法。
我绝对没有完成(至少以任何自动方式)是以递归方式运行宏 - 即创建数组数组或散列数组等。这是由于有趣的咳嗽疯狂咳嗽 C预处理器宏的语义。
如果您有兴趣,请输入以下代码:https://github.com/christianfriedl/CGenerics/blob/master/src/cgArray.h
答案 4 :(得分:0)
因此,对于没有自己声明类型的对象,有一个“有效类型”的概念。 (随着它的震动,它们几乎只由“ * alloc指针的另一端”和一些奇怪的联合规则组成)
基本上,此类对象的“有效类型”是您最后一次分配给它的对象,而不计算由于原因而为char
或char[]
的时间。
一个有趣的交互作用与声明结构类型的规则有关。也就是说,您可以自由地重新声明相同的标签名(或缺少标签名),并且每个声明都引入了一个全新的类型(过去的名称已被遮盖,但是具有旧类型的对象不会得到重新解释)。
因此您可以执行以下操作:
# 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;
}
(但是,人们可能会指责您滥用您的宏特权,而且他们可能并不完全错误)