0

I need to write function that calculate average of array with numeric values elements without knowing elements type.

The function need to be called with the array, number of array elements and other parameter(s) if i want to.

So this is what i have until now:

int arr[2] = { 3,7 };
avarage(arr, 2, sizeof(int));

void * avarage(void * arr, int elements, int bytes)
{
    int i;
    char *p = (char *)malloc(bytes);
    char *tmp = (char *)arr;
    char *n;
    int sum = 0;

    for (i = 0; i < elements * sizeof(bytes); i++)
    {
        p[i] = tmp[i];  
    }
}

Because i do not know the elements types I working with general pointer: void * and also sent into my function the size of my type.

In my computer i can see that bytes is 4 so after 4 iterations i need to convert my p into Int.

So inside the loop thing start to mess and I don't know how to proceed.

Dean Movy
  • 139
  • 1
  • 9
  • 3
    Average is `(sum(elements) / totalelements)`. If your `elements` is of a totally arbitrary type, the caller will have to provide the corresponding `sum` function as a function pointer. Or a `plus` function alternatively. – Eugene Sh. Feb 08 '18 at 18:01
  • First i want to know how to convert my array to numbers – Dean Movy Feb 08 '18 at 18:04
  • 3
    Who said these are numbers? Maybe it's vectors? Or matrices? Or ... apples? You said the type is unknown (BTW, in my previous comment there should be also the "divide" function) – Eugene Sh. Feb 08 '18 at 18:06
  • ho sorry for that the array is with numeric values i edit the question – Dean Movy Feb 08 '18 at 18:09
  • 2
    @DeanMovy, you seem to be focusing in the wrong place. In particular, your assertion that *after 4 iterations i need to convert my p into Int* is not sensible. What if the input contains `float`s? You then cannot expect to convert to `int` without losing precision and/or getting altogether the wrong value. Nor is there any other specific type you can choose that would properly accommodate all C arithmetic types. – John Bollinger Feb 08 '18 at 18:23
  • 1
    Generics are pretty hard to do in C. There are a few questions that have asked how to do this before. The answers usually tend to involve the C preprocessor. It may not be exactly what you want but maybe take a look? Here's a [link](https://stackoverflow.com/questions/16522341/pseudo-generics-in-c). – mustachioed Feb 08 '18 at 18:48
  • Is there an assumption here that although the type is not known, it is known to be an integral type, such that the size basically does define the type? – Steve Summit Feb 08 '18 at 19:00
  • the return type for the function is `void*`, but the function body has no statement similar to `return &status;` – user3629249 Feb 08 '18 at 20:06
  • regarding: `char *p = (char *)malloc(bytes);` 1) the return type is `void*`, which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. 2) Always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Feb 08 '18 at 20:08
  • the posted code (at best) is just copying the input array to a dynamically allocated array. – user3629249 Feb 08 '18 at 20:13

1 Answers1

0

need to write function that calculate average of array with numeric values elements without knowing elements type.

This is somewhat broad, yet with a few restrictions, it is doable.

The key is to pass into the average(), pointers to functions to do the add/divide math. @Eugene Sh..

To minimize memory management, also pass to avg(), add_ll(), etc., the destination to store the result.

Minor: use size_t rather than int for size data and math as that type is neither too narrow nor too wide.

#include <stdbool.h>
#include <stdio.h>
#include <string.h>

// Return true on failure
// Note that a, b, etc could point to the same object
bool add_ll(void *sum, void *a, void *b) {
  // TBD: add code to detect and prevent overflow
  *(long long *) sum = *(long long *) a + *(long long *) b;
  return false;
}

bool div_ll(void *quo, void *a, size_t n) {
  if (n == 0) {
    return true;
  }
  *(long long *) quo = *(long long *) a / n;
  return false;
}

bool avg(void *bar, void *a, size_t nmemb, size_t size, bool (add)(), bool (quo)()) {
  memset(bar, 0, size); // assume bits all zero is a value of zero
  char (*p)[size] = a;  // p is a pointer to a character array of size `size`
  for (size_t i = 0; i < nmemb; i++) {
    if (add(bar, bar, p)) {
      return true;
    }
    p++;  // this moves `size` bytes later
  }
  return quo(bar, bar, nmemb);
}

int main(void) {
  long long A[3] = { 3, 600000, 90000000000 };
  long long mean;
  if (avg(&mean, A, sizeof A / sizeof A[0], sizeof A[0], add_ll, div_ll)) {
    puts("Oops");
  } else {
    printf("Average = %lld\n", mean);
  }
  return 0;
}

Output

Average = 30000200001

Advanced issues: Code with more error checking would use the below to insure matching of function types and to be const correct.

bool avg(void *bar, void *a, size_t nmemb, size_t size,
    bool (add)(void *sum, void *a, void *b),
    bool (quo)(void *quo, void *a, size_t n));

or

bool avg(void *bar, void *a, size_t nmemb, size_t size,
    bool (add)(void *sum, const void *a, const void *b),
    bool (quo)(void *quo, const void *a, size_t n));
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • You forgot to include `#include ` for `memset()` – Michi Feb 08 '18 at 20:06
  • Here : `*(long long *) quo = *(long long *) a / n;` needs also a Fix: =>> `error: conversion to ‘long long unsigned int’ from ‘long long int’ may change the sign of the result [-Werror=sign-conversion] *(long long *) quo = *(long long *) a / n;` – Michi Feb 08 '18 at 20:08
  • 1
    @Michi That issues is only an error as you have warnings as error enabled. A simple "fix" would be to cast `(long long) n`. Pedantic code would first check `if (n > LLONG_MAX) { code to make quotient 0 }`. It depends how robust the coding goal. IAC, it is a good idea for advanced issues. – chux - Reinstate Monica Feb 08 '18 at 20:13
  • I am agree, but I am used to code without warnings :) – Michi Feb 08 '18 at 20:15