如何创建可以接收不同类型参数的c函数?

时间:2014-01-08 15:14:27

标签: c arrays pointers malloc realloc

我正在研究一个相当旧的软件包(NWChem)的模块,并且不确定从一对相当常用的函数调用中创建函数的最佳方法。主包内部是一组用于操作运行时数据库的函数。我经常使用的对是rtdb_get_infortdb_get来提取有关数据库中一个值的内容的信息并获取实际值。这些函数的标题是:

extern int rtdb_get_info(const int, const char *, int *, int *, char [26]);
extern int rtdb_get(const int, const char *, const int, const int, void *);

它们的调用方式是执行以下操作(忽略返回值):

int nelem, ma_type;
char date[26];

rtdb_get_info(rtdb, "nameofrtdbvalue", &ma_type, &nelem, date)
rtdb_get(rtdb, "nameofrtdbvalue", ma_type, array)

其中rtdb是在其他地方设置的整数,用于指定要访问的数据库,array是要存储“nameofrtdbvalue”中存储的值的数组。在某些情况下,您可能会在进行实际array = malloc(nelem * sizeof *array)来电之前rtdb_get

目前,我使用以下函数来调用此对:

void rtdb_pull(int rtdb, const char *name, void *array) {

  int ma_type;
  int nelem;
  char date[26];

  if (rtdb_get_info(rtdb, name, &ma_type, &nelem, date)) {
    if (rtdb_get(rtdb, name, ma_type, nelem, array)) 
      printf("Retrieved %s from rtdb.\n", name);
    else 
      printf("%s is in rtdb, but not retrievable.\n", name);
  }
  else 
    printf("Couldn't get info on %s from rtdb.\n", name);
}

以下是我将分配内容并致电rtdb_pull的示例方式。在这种情况下,我将从数据库中提取一个 3 * npoints 双精度数组,然后将它们传递给其他一些使用数组 coords 执行某些操作的函数。通常这会发生在我需要重新分配内存的循环中。

double *coords=malloc(sizeof *coords);
int npoints, rtdb;
int i, nloops;
char buf[32];

get_rtdb(&rtdb); //Just something that gets the integer for the runtime database
for (i=0;i<nloops;i++) {
  get_npoints(&npoints);
  coords=realloc(coords,npoints * sizeof *coords);
  rtdb_pull(rtdb,"geometryname",coords);
  use_coords(coords);
}
free(coords);

rtdb_pull是我在学习c时写的第一个函数之一,我注意到我称之为越多,我就越有可能得到分段错误,所以我想重写它,但我不确定最好的方法。似乎调用它会导致内存泄漏,但我不确定原因。也许这与我将一个指针分配给一个双精度数组的内存指向void *的事实有关?如果是这样,我不确定如何解决这个问题(并且不断调用这对函数真的很烦人)。

有任何想法或建议吗?

4 个答案:

答案 0 :(得分:1)

使用void *没有错误,当你需要时,它们可以像通用类型那样工作,而且它似乎是你想要的,对吗?

int myfunc(void* data, int op)
{
  double *mycoords;
  if(op == 1) // a way to control the real type 
    mycoords = (double*) data; 
  //...
  return 0;
}

在函数内部,您可以转换或将(void *)转换为您需要的类型。

另一种方法是编写一个带有变量参数列表的函数,这是stdarg手册页中的一个例子:

#include <stdio.h>
#include <stdarg.h>

void
foo(char *fmt, ...)
{
  va_list ap;
  int d;
  char c, *s;

  va_start(ap, fmt);
  while (*fmt)
    switch (*fmt++) {
      case 's':              /* string */
        s = va_arg(ap, char *);
        printf("string %s\n", s);
        break;
      case 'd':              /* int */
        d = va_arg(ap, int);
        printf("int %d\n", d);
        break;
      case 'c':              /* char */
        /* need a cast here since va_arg only
        takes fully promoted types */
        c = (char) va_arg(ap, int);
        printf("char %c\n", c);
        break;
    }
    va_end(ap);
}

答案 1 :(得分:1)

我没有发现您的rtdb_pull方法有任何问题,与void *这样的工作完全没问题。所以也许问题出在其他地方:

  • rtdb_get_infortdb_get坚如磐石且经过充分测试的?
  • 我的代码示例中的循环后没有看到free( coords );语句,这是正常的吗?

答案 2 :(得分:1)

您对rtb_get_info的调用会更新nelem中的值,该值来自上下文,我认为是要存储到数组中的元素数量。但是,您根据npoints的值来确定数组的大小,您知道这些值是否相同?我们无法看到如何设置npoints。

此外,get_npoints()函数看起来不适合C代码。 npoints被声明为一个int,我不知道如何通过调用get_npoints()来更新它,在C ++中我认为它是一个引用,但这是C。

答案 3 :(得分:0)

这句话让我很烦恼:

double *coords=malloc(sizeof *coords);

coords是指向一个或多个双精度的指针很好,但你必须在某处为它分配真实的内存。 sizeof *coords意味着什么?你真的想让malloc()的参数成为你对这个数组所需的总字节数,我不认为你是这么做的。您还需要将返回的指针强制转换为double *。您使用的是非常旧的C编译器,错误检测效果不佳吗?

无论如何,开始清理你的代码,并在整个代码中添加一些注释来解释你想要做的事情。