在C中对数组实现一个通用的"map"函数

Las*_*irc 10 c arrays function-pointers map

我在数组上实现通用的"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);
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么它不正确 - 我会在给它'f'之前投入(char*) - 但我现在已经失去动力并且无法提出解决方案.(我在学习C的过程中这样做)

我的理由是获得'f'的结果,并逐字节地将其复制到dest [i].

你能给我一些提示吗?

Pup*_*ppy 17

你的第一个问题是,你在一些表达方式中做得太多了.你需要分解它.

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);
}
Run Code Online (Sandbox Code Playgroud)

现在你的第二个问题.你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];
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

现在你的第三个问题.你传入指针 - 但只传给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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们还有另一个问题 - 温度的记忆.我们不释放它.我们也不会将用户数据参数传递给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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我仍然不明白这个功能的目的.所有这些都取代了简单的for循环?您尝试替换的代码比调用函数的代码更简单,并且可能更高效,并且肯定更强大(例如,它们可以使用continue/break).

更重要的是,C真的很糟糕这种工作.C++好多了.例如,将函数应用于数组的每个成员都非常简单.