【问题标题】:Passing any array type to a function in C [closed]将任何数组类型传递给C中的函数[关闭]
【发布时间】:2016-04-21 22:07:32
【问题描述】:

我正在尝试编写一个函数,对给定的任何数字数组进行排序。 问题是 C 需要知道数据类型才能正确地遍历数组,因为它的“指针性质”。 有什么方法可以在不知道类型的情况下传递任何数组?也许使用 void 类型?

void ordenation (void *array, ...) {}

【问题讨论】:

  • 既然你必须在你的函数中取消引用你的指针,为什么不传递正确的类型呢?显示您的代码并提供更多信息。要么这是一个 XY 问题,要么你的意图不明确。
  • 什么是戒律?
  • 这与指针无关,而是因为 C 是静态类型的。尝试用 C 编写全通用代码是一个非常糟糕的主意。如果愿意,可以使用 Python 等动态类型语言。
  • 可能有C11's _Generic

标签: c arrays function


【解决方案1】:

以下是我对您的问题的理解,如果不是,请在下方回复。您正在尝试在 C 中创建一个函数,该函数可以接受多种数字类型(float、int 等)的数组。

这称为函数重载。可以通过 _Generic 运算符在 C11 中执行此操作。见function overloading in C

另一种选择是创建具有不同名称的函数,所有函数都具有不同的参数列表。所以:

    void ordenation_i(int *array);
    void ordenation_f(float *array);

另一种方法是使用 void* 类型。这意味着您可以将任何指针传递给它,它可能不是您想要的。您必须将 void* 转换回指向其他东西的指针,例如浮点数。如果该操作失败,您可能会遇到问题。

    void ordenation(void *array){
      float* array_casted = (float*) array; 
      // Do stuff
    }

这段代码的问题是现在数组只能作为浮点数组使用。

最后,您也可以只使用 C++ 编译器。它应该编译任何 C 代码,并且默认情况下您会获得函数重载。

    void ordenation(int array[]){
      //do stuff
    }

    void ordenation(float array[]){
      //do stuff
    }

【讨论】:

    【解决方案2】:

    您可以绝对安全地使用void * 将指向任何对象的指针传递给这样的函数。正如其他人所指出的那样,问题在于,一旦进入该函数,您就必须对该对象执行某些操作,并且您需要知道执行该操作的类型,因此即使您不需要该类型要将指针传递给数组,您将需要以某种方式完成任何实际工作。

    正如另一个答案所述,您可以使用 C11 泛型来做到这一点,但另一种可能性是不仅传递指向数组的指针,而且还传递指向要在其上执行的代码的指针,使用函数指针。

    例如,下面的代码将为任何数值数组的每个元素添加两个(我只为intlongdouble 实现了它,但对于其余的标准数值类型实现它是微不足道的)。 add_two() 函数本身永远不知道它得到的是什么类型的数组。但要实现这一点,您还必须将指针传递给 知道的函数:

    #include <stdio.h>
    
    void add_two(void * array, size_t sz, void (*add_func)(void *, size_t));
    void add_two_int(void * array, size_t idx);
    void add_two_long(void * array, size_t idx);
    void add_two_double(void * array, size_t idx);
    
    int main(void)
    {
        int n[] = {1, 2, 3, 4, 5};
        add_two(n, 5, add_two_int);
        for ( size_t i = 0; i < 5; ++i ) {
            printf("%zu: %d\n", i, n[i]);
        }
    
        long l[] = {1L, 2L, 3L, 4L, 5L};
        add_two(l, 5, add_two_long);
        for ( size_t i = 0; i < 5; ++i ) {
            printf("%zu: %ld\n", i, l[i]);
        }
    
        double d[] = {1.0, 2.0, 3.0, 4.0, 5.0};
        add_two(d, 5, add_two_double);
        for ( size_t i = 0; i < 5; ++i ) {
            printf("%zu: %f\n", i, d[i]);
        }
    
        return 0;
    }
    
    void add_two(void * array, size_t sz, void (*add_func)(void *, size_t))
    {
        for ( size_t i = 0; i < sz; ++i ) {
            add_func(array, i);
        }
    }
    
    void add_two_int(void * array, size_t idx)
    {
        int * n = array;
        n[idx] += 2; 
    }
    
    void add_two_long(void * array, size_t idx)
    {
        long * l = array;
        l[idx] += 2; 
    }
    
    void add_two_double(void * array, size_t idx)
    {
        double * d = array;
        d[idx] += 2; 
    }
    

    带输出:

    paul@horus:~/src/sandbox$ ./genarray
    0: 3
    1: 4
    2: 5
    3: 6
    4: 7
    0: 3
    1: 4
    2: 5
    3: 6
    4: 7
    0: 3.000000
    1: 4.000000
    2: 5.000000
    3: 6.000000
    4: 7.000000
    paul@horus:~/src/sandbox$ 
    

    当然,在这个简单的示例中,与仅编写 add_two_int() 和朋友并直接使用它们相比,编写 add_two() 函数并没有太多真正的好处。但是在一个更复杂的示例中,例如,您希望在库中拥有类似 add_two() 的内容,那么这是一种无需修改 add_two() 或重建和重建即可处理任意新类型的方法。重新部署您的库。

    另外,我将函数命名为add_two(),但显然它只是依次对每个元素执行您提供给它的任何操作。因此,您可以编写函数subtract_two_int(void * array, size_t idx),例如,将其传递给add_two(),它实际上会从每个元素中减去两个,尽管名称不同。

    【讨论】:

    • 通常你也会传递元素的大小,传递一个对一个项目(而不是数组)进行操作的函数,并在每个项目上进行迭代。见qsort
    【解决方案3】:

    您可以创建函数void ordenation (void *array),并将任意数据类型的数组传递给函数,只要在调用函数时将输入数组转换为ordenation ((void*)array)。如果您希望能够在函数中使用数组,您可能应该添加第二个输入来表示相应数组的数据类型。 (我假设这是因为 C 不允许函数重载?)

    【讨论】:

    • 将任意指针投射到int * 并期望它工作是不行的。这就是void * 的用途。
    • 很公平,我已经编辑了我的答案。
    猜你喜欢
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多