通过结构数组中的函数指针调用函数

时间:2017-01-06 23:37:18

标签: c arrays pointers struct

我是C的新手,我正在尝试创建一个包含函数指针的结构数组。

从结构中调用函数(并访问成员)直接按预期工作,但通过循环访问它从数组访问它(访问成员工作)。

我已经发现了一个类似的问题,但是我想知道为什么我从各种教程和帖子放在一起的程序在我尝试通过访问数组中的函数来调用我的函数时崩溃了。

structs.h

typedef struct {
  char *functionId;
  void (*callback)(unsigned char *data);
  char *name;
  char *description;
} Function;

typedef struct {
  Function *fArr;
  size_t used;
  size_t size;
} Array;

的main.c

   #include <stdio.h>
#include <stdlib.h>

#include "structs.h" 

   Array functionArray;

void function1(int *i){
    printf("PRINT: %d\n", i);
}

void function2(char *c[]){
    printf("PRINT: %s\n", c);
}

void addFunction(Function f){
    insertFunctionArray(&functionArray, f);
}

int main()
{
    initFunctionArray(&functionArray, 5);

    //create new struct for function and assign function to callback member
    Function fun;
    fun.name = "Function1";
    fun.functionId = "FUNCTION1";
    fun.description = "Description for Function 1";
    fun.callback = &function1; // <-- doesn't seem to matter if I assign it as a value or as a pointer?!

    Function fun2;
    fun2.name = "Function2";
    fun2.functionId = "FUNCTION2";
    fun2.description = "Description for Function 2";
    fun2.callback = &function2;

    fun2.callback("{fun:\"test\"}");

    fun.callback(17);

    //store functions in array
    addFunction(fun);
    addFunction(fun2);

    unsigned int i = 0;
    for(i; i<functionArray.used; i++)
      {
        printf("PRINT: %s\n", functionArray.fArr[i].functionId); // <-- this works
        functionArray.fArr[i].callback("777"); // <-- this doesn't work
        }
      }

    return 0;
}

void initFunctionArray(Array *fa, size_t initialSize) {
  fa->fArr = (Function *)malloc(initialSize * sizeof(Function));
  fa->used = 0;
  fa->size = initialSize;
  unsigned int i = 0;
  for(i; i<initialSize; i++)
      {
          memset(&fa->fArr[i],0,sizeof(Function));
      }
}

void insertFunctionArray(Array *fa, Function f) {
  if (fa->used == fa->size) {
    fa->size *= 2;
    fa->fArr = (Function *)realloc(fa->fArr, fa->size * sizeof(Function));
  }
  // Copy name
  fa->fArr[fa->used].name = (char*)malloc(strlen(f.name) + 1);
      strcpy(fa->fArr[fa->used].name, f.name);
  // Copy ID
  fa->fArr[fa->used].functionId=f.functionId;
  fa->used++;
}

谢谢&amp; BR

1 个答案:

答案 0 :(得分:3)

此代码重新编写函数以获取void *然后,在没有修复的情况下,令人信服地崩溃,因为您在复制时没有分配callback这一小问题Function中的insertFunctionArray()。修复很简单 - 分配回调:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
    char *functionId;
    void (*callback)(void *data);
    char *name;
    char *description;
} Function;

typedef struct
{
    Function *fArr;
    size_t used;
    size_t size;
} Array;

void initFunctionArray(Array *fa, size_t initialSize);
void insertFunctionArray(Array *fa, Function f);

Array functionArray;

static void function1(void *vp)
{
    int *i = vp;
    printf("PRINT: %d\n", *i);
}

static void function2(void *vp)
{
    char *s = vp;
    printf("PRINT: %s\n", s);
}

static void addFunction(Function f)
{
    insertFunctionArray(&functionArray, f);
}

int main(void)
{
    initFunctionArray(&functionArray, 5);

    // create new struct for function and assign function to callback member
    Function fun;
    fun.name = "Function1";
    fun.functionId = "FUNCTION1";
    fun.description = "Description for Function 1";
    fun.callback = &function1; // <-- doesn't seem to matter if I assign it as a value or as a pointer?!

    Function fun2;
    fun2.name = "Function2";
    fun2.functionId = "FUNCTION2";
    fun2.description = "Description for Function 2";
    fun2.callback = &function2;

    fun2.callback("{fun:\"test\"}");

    int v = 17;
    fun.callback(&v);

    // store functions in array
    addFunction(fun);
    addFunction(fun2);

    for (size_t i = 0; i < functionArray.used; i++)
    {
        printf("PRINT: %s (%p)\n", functionArray.fArr[i].functionId, (void *)functionArray.fArr[i].callback);
        functionArray.fArr[i].callback("777");
    }

    return 0;
}

void initFunctionArray(Array *fa, size_t initialSize)
{
    fa->fArr = (Function *)malloc(initialSize * sizeof(Function));
    fa->used = 0;
    fa->size = initialSize;
    for (size_t i = 0; i < initialSize; i++)
    {
        memset(&fa->fArr[i], 0, sizeof(Function));
    }
}

void insertFunctionArray(Array *fa, Function f)
{
    if (fa->used == fa->size)
    {
        fa->size *= 2;
        fa->fArr = (Function *)realloc(fa->fArr, fa->size * sizeof(Function));
    }
    // Copy name
    fa->fArr[fa->used].name = (char *)malloc(strlen(f.name) + 1);
    strcpy(fa->fArr[fa->used].name, f.name);
    // Copy ID
    fa->fArr[fa->used].functionId = f.functionId;
    // Fix!
    fa->fArr[fa->used].callback = f.callback;
    fa->used++;
}

输出:

PRINT: {fun:"test"}
PRINT: 17
PRINT: FUNCTION1 (0x10c724af0)
PRINT: 3618615
PRINT: FUNCTION2 (0x10c724ad0)
PRINT: 777

注意:代码使用命令行在macOS Sierra 10.12.2上使用GCC 6.2.0(必须升级!)进行干净编译:

$  gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition str19.c -o str19 

其他变更

callback函数指针被修改为采用void *参数而不是unsigned char *。两个回调函数function1function2用于匹配回调接口 - 它们采用void *参数并将其转换为适当的类型。在function2上有一个额外的间接层次。必须更改通过function1结构直接调用fun.callback;你不能传递一个简单数字常量的地址。 (你可以使用&#39;复合文字&#39;,我想:fun.callback(&(int){ 17 });。)我需要<string.h>来声明strlen()

其他一切都没有改变。

请注意,我做的第一件事就是在调用之前将函数指针地址添加到打印操作中。当我得到0x0时,没有多久就找出问题所在。

请注意,function1function2最终都会以"777"作为参数进行调用。这就是为什么我将3618615作为循环内function1的输出的原因。那是不好的 - (联合国)幸运的是,C容忍这样的错误。

另请注意,代码会泄漏大量内存。它或多或少是一个MCVE,所以这或多或少是可以原谅的。