简体   繁体   English

如何在C中实现将名称与void函数关联的映射?

[英]How to implement map that associates a name with void function in C?

After reading Structure and Interpretation of Computer Programs (SICP) I decided to find a way to implement some of these functional programming techniques using C. I tried to write a program that makes a pair whose first argument is a name of the function and second arg is any function that takes one arg and returns one arg. 在阅读了《计算机程序的结构和解释》(SICP)之后,我决定找到一种方法来使用C来实现其中一些功能编程技术。我试图编写一个程序,该程序生成一对,其第一个参数是函数的名称,第二个arg是需要一个arg并返回一个arg的任何函数。 Using implementation below I was expecting to see an output like: 使用下面的实现,我期望看到类似以下的输出:

fact(7) = 5040
fib(7) = 13

but instead I am getting 但是我得到了

fact(7) = 5040
fib(7) = 0

along with warnings 以及警告

$ cc map.c
map.c: In function ‘main’:
map.c:41:17: warning: assignment from incompatible pointer type [enabled by default]
   maps[0].f_ptr = &fact;
                 ^
map.c:43:17: warning: assignment from incompatible pointer type [enabled by default]
   maps[1].f_ptr = &fib;
                 ^
map.c:47:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
       ans = (int) maps[i].f_ptr((int) num);
       ^
map.c:47:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:47:13: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
       ans = (int) maps[i].f_ptr((int) num);
             ^
map.c:52:7: warning: passing argument 1 of ‘maps[i].f_ptr’ makes pointer from integer without a cast [enabled by default]
       ans2 = (int) maps[i].f_ptr((int) num);
       ^
map.c:52:7: note: expected ‘void *’ but argument is of type ‘int’
map.c:52:14: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
       ans2 = (int) maps[i].f_ptr((int) num);

during compilation. 在编译过程中。 Looking at the code I don't see the problem but then again I haven't used C in quite some time. 查看代码,我看不到问题,但是又有一段时间我没有使用C了。 Is there a better way to implement such a construct and why is fib(7) printing a 0 instead of 13? 有没有更好的方法来实现这种构造,为什么fib(7)打印0而不是13?

Here's my code: 这是我的代码:

struct Map
{
  char* name;
  void* (*f_ptr)(void*);
};

int fact(int a) {
    if (a == 0)
      return 0;
    if (a == 1)
      return 1;
    return a * fact (a-1);
}

int fib(int a) {
  if (a == 0)
    return 0;
  if (a == 1)
    return 1;
  return fib(a-1) + fib(a-2);
}

int findFunc (char* str, struct Map map)
{
  if (map.name == str)
    return 1;
  return 0;
}

int main()
{
  int i = 0;
  int ans = 0;
  int ans2 = 0;
  int num = 7;

  struct Map maps[2];
  maps[0].name = "fact";
  maps[0].f_ptr = &fact;
  maps[1].name = "fib";
  maps[1].f_ptr = &fib;

  for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
    if (findFunc("fact", maps[i]))
      ans = (int) maps[i].f_ptr((int) num);
  }

  for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {
    if (findFunc("fib", maps[i]))
      ans2 = (int) maps[i].f_ptr((int) num);
  }

  printf("fact(%d) = %d\n", num, ans);
  printf("fib(%d) = %d", num, ans2);
  return 0;
}

String comparisons 字符串比较

This is not how you do string comparison in C. 这不是在C中进行字符串比较的方式。

if (map.name == str)

This is how you do string comparison in C. 这是在C中进行字符串比较的方式。

if (0 == strcmp(map.name, str))

Because strings in C are just pointers to characters, map.name == str checks if map.name and str are identical pointers (point to the same block of memory), not whether what they point to is the same. 因为C中的字符串只是指向字符的指针, map.name == str检查map.namestr是否为相同的指针(指向相同的内存块),而不是它们指向的指针是否相同。

for loops for循环

Your code is probably reporting fib(7) = 0 because it's failing to find fib. 您的代码可能报告fib(7) = 0因为它找不到fib。 One possible culprit is the string comparison issue I mentioned. 可能的罪魁祸首是我提到的字符串比较问题。 However, your for loop syntax is also odd: 但是,您的for循环语法也很奇怪:

for (i; i < (sizeof(maps)/sizeof(maps[0])); i++) {

You don't set i to anything, so this means, "Starting from wherever i happens to be, do the following..." 您没有将i设置为任何值,所以这意味着,“从我碰巧的地方开始,请执行以下操作……”

To loop over all of maps, use this: 要遍历所有地图,请使用以下命令:

for (i = 0; i < (sizeof(maps)/sizeof(maps[0])); i++) {

type warnings 键入警告

As @alk said in a comment, the reason you're getting all of those warnings is because you've declared a function type of void* (*f_ptr)(void*); 正如@alk在评论中所说,得到所有这些警告的原因是因为您已声明一个函数类型void* (*f_ptr)(void*); , even though your functions are int (*)(int) . ,即使您的函数是int (*)(int) If you want to keep using void* to allow different types, and you're careful enough with your types to make this work, then you can add casts to silence the warnings. 如果您想继续使用void*来允许不同的类型,并且您对类型足够谨慎以使其起作用,那么可以添加强制类型转换以使警告消失。

maps[0].f_ptr = (void *(*)(void*)) &fact;
ans2 = (int) maps[i].f_ptr((void*) num);

Etc. 等等。

Better implementations? 更好的实现?

A "real" implementation of mapping functions to names would use a hash table, instead of linearly searching for matching names. 映射功能到名称的“实际”实现将使用哈希表,而不是线性搜索匹配的名称。 Implementing a hash table in C would add complexity and may not be worth it for this exercise. 在C中实现哈希表会增加复杂性,在本练习中可能不值得。

but instead I am getting 但是我得到了

[...] [...]

 fib(7) = 0 

The code misses to initialise i to 0 for the 2nd for -loop. 代码偏出初始化i0为第二for -loop。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM