0

I need to write a method to calculate the average of an unknown type of numbers (double, float, int...). I tried to do something like this, but it works for double type only:

double average(void *arr, int length, int bytes) {
    int i;
    double sum = 0;
    double num;
    for (i = 0; i < length; i++) {
        memcpy(&num, (char *) arr, bytes);
        sum += num;
        arr = (char *) arr + bytes;
    }
    return sum / length;
}

Any suggestions?

Yuval
  • 764
  • 1
  • 9
  • 23
  • 2
    This isn't possible. You have a void* which points to raw memory. There's no way you can determine, from raw bytes, what kinds of numbers are there. You can treat raw bytes as a bunch of integers, floats, doubles, or any crazy mix at all. What exactly are you trying to do? – Ray Toal Feb 20 '18 at 08:57
  • Refer this https://stackoverflow.com/questions/5551427/generic-data-type-in-c-void – Arpan Sarkar Feb 20 '18 at 08:57
  • You have an impossible assignment. The only way to distinguish between the types is the `bytes` argument, and it can't help you with `int` or `float` since both are generally the same size. If `long long` could be used then there's trouble with it and `double`. And if you pass an array of integers, is it signed or unsigned? – Some programmer dude Feb 20 '18 at 08:58
  • 1
    In C the only way to solve a problem like this is to use [*generic selection*](http://en.cppreference.com/w/c/language/generic). – Some programmer dude Feb 20 '18 at 09:00
  • Well is it possible to pass the type of the array? – Yuval Feb 20 '18 at 09:05
  • Sure - you can pass an enum, say, and then switch on it. Seems a bit pointless - may as well have separate functions. – Martin James Feb 20 '18 at 09:20
  • Was this an assignment? Maybe you misunderstood it. – Jabberwocky Feb 20 '18 at 10:09
  • @Yuval There are a number of approaches, the key is that you need to show sample code of how it might be called. The main idea is in the calling, the info about type steers code by function selection or parameter passing. Unfortunately your code only shows a function and not how it is used. – chux - Reinstate Monica Feb 20 '18 at 17:10

1 Answers1

2

You can't sum the array values if you don't know what type they are. Relying on the bytes parameter alone is not enough, since int and float are commonly the same size in many compilers, but they are very different types. You lose type information when operating with void*.

If you must use void*, the only way to solve this is to pass in a parameter that specifies what type the array actually holds, and then cast the void* accordingly.

I suggest writing a separate function for each type, eg:

enum dataType {dtInt, dtFloat, dtDouble};

double averageInt(int *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum / length;
}

double averageFloat(float *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum / length;
}

double averageDouble(double *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum / length;
}

double average(void *arr, int length, enum dataType arrType)
{
    switch (arrType)
    {
        case dtInt:    return averageInt((int*)arr, length);
        case dtFloat:  return averageFloat((float*)arr, length);
        case dtDouble: return averageDouble((double*)arr, length);
    }
    return 0;
}

Alternatively:

enum dataType {dtInt, dtFloat, dtDouble};

double sumInt(int *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum;
}

double sumFloat(float *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum;
}

double sumDouble(double *arr, int length)
{
    double sum = 0;
    for (int i = 0; i < length; ++i)
        sum += arr[i];
    return sum;
}

double average(void *arr, int length, enum dataType arrType)
{
    double sum;
    switch (arrType)
    {
        case dtInt:    sum = sumInt((int*)arr, length); break;
        case dtFloat:  sum = sumFloat((float*)arr, length); break;
        case dtDouble: sum = sumDouble((double*)arr, length); break;
        default:       sum = 0; break;
    }
    return sum / length;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770