如何制作接受不同类型的功能?

时间:2017-10-31 09:14:08

标签: c algorithm sorting c99

我有这个冒泡排序功能:

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数组,另一次传递一个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;
            }
        }
    }
  }
}

5 个答案:

答案 0 :(得分:8)

编辑:在撰写以下答案时,对C99的限制并不明确。有了这个限制,教师很可能期望一个模拟qsort()的解决方案,带有“比较”功能,并且public void addCastleToKingdom(String kingdomName,String castleName) { Kingdom kingdom = getKingdom(kingdomName); Castle castle = new Castle(castleName); kingdom.addCastle(castle); kingdomRepository.save(kingdom); } 作为参数传递的数据类型。所以我也写了一个“C99”的答案。

这只需要几个“技巧”。您将数组作为sizeof接收,处理类型的大小和比较函数作为参数。

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

这是原始答案,在C99成为要求之前。我仍然坚持所作的陈述。

不,这是不可能的,至少不是很好的风格。您可以将第一个参数作为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 ); ,并在void *float处理之间有一个“切换”的附加参数,但这会有几种风格糟糕的设计。或者你可以将比较“外包”到作为函数指针传递的另一个函数,qsort()的方式,但我不认为那是一个好的设计。

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

bubble_sort_double()

答案 1 :(得分:1)

研究qsort的界面。它应该激励你。

请注意,函数的类型和签名与calling conventionsABI相关。实际上,编译器正在生成不同的代码来为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)宏(除最后一行之外都以\结尾),这将扩展为在数组上运行的名为Name的冒泡排序函数的定义Type。在SGLIB的源代码中寻找灵感。然后,您将使用DEFINE_BUBBLE_SORT(int, my_int_bubble_sort)来定义在my_int_bubble_sort - s上运行的例程int,并使用DEFINE_BUBBLE_SORT(double, my_double_bubble_sort)获取对{double}进行操作的my_double_bubble_sort。< / p>

(你甚至可以混合两种方法:使用函数指针代码my_bubble_sort和内部使用该函数的较短DEFINE_BUBBLE_SORT宏)

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

BTW,在操作系统及其外部编译器的帮助下,您甚至可以“动态地”执行此操作:在运行时生成一些C代码,将其编译为临时Makefile和{{3这个插件使用eg关于POSIX的plugin;但这对初学者来说太过分了......

答案 2 :(得分:1)

无论您做什么,都必须有一个类型比较array[d] > 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);

答案 3 :(得分:0)

正如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]));  

答案 4 :(得分:0)

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

#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;   
}