假设我们有以下结构:
typedef struct array
{
size_t sz_of // sizeof an object;
size_t count;
void* objects;
}Array;
好吧,一个可以包含一组任意类型的数组。以下功能旨在应用于此结构:
Array* ArrayNew(size_t len, size_t sz_of){
Array* a = malloc(sizeof(Array));
if(a == NULL)
return NULL;
a->sz_of = sz_of;
a->count = len;
a->objects = malloc(len * sz_of);
if(a->objects == NULL){
free(a);
return NULL;
}
return a;
}
void ArrayDestroy(Array* a){
free(a->objects);
free(a);
}
void* ArrayGet(Array* a, size_t i){
if(i > a->count)
return NULL;
return (a->objects + a->sz_of * i);
}
void ArraySet(Array* a, void* v, size_t i){
if(i > a->count)
return;
memcpy(a->objects + a->sz_of * i, v, a->sz_of);
}
我们有一个功能:
我添加了一个交换数组的两个元素的函数,但我不确定我是否正确执行。由于char
长度为1个字节,因此我暂时将一个元素存储在char
数组中sz_of
长:
void ArraySwap(Array* a, size_t x, size_t y){
if(x < a->count && y < a->count){
char t[a->sz_of];
memcpy(t, a->objects + a->sz_of * x, a->sz_of);
memcpy(a->objects + a->sz_of * x, a->objects + a->sz_of * y, a->sz_of);
memcpy(a->objects + a->sz_of * y, t, a->sz_of);
}
}
x
和y
是必须交换的对象的索引。
它在我的配置上运行良好,但它是不安全还是非标准的继续进行方式?在全球范围内,如果你看到一些奇怪的,不安全的或非标准的东西,你能指出我吗?
感谢您的回答。
答案 0 :(得分:3)
代码依赖char*
像void*
的指针数学一样。有些编译器将void*
指针数学视为char*
,但最好不要假设非标准行为。
a->objects + a->sz_of * x // not potable.
而是使用unsigned char *
或char *
并考虑固定大小的缓冲区@supercat。这避免了使用可变长度数组(VLA),这是一个无限制的,只有可选支持C11。
void ArraySwap(Array* a, size_t x, size_t y){
if(x < a->count && y < a->count){
unsigned char *xp = a->objects;
xp += x*a->sz_of;
unsigned char *yp = a->objects;
yp += y*a->sz_of;
unsigned char buf[64];
for (size_t i=0; i<a->sz_of; i += sizeof buf) {
size_t sz = a->sz_of - i;
if (sz > sizeof buf) {
sz = sizeof buf;
}
memcpy(t, xp, sz);
memcpy(xp, yp, sz);
memcpy(yp, t, sz);
xp += sz;
yp += sz;
}
}
}
答案 1 :(得分:2)
您不必担心临时阵列的大小。在C99中,it is always true sizeof(char) == 1
。
这意味着堆栈大小上的t
数组将为a->sz_of
个字节。
可能会出现另一个问题。在堆栈上分配t
时,您使用名为VLA (variable-length array)的C99功能。这可能在两种情况下存在问题:
NULL
进行比较)。最后,这可能不是问题,但在ArrayGet
的实现中使用ArraySwap
函数似乎更好,而不是手动计算元素`地址。