【问题标题】:How do I make a function that accepts different types?如何制作一个接受不同类型的函数?
【发布时间】:2017-10-31 09:14:07
【问题描述】:

我有这个冒泡排序功能:

void bubble_sort(float* array, int length)
{
    int c, d;
    float temp;

    for (c = 0; c < (length - 1); c++) {
        for (d = 0; d < length - c - 1; d++) {
            if (array[d] > array[d + 1]) {
                temp = array[d];
                array[d] = array[d + 1];
                array[d + 1] = temp;
            }
        }
    }
}

如何更改它以便我也可以将它用于double?我希望能够一次传递一个浮点数组,另一次传递一个双精度数组,但它必须是相同的函数。像这样的:

float farr[SIZE];
double darr[SIZE];
...
bouble_sort(farr, SIZE);
bouble_sort(darr, SIZE);

编辑:我重写了排序功能,现在它似乎工作正常。你怎么看?

void bubble_sort(void* generalArray, int lenght_row, char type) 
{ 
int column_sort;
int sorting_process = 0;
if (type == 'f')
{
    float temp; 
    float* array = (float *) generalArray; 
    while (sorting_process == 0)
    {
        sorting_process = 1;
        for (column_sort = 0; column_sort < lenght_row - 1; column_sort++)
        {
            if (array[column_sort] > array[column_sort + 1])
            {
                temp = array[column_sort + 1]; 
                array[column_sort + 1] = array[column_sort];
                array[column_sort] = temp;
                sorting_process = 0;
            }

        }
    }
}
else if (type == 'd') 
{
    double temp; // added
    double* array = (double *) generalArray;
    while (sorting_process == 0)
    {
        sorting_process = 1;
        for (column_sort = 0; column_sort < lenght_row - 1; column_sort++)
        {
            if (array[column_sort] > array[column_sort + 1])
            {
                temp = array[column_sort + 1]; 
                array[column_sort + 1] = array[column_sort];
                array[column_sort] = temp;
                sorting_process = 0;
            }
        }
    }
  }
}

【问题讨论】:

  • 你打算拥有一个混合类型的集合吗?如果您只想对双精度进行排序,请更改函数签名。
  • 那种;查看qsort 的文档。不过,你可能最好创建两个函数。
  • @underscore_d - 好吧,可以使用宏为不同的数据类型生成此函数,然后将其包装在通用选择中,我想。但是模板仍然更好:P
  • 我必须在一个函数中完成它。你看我只是 C 编程的初学者,这是练习之一。 @Ryan 在这种情况下它只会得到浮点类型,但理论上该算法应该能够处理浮点数和双精度数。
  • 点赞this

标签: c algorithm sorting c99


【解决方案1】:

编辑:在编写以下答案时,对 C99 的限制尚不清楚。有了这个限制,教师很可能希望有一个模仿qsort() 的解决方案,具有“比较”功能和sizeof 作为参数传递的数据类型。所以我也写了一个“C99”的答案。

这只需要几个“技巧”。您收到数组void *、处理类型的大小和一个比较函数作为参数。

void bubble_sort( void * array, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )

您需要进行指针运算而不是数组索引,因为您无法将 array 转换为正确的(未知)类型。

为此,您需要unsigned char *(因为在void * 上无法进行指针运算),并将size 添加到这些指针以获取下一个元素。

unsigned char * array_ = (unsigned char *)array;

你调用比较函数而不是自己比较。

// instead of...
if (array[d] > array[d + 1])
// ...you call...
if ( compar( array_[d * size], array_[(d+1) * size] > 0 ) 

您需要memswp 两个元素,而不是处理它们的类型:

static inline void memswp( unsigned char * i, unsigned char * j, size_t size )
{
    unsigned char tmp;
    while ( size )
    {
        tmp = *i;
        *i++ = *j;
        *j++ = tmp;
        --size;
    }
}

// instead of...
temp = array[d];
array[d] = array[d + 1];
array[d + 1] = temp;
// ...you call:
memswp( array[ d * size ], array[ ( d + 1 ) * size ], size );

这是在 C99 成为要求之前的原始答案。我仍然坚持所做的声明。

不,这是不可能的,至少风格不好。您可以将第一个参数作为void *,并有一个附加参数在floatdouble 之间“切换”处理,但这将是几种糟糕的设计。或者您可以将比较“外包”到作为函数指针传递的另一个函数,就像qsort() 那样,但我认为这也不是一个好的设计。

但是,您可以创建一个函数 bubble_sort_float() 和一个函数 bubble_sort_double(),然后将它们“隐藏”在 _Generic macro 后面:

#define bubble_sort(X, length) _Generic((X), \
                               double: bubble_sort_double, \
                               default: bubble_sort_double,  \
                               float: bubble_sort_float  \
)(X, length)

【讨论】:

  • Nota Bene:_Generic 是 C11 扩展。
  • 嗯,我认为这是个好主意。如果您检查数字是否具有数据类型 float 或 double 并取决于它是哪一个,它会跳转到可以处理该类型的函数部分。我是编程新手,所以我无法真正正确地制定自己。希望你明白我的意思..
  • @TheophileDano:我认为在修订标准推出六年后,不再需要明确指出这不是 18 年前发布的先前标准的一部分......
  • @Unbuckle:如果您通过float * 接收数组,您的函数将“看到”floats。如果您通过double * 收到数组,您的函数将“看到”double 的。如果您通过void * 收到数组,则您的函数根本不会“看到”任何特定类型。因此,您要么必须转到void * 并通过附加参数告诉函数要采用哪种类型,要么转到_Generic,如我的回答中所示,或者转到C++,模板使这种事情变得非常容易。 ;-)
  • 我只允许使用 C99 标准:/
