C 成员为函数指针和空指针的结构的内存分配错误

C 成员为函数指针和空指针的结构的内存分配错误,c,memory-management,function-pointers,void-pointers,C,Memory Management,Function Pointers,Void Pointers,我编写了一个简单的C代码,它使用一个引擎根据用户输入运行两种不同的算法。它使用指向算法方法和对象的函数指针。某个地方有一个我无法追踪的严重内存错误,所以可能是我以错误的方式分配内存。出什么事了 下面是代码的一个最小工作示例(相关部分) main.c #include "engine.h" int main() { char *id = "one"; Engine_t eng; Engine_init(&eng); Engine_select_algorithm(en

我编写了一个简单的C代码,它使用一个引擎根据用户输入运行两种不同的算法。它使用指向算法方法和对象的函数指针。某个地方有一个我无法追踪的严重内存错误,所以可能是我以错误的方式分配内存。出什么事了

下面是代码的一个最小工作示例(相关部分)

main.c

#include "engine.h"

int main()
{
  char *id = "one";

  Engine_t eng;

  Engine_init(&eng);
  Engine_select_algorithm(eng, id);
  Engine_run(eng);
}
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"

typedef struct _Engine
{ 
  void *p_algorithm;

  void (*init)(Engine_t);
  void (*run)(Engine_t);

} Engine;

void Engine_init(Engine_t *eng)
{
  *eng = malloc(sizeof(Engine));

  (*eng)->p_algorithm = NULL;
}

void Engine_select_algorithm(Engine_t eng, char *id)
{
  if ( strcmp(id, "one") == 0 )
    {
      eng->init = Algorithm_one_init;
      eng->run  = Algorithm_one_run;
    }
  else if ( strcmp(id, "two") == 0 )
    {
      eng->init = Algorithm_two_init;
      eng->run  = Algorithm_two_run;
    }
  else
    {
      printf("Unknown engine %s.\n", id); exit(0);
    }

  eng->init(eng);
}

void Engine_run(Engine_t eng)
{
  eng->run(eng);
}

void Engine_set_algorithm(Engine_t eng, void *p)
{
  eng->p_algorithm = p;
}

void Engine_get_algorithm(Engine_t eng, void *p)
{
  p = eng->p_algorithm;
}
#include "engine.h"
#include "algorithm_one.h"

typedef struct _A_one
{ 
  float value;
} A_one;

void Algorithm_one_init(Engine_t eng)
{
  A_one_t aone;
  aone = malloc(sizeof(A_one));
  aone->value = 13.0;

  //int var = 10;

  Engine_set_algorithm(eng, &aone);
}

void Algorithm_one_run(Engine_t eng)
{  
  A_one_t aone;
  Engine_get_algorithm(eng, &aone);

  printf("I am running algorithm one with value %f.\n", aone->value);
  // The code for algorithm one goes here.
}
发动机.h

typedef struct _Engine *Engine_t;
typedef struct _A_one *A_one_t;
引擎.c

#include "engine.h"

int main()
{
  char *id = "one";

  Engine_t eng;

  Engine_init(&eng);
  Engine_select_algorithm(eng, id);
  Engine_run(eng);
}
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"

typedef struct _Engine
{ 
  void *p_algorithm;

  void (*init)(Engine_t);
  void (*run)(Engine_t);

} Engine;

void Engine_init(Engine_t *eng)
{
  *eng = malloc(sizeof(Engine));

  (*eng)->p_algorithm = NULL;
}

void Engine_select_algorithm(Engine_t eng, char *id)
{
  if ( strcmp(id, "one") == 0 )
    {
      eng->init = Algorithm_one_init;
      eng->run  = Algorithm_one_run;
    }
  else if ( strcmp(id, "two") == 0 )
    {
      eng->init = Algorithm_two_init;
      eng->run  = Algorithm_two_run;
    }
  else
    {
      printf("Unknown engine %s.\n", id); exit(0);
    }

  eng->init(eng);
}

void Engine_run(Engine_t eng)
{
  eng->run(eng);
}

void Engine_set_algorithm(Engine_t eng, void *p)
{
  eng->p_algorithm = p;
}

void Engine_get_algorithm(Engine_t eng, void *p)
{
  p = eng->p_algorithm;
}
#include "engine.h"
#include "algorithm_one.h"

typedef struct _A_one
{ 
  float value;
} A_one;

