我很难在数组上实现通用的'map'函数。 我从以下草案开始:
void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem)
{
unsigned int i = 0, j = 0;
void * temp = malloc(elem);
for(i = 0; i<n, i++)
{
temp = (f)((char *) src) + i));
for(j = 0; j < elem; j++)
{
*(((char *) dest) + i) = *(((char *) temp) + i);
}
}
free(temp);
}
我理解为什么它不正确 - 我会在给它'f'之前投入(char *) - 但我现在已经失去动力并且无法提出解决方案。 (我在学习C的过程中这样做)
我的理由是获得'f'的结果,并逐字节地将其复制到dest [i]。
你能给我一些提示吗?
答案 0 :(得分:18)
你的第一个问题是,你在一些表达方式中做得太多了。你需要分解它。
void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem)
{
unsigned int i = 0, j = 0;
void * temp = malloc(elem);
char* csrc = (char*)src;
char* cdest = (char*)dest;
char* ctemp = (char*)temp;
for(i = 0; i<n; i++)
{
csrc++;
cdest++;
ctemp++;
temp = f(csrc);
for(j = 0; j < elem; j++)
{
cdest[i] = ctemp[i];
}
}
free(temp);
}
现在是你的第二个问题。你malloc一个缓冲区,然后你..分配给那个指针?反复?然后只释放最后一个f调用的结果?这完全没必要。
void MapArray(void * src, void * dest, void * (f)(void *), size_t n, size_t elem)
{
unsigned int i = 0, j = 0;
char* csrc = (char*)src;
char* cdest = (char*)dest;
for(i = 0; i<n; i++)
{
csrc++;
cdest++;
char* ctemp = (char*)f(csrc);
for(j = 0; j < elem; j++)
{
cdest[i] = ctemp[i];
}
}
}
现在是你的第三个问题。你传入指针 - 但只传给char。你没有传递空白*。这意味着您的函数不能是通用的 - f不能应用于任何东西。我们需要一个void * s数组,以便该函数可以将任何类型作为参数。我们还需要将类型的大小作为参数,以便我们知道向dest移动的距离。
void MapArray(void ** src, void * dest, void * (f)(void *), size_t n, size_t sizeofT)
{
for(unsigned int i = 0; i < n; i++) {
void* temp = f(src[n]);
memcpy(dest, temp, sizeofT);
dest = (char*)dest + sizeofT;
}
}
我们还有另一个问题 - 临时的记忆。我们不释放它。我们也不会将用户数据参数传递给f,这将允许它返回我们不需要释放的堆分配内存。 f可以工作的唯一方法是返回一个静态缓冲区。
void MapArray(void ** src, void * dest, void * (f)(void *, void*), void* userdata, size_t n, size_t sizeofT)
{
for(unsigned int i = 0; i < n; i++) {
void* temp = f(src[n], userdata);
memcpy(dest, temp, sizeofT);
dest = (char*)dest + sizeofT;
}
}
现在f可以运行几乎任何它喜欢的东西,并保持它需要的任何状态。但我们仍然没有释放缓冲区。现在,f返回一个简单的结构,告诉我们是否需要释放缓冲区。这也允许我们在不同的f。
调用中释放或不释放缓冲区typedef struct {
void* data;
int free;
} freturn;
void MapArray(void ** src, void * dest, freturn (f)(void *, void*), void* userdata, size_t n, size_t sizeofT)
{
for(unsigned int i = 0; i < n; i++) {
freturn thisreturn = f(src[n], userdata);
void* temp = thisreturn.data;
memcpy(dest, temp, sizeofT);
dest = (char*)dest + sizeofT;
if (thisreturn.free)
free(temp);
}
}
但是,我仍然不明白这个功能的目的。所有这些都取代了简单的for循环?您尝试替换的代码比调用函数的代码更简单,并且可能更高效,并且肯定更强大(例如,它们可以使用continue / break)。
更重要的是,C真的很糟糕这种工作。 C ++好多了。例如,将函数应用于数组的每个成员都非常简单。
答案 1 :(得分:2)
有一个原因,在C标准库中没有这么多 - 在C语言中几乎不可能做到这一点。你不能将结果“逐字节”复制到dest[i]
- 由于您已将dest
投射到char *
,因此它只指向一个char
(字节)。
据推测,elem
的大小是f
返回的大小,而n
是src
和dest
中元素的数量。在这种情况下,你的代码并不太远,但是(正如你已经猜测的那样)你操纵指针的方式(特别是转换为char *
)不会削减它。 / p>
然而,即使你修复了这个问题,你还会遇到另一个问题:从f
分配返回类型,而不知道类型真的(真的)很难。事实上,关于我能想到的唯一方法是将这些代码包装成宏而不是:
#define MapArray(s, d, f, n) \
do { \
unsigned i; \
for (i = 0; i<n; i++) \
d[i] = f(s[i]); \
} while (0)
您可以使用以下内容:
int f(int a) { return a + 100; }
#define elements(array) (sizeof(array)/sizeof(array[0]))
int main() {
unsigned i;
int x[] = { 0, 1, 2, 3};
int y[elements(x)];
MapArray(x, y, f, elements(x));
for (i=0; i<elements(x); i++)
printf("%d\n", y[i]);
return 0;
}
注意:我不推荐这个。这个是一种方法来做你所要求的,但正如我所说的那样,这几乎不可能在C中做得很好。这段代码在某种程度上有效,但IMO确实如此没有资格做好这份工作。
答案 2 :(得分:1)
j
上的循环应该是什么