【解决方案2】:

研究qsort的接口。它应该会激励你。

请注意,函数的类型和签名与calling conventionsABIs 相关。实际上,编译器正在生成不同的代码来调用double-s 的排序函数和long-s 的另一个函数。

我猜你的老师希望你使用function pointers。您可能希望向它们传递一些额外的客户端数据(将这些函数指针用作callbacks),有点像非标准的qsort_r(3) 所做的那样。

请注意,遗憾的是 C 没有 closures(一个重要的概念,与 anonymous functionsfree and bound variables 有关)。我建议阅读 SICP 以了解它们的重要性。

或者,使用preprocessor 拥有一些穷人的metaprogramming。您可能会定义一个包含几十行的巨大DEFINE_BUBBLE_SORT(Type,Name) 宏(除最后一行外,所有行都以\ 结尾),它将扩展为对Type 数组进行操作的名为Name 的冒泡排序函数的定义。在SGLIB的源代码中寻找灵感。然后,您将使用DEFINE_BUBBLE_SORT(int, my_int_bubble_sort) 来定义一个在int-s 上运行的例程my_int_bubble_sort,并使用DEFINE_BUBBLE_SORT(double, my_double_bubble_sort) 来获得一个在双精度上运行的my_double_bubble_sort

(您甚至可以混合使用这两种方法:编写一个采用函数指针的 my_bubble_sort,并在内部使用该函数编写一个较短的 DEFINE_BUBBLE_SORT 宏)

另一种方法(与第二种方法相关)是用 C 编写元程序。您将在某个文件中编写一个程序生成一些 C 代码,该程序可能take 两者DEFINE_BUBBLE_SORT 的类型和函数名作为程序参数。然后,您将配置您的 build automation 工具(例如您的 Makefile)以适当地使用该生成器。

顺便说一句,在操作系统及其外部编译器的帮助下,您甚至可以“动态”地做到这一点:在运行时生成一些 C 代码,将其编译为临时的 plugindynamically load 那个插件使用例如dlopen 在 POSIX 上;但这对于初学者来说太过分了......

【讨论】:

    【解决方案3】:

    无论您做什么,都必须有一个带有类型比较 array[d] &gt; array[d + 1] 的位置,或者从 floatdouble 的提升。因此,每种类型都需要最少的定制。对于这么小的代码,将其打包在一个函数中并不是一个好主意。并且传递外部比较函数会增加不必要的开销。

    为避免代码重复,我将通过使用预处理器模拟模板化函数来解决此问题:

    文件bubblesort.h

    #define function_name(type) type##_bubble_sort
    void function_name(type)(type* array, int length)
    {
        int c, d;
        type temp;
    
        for (c = 0; c < (length - 1); c++) {
            for (d = 0; d < length - c - 1; d++) {
                if (array[d] > array[d + 1]) {
                    temp = array[d];
                    array[d] = array[d + 1];
                    array[d + 1] = temp;
                }
            }
        }
    }
    #undef function_name
    #undef type
    

    主文件:

    #define type float
    #include "bubblesort.h"
    
    #define type double
    #include "bubblesort.h"
    

    这定义了函数

    void float_bubble_sort(float* array, int length);
    void double_bubble_sort(double* array, int length);
    

    【讨论】:

      【解决方案4】:

      您不能将不同类型的变量传递给函数,但可以避免重写函数以更改类型。

      #include<stdio.h>
      
      #define bubble_sort(type) type##_bubble_sort (type* array, int length)      \
      {                                                                   \
          int c, d;                                                       \
          type temp;                                                      \
          for (c = 0; c < (length - 1); c++) {                            \
              for (d = 0; d < length - c - 1; d++) {                      \
                  if (array[d] > array[d + 1]) {                          \
                      temp = array[d];                                    \
                      array[d] = array[d + 1];                            \
                      array[d + 1] = temp;                                \
                  }                                                       \
              }                                                           \
          }                                                               \
      }
      
      bubble_sort(int)        //This will create function named int_bubble_sort(int* array, int length)
      bubble_sort(char)       //char_bubble_sort(char* array, int length)
      bubble_sort(float)      //float_bubble_sort(float* array, int length)
      
      
      int main()
      {
          char array[] = {"edcba"};
      
          char_bubble_sort(array,5);
          puts(array);
          return 0;   
      }
      

      【讨论】:

        【解决方案5】:

        正如 DevSolar 所提到的。您可以使用 void 指针来完成。比如:

            void bubble_sort(void* array, int length, int sizeItem)
            {
                int c, d;
                double temp_d;
                float  temp_f
                float* array_f;
                double* array_d;
        
                if (sizeItem == sizeof(float)){
                    array_f = (float*)array;
                    for (c = 0; c < (length - 1); c++) {
                      for (d = 0; d < length - c - 1; d++) {
                        if (array_f[d] > array_f[d + 1]) {
                          temp_f = array_f[d];
                          array_f[d] = array_f[d + 1];
                          array_f[d + 1] = temp_f;
                        }
                      }
                   }
               } else if (sizeItem == sizeof(double)){
                  array_d = (double*)array;
                  for (c = 0; c < (length - 1); c++) {
                    for (d = 0; d < length - c - 1; d++) {
                      if (array_d[d] > array_d[d + 1]) {
                        temp_d = array_d[d];
                        array_d[d] = array_d[d + 1];
                        array_d[d + 1] = temp_d;
                      }
                    }  
                  }
               } else {
                // unknown type ->your errorhandling goes here
               }
            }
        
        // function call:   
        bubble_sort((void*)your_array, length, sizeof(your_array[0]));  
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-07-07
          • 2018-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-14
          相关资源
          最近更新 更多