JWDN
JWDN

Reputation: 382

Can I create a function which accepts a pointer to an array which may contain a different type of numbers on each call?

I need to write a function which writes an array of "n" elements to a binary output file. I would like to avoid having to write a separate function for each type of data I may wish to write (int, float, double, etc).

Is there any way I can specify the data type (perhaps number-of-bytes) as an argument to the function, and let the function determine how it handles it?

e.g.

f_writebinary(??? *data, int size, long n) {

   for(i=0;i<n;i++) {

        fwrite((data+i),size,1,stdout); 

    }
}

...or is this a totally absurd thing to expect of C?

Upvotes: 1

Views: 87

Answers (2)

alk
alk

Reputation: 70971

Just replace ??? with char. Or use void and cast to char* inside the function, so there is no need to cast to char* when calling the function. And better use size_t instead of int and long:

#include <stdio.h>
...

size_t f_writebinary(void * data, size_t size, size_t n) 
{
  size_t result = 0;

  for (size_t i = 0; i < n; ++i) 
  {    
    size_t result_inner = fwrite(((char *) data) + (i * size), size, 1, stdout); 
    if (!result_inner)
    {
      /* handle error here */
    }
    else
    {
      ++result;
    }
  }

  return result;
}

Optimised version:

size_t f_writebinary(void * data, size_t size, size_t n) 
{
  size_t result = 0;

  n *= size;
  for (size_t i = 0; i < n; i += size) 
  {    
    size_t result_inner = fwrite(((char *) data) + i, size, 1, stdout); 
    if (!result_inner)
    {
      /* handle error here */
    }
    else
    {
      ++result;
    }
  }

  return result;
}

To cut it short: Just mimik the signature fwrite() uses.

Upvotes: 1

unwind
unwind

Reputation: 399949

Yes, that's exactly what fwrite() is. It uses a const void * which means "pointer to any type of data", and treats it as a pointer to bytes.

So, your wrapper isn't really needed, you can just make a correctly-sized call to fwrite() right away to write the array:

const int my_ints[3] = { 1, 2, 3 };
const double my_doubles[5] = { 5, 4, 3, 2, 1 };

fwrite(my_ints, sizeof *my_ints, sizeof my_ints / sizeof *my_ints, stdout);
fwrite(my_doubles, sizeof *my_doubles, sizeof my_doubles / sizeof *my_doubles, stdout);

Note that writing binary data to stdout can be somewhat rude, and also that I/O calls should be checked for errors.

If you drop the "x elements of y bytes" model that fwrite()'s API uses, and just treat them as single chunks of bytes, you can simplify the calls:

fwrite(my_ints, sizeof my_ints, 1, stdout);
fwrite(my_doubles, sizeof my_doubles, 1, stdout);

Note that there's no point in looping, the numbers in each array will be adjacent in memory so fwrite() can write them all at once. It's generally best to keep the number of I/O calls done down as much as possible, so if you can do a single write of n * m bytes instead of n writes of m bytes each, that's almost often better. Remember that that many of the underlying devices that you write to are block-oriented, and will benefit a lot from getting whole blocks of data since that's what they have to write, anyway.

Upvotes: 2

Related Questions