3

I have this bubble sort function:

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

How do I change it so that I can use it for double as well? I want to be able to pass a float array one time and a double array another time, but it has to be the same function. Something like this:

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

EDIT: I rewrote the sorting function and it seems to work fine now. What do you think?

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;
            }
        }
    }
  }
}
Unbuckle
  • 31
  • 6
  • Do you plan on having a collection with mixed types? If you just want to sort doubles, change the function signature. – Tim Biegeleisen Oct 31 '17 at 09:16
  • 2
    Kind of; take a look at the documentation for `qsort`. You’d probably be better off making two functions, though. – Ry- Oct 31 '17 at 09:18
  • @underscore_d - Well, one can use a macro to generate this function for different data-types, then wrap it in a generic selection, I 'spose. But templates are still better :P – StoryTeller - Unslander Monica Oct 31 '17 at 09:19
  • I got to do it in one function. You see Im only a beginner in C programming and this is one of the exercises. @Ryan And in this case it will only get float types, but in theory the algorithm should be able to handle floats and doubles. – Unbuckle Oct 31 '17 at 09:21
  • 1
    like [this](https://stackoverflow.com/a/21304055/971127) – BLUEPIXY Oct 31 '17 at 09:25
  • Are you asking if you can have an array with both floats and doubles? What do you mean with "at the same time"? – klutt Oct 31 '17 at 09:29
  • @klutt No in the program Im using this in I will only have floats anyway. But the function itself should be able to handle both data types for later use. – Unbuckle Oct 31 '17 at 09:38
  • Array are homogeneous data structures. You *cannot* have an array mixing `float`-s and `double`-s. You might want to define some single [tagged union](https://en.wikipedia.org/wiki/Tagged_union) type if you absolutely need to mix both (but that is unlikely). – Basile Starynkevitch Oct 31 '17 at 09:50
  • I made an edit to your question. Is it what you want? – klutt Oct 31 '17 at 09:53
  • A solution like `bouble_sort(farr, SIZE); bouble_sort(darr, SIZE);` is just impossible. Because function overloading is not allowed in C (before C11), you must use a "neutral" argument type such as `void*`. But then the function cannot guess what you passed. –  Oct 31 '17 at 09:56
  • Exactly, both ways gotta be IN the same function aswell @Klutt – Unbuckle Oct 31 '17 at 09:56

5 Answers5

8

Edit: Limitation to C99 was not clear at the time the answer below was written. With that limitation, it is quite likely the instructor expects a solution mimicking qsort(), with a "compare" function and the sizeof for the data type passed as parameters. So I wrote a "C99" answer as well.

This takes only a couple of "tricks". You receive the array as void *, the size of the handled type and a compare function as parameters.

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

You need to do pointer arithmetics instead of array indexing, as you can't cast array to the correct (unknown) type.

For this, you need unsigned char * (as pointer arithmetic is not possible on void *), and add size to those pointers to get to the next element.

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

You call the compare function instead of comparing yourself.

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

And you need to memswp two elements instead of working on their type:

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 );

This is the original answer, prior to C99 being a requirement. I still stand by the statements made.

No, it is not possible, at least not in good style. You could take the first parameter as a void *, and have an additional parameter to "switch" between float and double handling, but that would be several flavours of bad design. Or you could "outsource" the comparison to another function passed as function pointer, the way qsort() does it, but I don't think that is that good a design either.

You can, however, create a function bubble_sort_float() and a function bubble_sort_double(), and then "hide" both of them behind a _Generic macro:

#define bubble_sort(X, length) _Generic((X), \
                               double: bubble_sort_double, \
                               default: bubble_sort_double,  \
                               float: bubble_sort_float  \
)(X, length)
DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 2
    Nota Bene: `_Generic` is a C11 extension. – TDk Oct 31 '17 at 09:31
  • Hm, I think this is a good idea. What if you check if the number has either data type float OR double and depending on which one it is it jumps to the part of the function which can handle that type. Im new to programming so I cant really formulate myself right. Hope you understand what I meant.. – Unbuckle Oct 31 '17 at 09:32
  • @TheophileDano: I think six years after the introduction of the revised standard it is no longer necessary to point out explicitly that this was not part of the previous standard released eighteen years ago... – DevSolar Oct 31 '17 at 09:33
  • @Unbuckle: If you receive the array via `float *`, your function will "see" `float`s. If you received the array via `double *`, your function will "see" `double`'s. If you received the array via `void *`, your function will not "see" any specific type at all. So you either have to go `void *` and tell the function which type to assume via additional parameter, go `_Generic` as shown in my answer, or go C++ where templates make this kind of stuff quite easy. ;-) – DevSolar Oct 31 '17 at 09:36
  • Im only allowed to use C99 Standard though :/ – Unbuckle Oct 31 '17 at 09:42
  • @Unbuckle: Well... time to upgrade your instructor? ;-) – DevSolar Oct 31 '17 at 09:45
  • @Unbuckle: He's probably expecting you to mimick `qsort()`'s behaviour then. – DevSolar Oct 31 '17 at 09:46
  • @Unbuckle: Extended the answer with a "qsort how-to". – DevSolar Oct 31 '17 at 10:08
  • Im overwhelmed by all the given information. Not sure if the instructor means this, since we didnt really go through pointers yet.. Altough bubble sort uses pointers too ^^ – Unbuckle Oct 31 '17 at 10:47
  • @Unbuckle: It is sometimes hard to guess what an instructor meant. I consider the "C99 only" requirement a strong indication that your instructor might be a bit... set in his ways? Perhaps he's asking for a macro (where type wouldn't be a problem), but *that* would cross the line from "not good design" to "really bad design"... – DevSolar Oct 31 '17 at 10:51
  • I could send you the exact instructions as I saw you are german aswell. Another instruction is that we can only use standard libary which you could also not know. Memswp isnt part of the standard libary as far as I am concerned :( – Unbuckle Oct 31 '17 at 11:08
  • @Unbuckle: Ah. Whoops. I was looking at [my own `qsort()` implementation](https://bitbucket.org/pdclib/pdclib/src/c8dc861df697a6c8bddbcbf331d9b6fcae6e2f4d/functions/stdlib/qsort.c) and didn't realize that the `memswp()` in there was a convenience function by me, not a standard one. Will add to answer. – DevSolar Oct 31 '17 at 11:18
  • I added another solution above – Unbuckle Nov 01 '17 at 14:34
1

Study the interface of qsort. It should inspire you.

Be aware that the type and signature of functions are related to calling conventions and ABIs. Practically speaking the compiler is generating different code to call a sorting function for double-s and another one for long-s.

I guess that your teacher wants you to use function pointers. You probably want to pass them some additional client data (to use these function pointers as callbacks) a bit like the non-standard qsort_r(3) does.

Notice that C sadly does not have closures (an important concept, related to anonymous functions and free and bound variables). I recommend reading SICP to understand how important they are.

Alternatively, use the preprocessor to have some poor man's metaprogramming. You might define a huge DEFINE_BUBBLE_SORT(Type,Name) macro of several dozen lines (all ended with a \ except the last one) which would expand to the definition of a bubble sort function named Name operating on arrays of Type. Look for inspiration into the source code of SGLIB. You'll then use DEFINE_BUBBLE_SORT(int, my_int_bubble_sort) to get defined a routine my_int_bubble_sort operating on int-s, and use DEFINE_BUBBLE_SORT(double, my_double_bubble_sort) to obtain a my_double_bubble_sort operating on doubles.

(you could even mix both approaches: code a my_bubble_sort taking a function pointer, and a shorter DEFINE_BUBBLE_SORT macro internally using that function)

Another approach (related to the second one) would be to code a metaprogram in C. You'll code a program generating some C code in some file, and that program might take both the type and the function name as the DEFINE_BUBBLE_SORT does as program arguments. You'll then configure your build automation tool (e.g. your Makefile) to use that generator appropriately.

BTW, with the help of operating system and its external compiler, you could even do that "dynamically": generate at runtime some C code, compile it as a temporary plugin, and dynamically load that plugin using e.g. dlopen on POSIX; but this goes too far for a beginner....

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

Whatever you do, there must be a place with a typed comparison array[d] > array[d + 1], or a promotion from float to double. So there needs to be a minimum of customization per type. For such a tiny code, it is not a very good idea to pack this in a single function. And passing an external comparison function will add undesirable overhead.

To avoid code duplication, I would solve the case by emulating a templated function, using the preprocessor:

File 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

Main file:

#define type float
#include "bubblesort.h"

#define type double
#include "bubblesort.h"

This defines the functions

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

As DevSolar has mentioned. You can do it with a void pointer. So for example:

    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]));  
simonegg
  • 11
  • 2
0

You cannot pass different type of variables to function but you can avoid rewriting function for type change.

#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;   
}
amitkindre
  • 43
  • 7