void Algorithm_one_init(Engine_t eng)
{
  A_one_t aone;
  aone = malloc(sizeof(A_one));
  aone->value = 13.0;

  //int var = 10;

  Engine_set_algorithm(eng, &aone);
}

void Algorithm_one_run(Engine_t eng)
{  
  A_one_t aone;
  Engine_get_algorithm(eng, &aone);

  printf("I am running algorithm one with value %f.\n", aone->value);
  // The code for algorithm one goes here.
}
算法_one.h

typedef struct _Engine *Engine_t;
typedef struct _A_one *A_one_t;
算法_one.c

#include "engine.h"

int main()
{
  char *id = "one";

  Engine_t eng;

  Engine_init(&eng);
  Engine_select_algorithm(eng, id);
  Engine_run(eng);
}
#include "engine.h"
#include "algorithm_one.h"
#include "algorithm_two.h"

typedef struct _Engine
{ 
  void *p_algorithm;

  void (*init)(Engine_t);
  void (*run)(Engine_t);

} Engine;

void Engine_init(Engine_t *eng)
{
  *eng = malloc(sizeof(Engine));

  (*eng)->p_algorithm = NULL;
}

void Engine_select_algorithm(Engine_t eng, char *id)
{
  if ( strcmp(id, "one") == 0 )
    {
      eng->init = Algorithm_one_init;
      eng->run  = Algorithm_one_run;
    }
  else if ( strcmp(id, "two") == 0 )
    {
      eng->init = Algorithm_two_init;
      eng->run  = Algorithm_two_run;
    }
  else
    {
      printf("Unknown engine %s.\n", id); exit(0);
    }

  eng->init(eng);
}

void Engine_run(Engine_t eng)
{
  eng->run(eng);
}

void Engine_set_algorithm(Engine_t eng, void *p)
{
  eng->p_algorithm = p;
}

void Engine_get_algorithm(Engine_t eng, void *p)
{
  p = eng->p_algorithm;
}
#include "engine.h"
#include "algorithm_one.h"

typedef struct _A_one
{ 
  float value;
} A_one;

void Algorithm_one_init(Engine_t eng)
{
  A_one_t aone;
  aone = malloc(sizeof(A_one));
  aone->value = 13.0;

  //int var = 10;

  Engine_set_algorithm(eng, &aone);
}

void Algorithm_one_run(Engine_t eng)
{  
  A_one_t aone;
  Engine_get_algorithm(eng, &aone);

  printf("I am running algorithm one with value %f.\n", aone->value);
  // The code for algorithm one goes here.
}
算法_two.h算法_two.c的代码与算法一文件相同

一定有内存错误,因为代码按照给定的方式运行,但是如果我取消注释

//int var = 10;

algoritm\u one.c中的行代码因分段错误而崩溃。

您将错误的内容传递给
引擎集\u算法
。您传递的是局部变量的地址,而不是算法的地址。你需要写:

Engine_set_algorithm(eng, aone);
而且
Engine\u get\u算法
也是错误的。您将按值传递一个指针,并修改该指针。因此调用方无法看到该修改。你需要它是:

void Engine_get_algorithm(Engine_t eng, void **p)
{
  *p = eng->p_algorithm;
}
我认为如果定义一个类型来表示一个算法,代码会更容易。这种类型将只是一个
void*
,但它会使代码更易于阅读。而且,我会让
Engine\u get\u algorithm
返回算法

algorithm Engine_get_algorithm(Engine_t eng)
{
    return eng->p_algorithm;
}

void Engine_set_algorithm(Engine_t eng, algorithm alg)
{
    eng->p_algorithm = alg;
}

您的
Engine\u get\u算法
函数实际上不会得到任何东西,因为
p
是该函数的局部函数。您需要返回算法,或者通过指针.Argh传递
p
,指针
typedef
。这使得你的代码很难阅读。@Sander De Dycker谢谢,你是对的,我已经根据David Heffernan的回答进行了修改。@JensGustedt如果写起来很难,应该很难阅读。。)不,说真的,我认为在.h中的接口和.c.Hm中的实现之间有一个清晰的分离是一个好方法,这只是隐藏了一些东西。在C语言中,当您看到一个没有
*
的接口时,您希望通过值传递东西。在大多数项目中,这样的界面不会通过审查。谢谢,你是对的。我应该自己发现的。你的其他建议也很好。代码现在按预期工作。为可读性定义算法类型绝对是个好主意。非常感谢您迅速而简洁的回答。