Access elements in Struct by Address - c++

I've done some research and I cant quite find what I'm looking for on here or google. Is there a way to access the elements in a Customer by address (and not by using customer[i].bottles). I cannot modify the struct so I cannot put the properties into an array.
typedef struct Customer {
int id;
int bottles;
int diapers;
int rattles;
} Customer;
Customer customers[100];
void setValue(int custInd, int propertyInd) {
//propertyInd would be 1 for id, 2 for bottles
//Attempting to set customers[0].bottles
*(&customers[custInd]+propertyInd) = 5;
}
I thought I'd be able to do this but I got various errors. Knowing that the "bottles" value will be the second space in memory from the address of a Customer shouldn't i be able to directly set the spot.
I know this may be improper code but I would like to understand how and why does/doesnt work. I also promise I have reasons for attempting to do this over the conventional way hah

Instead of using propertyInd, perhaps pass an offset into the structure. That way, the code will work even if the layout changes dramatically (for example, if it includes non-int fields at the beginning).
Here's how you might do it:
void setValue(int custInd, int fieldOffset) {
int *ptr = (int *)((char *)&customers[custInd] + fieldOffset);
*ptr = 5;
}
...
setValue(custInd, offsetof(Customer, bottles));
offsetof is a standardized macro that returns the offset, in bytes, from the start of the structure to the given element.
If you still want to use indices, you can compute the offset as propertyInd * sizeof(int), assuming every field in the struct is an int.

You can't do this:
*(&customers[custInd]+propertyInd) = 5;
because the type of &customers[custInd] is struct Customer*, not int *. So &customers[custInd]+propertyInd means the same thing as &customers + custInd + propertyInd or, in other words, &customers[custInd + propertyInd]. The assignment then attempts to set a structure value to the integer 5, which is obviously illegal.
What I suppose you meant was
((int*)&customers[custInd])[propertyInd] = 5;
which would compile fine, and would probably work[*], but is undefined behaviour because you cannot assume that just because a struct consists of four ints, that it is laid-out in memory the same way as int[4] would be. It may seem reasonable and even logical that they layout be the same, but the standard doesn't require it, so that's that. Sorry.
As #iharob suggests in a comment, you might find a compiler clever enough to generate efficient code from the following verbiage:
void setValue(int custInd, int propertyInd, int value) {
//propertyInd would be 1 for id, 2 for bottles
switch (propertyInd) {
case 1: customers[custInd].id = value; break;
case 2: customers[custInd].bottles = value; break;
case 3: customers[custInd].diapers = value; break;
case 4: customers[custInd].rattles = value; break;
default: assert(0);
}
}
*: Actually, it would (probably) work if propertyInd for id were 0, not 1. C array indices start at 0.

&customers[custInd] is a pointer to customers[custInd], so &customers[custInd]+propertyInd is a pointer to customers[custInd+propertyInd]. It is not a pointer to a member. It will have type pointer to Customer. The value of that pointer will be equal to &(customers[custInd+propertyInd].id), but is not a pointer to int - hence the compiler error.
Your bigger problem is that four int in a struct are not necessarily laid out like an array of int - there may be padding between struct members. So, if we do
int *p = &(customers[custInd].id);
then p+1 is not necessarily equal to &(customers[custInd].bottles).
So you will need to do something like
void setValue(int custInd, int Offset)
{
int *ptr = (int *)(((char *)&customers[custInd]) + Offset);
*ptr = 5;
}
/* and to call it to set customers[custInd].bottles to 5 */
setValue(custInd, offsetof(Customer, bottles));

Related

Why can't we use a void* to operate on the object it addresses

I am learning C++ using C++ Primer 5th edition. In particular, i read about void*. There it is written that:
We cannot use a void* to operate on the object it addresses—we don’t know that object’s type, and the type determines what operations we can perform on that object.
void*: Pointer type that can point to any nonconst type. Such pointers may not
be dereferenced.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*. Also, i am not sure if the above quoted statement from C++ Primer is technically correct because i am not able to understand what it is conveying. Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses". So can someone please provide some example to clarify what the author meant and whether he is correct or incorrect in saying the above statement.
My question is that if we're not allowed to use a void* to operate on the object it addressess then why do we need a void*
It's indeed quite rare to need void* in C++. It's more common in C.
But where it's useful is type-erasure. For example, try to store an object of any type in a variable, determining the type at runtime. You'll find that hiding the type becomes essential to achieve that task.
What you may be missing is that it is possible to convert the void* back to the typed pointer afterwards (or in special cases, you can reinterpret as another pointer type), which allows you to operate on the object.
Maybe some examples can help me understand what the author meant when he said that "we cannot use a void* to operate on the object it addresses"
Example:
int i;
int* int_ptr = &i;
void* void_ptr = &i;
*int_ptr = 42; // OK
*void_ptr = 42; // ill-formed
As the example demonstrates, we cannot modify the pointed int object through the pointer to void.
so since a void* has no size(as written in the answer by PMF)
Their answer is misleading or you've misunderstood. The pointer has a size. But since there is no information about the type of the pointed object, the size of the pointed object is unknown. In a way, that's part of why it can point to an object of any size.
so how can a int* on the right hand side be implicitly converted to a void*
All pointers to objects can implicitly be converted to void* because the language rules say so.
Yes, the author is right.
A pointer of type void* cannot be dereferenced, because it has no size1. The compiler would not know how much data he needs to get from that address if you try to access it:
void* myData = std::malloc(1000); // Allocate some memory (note that the return type of malloc() is void*)
int value = *myData; // Error, can't dereference
int field = myData->myField; // Error, a void pointer obviously has no fields
The first example fails because the compiler doesn't know how much data to get. We need to tell it the size of the data to get:
int value = *(int*)myData; // Now fine, we have casted the pointer to int*
int value = *(char*)myData; // Fine too, but NOT the same as above!
or, to be more in the C++-world:
int value = *static_cast<int*>(myData);
int value = *static_cast<char*>(myData);
The two examples return a different result, because the first gets an integer (32 bit on most systems) from the target address, while the second only gets a single byte and then moves that to a larger variable.
The reason why the use of void* is sometimes still useful is when the type of data doesn't matter much, like when just copying stuff around. Methods such as memset or memcpy take void* parameters, since they don't care about the actual structure of the data (but they need to be given the size explicitly). When working in C++ (as opposed to C) you'll not use these very often, though.
1 "No size" applies to the size of the destination object, not the size of the variable containing the pointer. sizeof(void*) is perfectly valid and returns, the size of a pointer variable. This is always equal to any other pointer size, so sizeof(void*)==sizeof(int*)==sizeof(MyClass*) is always true (for 99% of today's compilers at least). The type of the pointer however defines the size of the element it points to. And that is required for the compiler so he knows how much data he needs to get, or, when used with + or -, how much to add or subtract to get the address of the next or previous elements.
void * is basically a catch-all type. Any pointer type can be implicitly cast to void * without getting any errors. As such, it is mostly used in low level data manipulations, where all that matters is the data that some memory block contains, rather than what the data represents. On the flip side, when you have a void * pointer, it is impossible to determine directly which type it was originally. That's why you can't operate on the object it addresses.
if we try something like
typedef struct foo {
int key;
int value;
} t_foo;
void try_fill_with_zero(void *destination) {
destination->key = 0;
destination->value = 0;
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
try_fill_with_zero(foo_instance, sizeof(t_foo));
}
we will get a compilation error because it is impossible to determine what type void *destination was, as soon as the address gets into try_fill_with_zero. That's an example of being unable to "use a void* to operate on the object it addresses"
Typically you will see something like this:
typedef struct foo {
int key;
int value;
} t_foo;
void init_with_zero(void *destination, size_t bytes) {
unsigned char *to_fill = (unsigned char *)destination;
for (int i = 0; i < bytes; i++) {
to_fill[i] = 0;
}
}
int main() {
t_foo *foo_instance = malloc(sizeof(t_foo));
int test_int;
init_with_zero(foo_instance, sizeof(t_foo));
init_with_zero(&test_int, sizeof(int));
}
Here we can operate on the memory that we pass to init_with_zero represented as bytes.
You can think of void * as representing missing knowledge about the associated type of the data at this address. You may still cast it to something else and then dereference it, if you know what is behind it. Example:
int n = 5;
void * p = (void *) &n;
At this point, p we have lost the type information for p and thus, the compiler does not know what to do with it. But if you know this p is an address to an integer, then you can use that information:
int * q = (int *) p;
int m = *q;
And m will be equal to n.
void is not a type like any other. There is no object of type void. Hence, there exists no way of operating on such pointers.
This is one of my favourite kind of questions because at first I was also so confused about void pointers.
Like the rest of the Answers above void * refers to a generic type of data.
Being a void pointer you must understand that it only holds the address of some kind of data or object.
No other information about the object itself, at first you are asking yourself why do you even need this if it's only able to hold an address. That's because you can still cast your pointer to a more specific kind of data, and that's the real power.
Making generic functions that works with all kind of data.
And to be more clear let's say you want to implement generic sorting algorithm.
The sorting algorithm has basically 2 steps:
The algorithm itself.
The comparation between the objects.
Here we will also talk about pointer functions.
Let's take for example qsort built in function
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
We see that it takes the next parameters:
base − This is the pointer to the first element of the array to be sorted.
nitems − This is the number of elements in the array pointed by base.
size − This is the size in bytes of each element in the array.
compar − This is the function that compares two elements.
And based on the article that I referenced above we can do something like this:
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
int main () {
int n;
printf("Before sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\nAfter sorting the list is: \n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
return(0);
}
Where you can define your own custom compare function that can match any kind of data, there can be even a more complex data structure like a class instance of some kind of object you just define. Let's say a Person class, that has a field age and you want to sort all Persons by age.
And that's one example where you can use void * , you can abstract this and create other use cases based on this example.
It is true that is a C example, but I think, being something that appeared in C can make more sense of the real usage of void *. If you can understand what you can do with void * you are good to go.
For C++ you can also check templates, templates can let you achieve a generic type for your functions / objects.

How to avoid dynamic allocation of memory C++

[edit] Outside of this get method (see below), i'd like to have a pointer double * result; and then call the get method, i.e.
// Pull results out
int story = 3;
double * data;
int len;
m_Scene->GetSectionStoryGrid_m(story, data, len);
with that said, I want to a get method that simply sets the result (*&data) by reference, and does not dynamically allocate memory.
The results I am looking for already exist in memory, but they are within C-structs and are not in one continuous block of memory. Fyi, &len is just the length of the array. I want one big array that holds all of the results.
Since the actual results that I am looking for are stored within the native C-struct pointer story_ptr->int_hv[i].ab.center.x;. How would I avoid dynamically allocating memory like I am doing above? I’d like to point the data* to the results, but I just don’t know how to do it. It’s probably something simple I am overlooking… The code is below.
Is this even possible? From what I've read, it is not, but as my username implies, I'm not a software developer. Thanks to all who have replied so far by the way!
Here is a snippet of code:
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
std::stringstream LogMessage;
if (!ValidateStoryNumber(story_number))
{
data = NULL;
len = -1;
}
else
{
// Check to see if we already retrieved this result
if ( m_dStoryNum_To_GridMap_m.find(story_number) == m_dStoryNum_To_GridMap_m.end() )
{
data = new double[GetSectionNumInternalHazardVolumes()*3];
len = GetSectionNumInternalHazardVolumes()*3;
Story * story_ptr = m_StoriesInSection.at(story_number-1);
int counter = 0; // counts the current int hv number we are on
for ( int i = 0; i < GetSectionNumInternalHazardVolumes() && story_ptr->int_hv != NULL; i++ )
{
data[0 + counter] = story_ptr->int_hv[i].ab.center.x;
data[1 + counter] = story_ptr->int_hv[i].ab.center.y;
data[2 + counter] = story_ptr->int_hv[i].ab.center.z;
m_dStoryNum_To_GridMap_m.insert( std::pair<int, double*>(story_number,data));
counter += 3;
}
}
else
{
data = m_dStoryNum_To_GridMap_m.find(story_number)->second;
len = GetSectionNumInternalHazardVolumes()*3;
}
}
}
Consider returning a custom accessor class instead of the "double *&data". Depending on your needs that class would look something like this:
class StoryGrid {
public:
StoryGrid(int story_index):m_storyIndex(story_index) {
m_storyPtr = m_StoriesInSection.at(story_index-1);
}
inline int length() { return GetSectionNumInternalHazardVolumes()*3; }
double &operator[](int index) {
int i = index / 3;
int axis = index % 3;
switch(axis){
case 0: return m_storyPtr->int_hv[i].ab.center.x;
case 1: return m_storyPtr->int_hv[i].ab.center.y;
case 2: return m_storyPtr->int_hv[i].ab.center.z;
}
}
};
Sorry for any syntax problems, but you get the idea. Return a reference to this and record this in your map. If done correctly the map with then manage all of the dynamic allocation required.
So you want the allocated array to go "down" in the call stack. You can only achieve this allocating it in the heap, using dynamic allocation. Or creating a static variable, since static variables' lifecycle are not controlled by the call stack.
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
static g_data[DATA_SIZE];
data = g_data;
// continues ...
If you want to "avoid any allocation", the solution by #Speed8ump is your first choice! But then you will not have your double * result; anymore. You will be turning your "offline" solution (calculates the whole array first, then use the array elsewhere) to an "online" solution (calculates values as they are needed). This is a good refactoring to avoid memory allocation.
This answer to this question relies on the lifetime of the doubles you want pointers to. Consider:
// "pointless" because it takes no input and throws away all its work
void pointless_function()
{
double foo = 3.14159;
int j = 0;
for (int i = 0; i < 10; ++i) {
j += i;
}
}
foo exists and has a value inside pointless_function, but ceases to exist as soon as the function exits. Even if you could get a pointer to it, that pointer would be useless outside of pointless_function. It would be a dangling pointer, and dereferencing it would trigger undefined behavior.
On the other hand, you are correct that if you have data in memory (and you can guarantee it will live long enough for whatever you want to do with it), it can be a great idea to get pointers to that data instead of paying the cost to copy it. However, the main way for data to outlive the function that creates it is to call new, new[], or malloc. You really can't get out of that.
Looking at the code you posted, I don't see how you can avoid new[]-ing up the doubles when you create story. But you can then get pointers to those doubles later without needing to call new or new[] again.
I should mention that pointers to data can be used to modify the original data. Often that can lead to hard-to-track-down bugs. So there are times that it's better to pay the price of copying the data (which you're then free to muck with however you want), or to get a pointer-to-const (in this case const double* or double const*, they are equivalent; a pointer-to-const will give you a compiler error if you try to change the data being pointed to). In fact, that's so often the case that the advice should be inverted: "there are a few times when you don't want to copy or get a pointer-to-const; in those cases you must be very careful."

what is the value of an array element if I don't assign it myself

what would be the result if I wrote this
int array1[2];
cout << array1[0] ;
and how can I do this pseudocode :
if array1[0] doesn't have a value then assign its value to 1
I'm using C++ on DevCPP
The elements of array are uninitialized, and it is undefined behaviour to read them before writing to them. Your program is ill-formed. There is no way to "check" for this; it is your responsibility to write a correct program.
The initial value of unassigned array values is undefined (unless the array element type is a class/struct, in which case the default constructor will be called for each array element). In your first example, the behavior is undefined since you have not initialized the array element before using it.
If you want to retain an "unassigned" status then you need to use a class that encapsulates this, for example using the nullable pattern for value types.
Consider using Boost.Optional: you'd declare the array as boost::optional<int> array1[2]; and then you can test if (array1[0]) to see if that particular element has a value.
There is one point that the answers I'm seeing thus far seem to have missed. It depends on where your array is defined.
If the array is local to a function, like:
int f() {
int array1[2];
cout << array1[0] ;
}
...then the other answers are correct: the content of array1 contains unspecified values, and your attempt to read the value and send it to cout gives undefined behavior.
On the other hand, you may have defined array1 as a global variable:
int array1[2];
int f() {
cout << array1[0];
}
In this case, the content of array1 is required to be initialized to 0 for any arithmetic type (or NULL for an array of pointers). In a case like this, writing out the value in array1[0] is perfectly fine and gives defined results -- it must be 0. In this case, there is no any way to tell whether an element of an array containing the value 0 has that value because it was automatically initialized to 0, or was assigned that value later.
If you really need to know whether a value has been written to a variable, it's possible to write a class that will do that:
template <class T>
class value {
T val;
bool assigned;
public:
value(T const init=T()) : assigned(false), val(init) {}
value &operator=(T const &t) {
assigned = true;
val = t;
}
operator T() { return val; }
bool was_assigned() { return assigned; }
};
// ...
value<int> array2[2];
if (!array2[0].was_assigned())
array2[0] = 1;
It's usually easier and more efficient to just define the type to always start out initialized to a known value, so you never really care about whether it's been assigned to or not though. In short, although this supports what you've asked for, my immediate reaction is that there's probably a better/cleaner way to accomplish your ultimate goal. Before you even consider using something like this, I'd strongly recommend stepping back from what you're doing, and trying to figure out if there's a better way to do it. My guess is that there is/will be (and if you can't find it, you might want to ask another question, telling us about why you're trying to do this, to see if somebody can see a more direct way to accomplish your goal).
As far I remember that depend on the OS
As other users said, you need to initialize a then use a for loop to test each value one by one and modify them, if they fulfill a condition, I leave you a C snippet:
/* Variable declaration and initialization to 0s (You can use another value as default )*/
int a[ 5 ] = { 0 };
/* If the array[ i ] has 0 as value */
for( i = 0; i < 5; i++){
if ( a[ i ] == 0 ){
a[ i ] = 1;
}
}
If you don't initialise the element yourself, the element will obtain the value from the memory location it is stored on now (and will most probably convert it to its data type). Consider this program :
#include <iostream>
using namespace std;
int foo(int A[])
{
cout << A[0] << A[1];
}
int main()
{
int array[2];
foo(array);
}
This will give the output 00.
But now consider this code :
int main()
{
int array[2];
cout << array[0] << array[1];
}
It will give some random integer output. This is so because the uninitialised array picks up the value stored on the memory location it now occupies. You can check its memory adress by &array[0] and print it in different data types for some thought provoking questions.
eg: cout << &array[0] << char(array[0]) << bool(array[0]) etc.

Different values of sizeof(datatype_pointer)/sizeof(datatype) for different datatypes, why?

I declared the following struct in my C++ program:
struct person {
char name[10]; /* first name */
char id[10]; /* ID number */
off_t pos; /* position in file, for demonstration */
} people[] = {
{ "arnold", "123456789", 0 },
{ "miriam", "987654321", 10240 },
{ "joe", "192837465", 81920 },
};
j = sizeof(people) / sizeof(people[0]); /* count of elements */
gives j = 3 here, i.e, no of elements in the array; always even if you add or reduce the elements...
But
char b[8];
i = sizeof(b)/sizeof(b[0]);
gives the value of i = a constant = 4 on my machine.
Now thats justified as the sizeof(char*) is constant on my machine and the sizeof(char) too is constant..
But as soon as I declare the struct person, the sizeof(person*) and sizeof(person) should also be constant, and it should also yield a constant value, isn't it???
Your compiler is wrong.
char b[8];
i = sizeof(b)/sizeof(b[0]);
should yield i==8.
The result you're getting for the struct size is correct. I would switch compilers if I were you.
If you were to pass b to a function calculating the size, than you'd be right. But as the code is now, no.
Also, if it was a function calculating sizeof(people) / sizeof(people[0]) which received people as a parameter, you'd also get a constant.
This is because arrays decay to pointers when passed as arguments.
Are you sure you're actually applying sizeof to an array, not a pointer?
In a case like this, the function argument is actually a pointer, so you'll get i == sizeof(char*):
void f(char b[8]) {
i = sizeof(b)/sizeof(b[0]);
}
The code you've posted should definitely give the number of array elements. If it doesn't, then you've either got something else very strange in your code, or your compiler is hopelessly broken.
char b[8];
i = sizeof(b)/sizeof(b[0]);
This should give a value of 8 only. sizeof(b) will give the size of the array and not sizeof(char *) as perceived by you.

What's the best way to rewrite this generic function I wrote in C++ in C?

//Prints out a given array
template <typename T>
void print(T t)
{
for(int i = 0; i < t.size(); i++)
{
cout << t[i] << " ";
}
cout << endl;
}
I have an idea but it includes passing the size of the array. Is it possible to avoid this?
*Update
Thanks for all of the answers/ideas but this problem is getting way deeper than my snorkeler can handle. I wanted to rewrite my C++ code in C because it was horribly written and slow. I see now that I have an opportunity to make it even worse in C. I'll rewrite it from the ground up in Python(performance be damned). Thanks again
If you don't have ELEMENTS, it's
#define ELEMENTS(a) (sizeof(a)/sizeof(*a))
Then,
#define print_array(a, specifier) print_array_impl(a, specifier, ELEMENTS(a), sizeof(*a))
void print_array_impl(void* a, char* specifier, size_t asize, size_t elsize)
{
for(int i = 0; i < asize; i++)
{
// corrected based on comment -- unfortunately, not as general
if (strcmp(specifier, "%d") == 0)
printf(specifier, ((int*)a)[i]);
// else if ... // check other specifiers
printf(" ");
}
printf("\n");
}
Use like this
print_array(a, "%d") // if a is a int[]
and, a needs to be an array name, not a pointer (or else ELEMENTS won't work)
You cannot know what is the size of an array without passing the size of that array (except operating with sizeof in static arrays). This is because the a pointer to a block of memory will only point to the base of the block of memory, from which you can know where the array/block of memory starts, but as there is no end defined you cannot determine where it will end.
You either need to set your own length per array and preserve it, and use it with the array like as described:
You can make a new type like:
struct _my_array {
typename arr[MAX];
int n;
} my_array;
OR
struct _my_array {
typename *arr;
int n;
} my_array;
In this case you need to allocate the a block of memory dynamically with new or malloc , and when finished free the memory with delete or free (respectively).
Or you can simply pass the array number of elements through the function.
Another way is to use a special terminator value of your array type which if encountered will be determined as the end of the array. In this case you need not preserve the size. For example a string is '\0' terminated, so all the string functions know that when a '\0' character is encounter in the char array it will consider that the string has end.
UPDATE
Because this is a generic function and the array can be of any type, one thing which you can do is like this:
struct _my_generic_arr {
void *arr;
int n;
int type;
} my_generic_arr;
When populating this array you can use any type. To identify which type, pass an identified in the type component. Each unique value will determine which type does the arr pointer actually points to (was actually the intended type to be pointed). The n will define the length. Now, depending on different values of type make a switch - case or an if - else ladder or nest, and process the array as you need.
It is impossible in c to track the size of an array in other block,,
It would be a better option to pass the size of the array along..
The other option would be to declare a global variable that has the size and using that variable inside the function
Eg,,
int size=<some value>
void main()
{
int arr[<same value>];
}
void print(T t)
{
for(int i = 0; i < size; i++)
{
printf("%d ",t[i]) //assuming T as int
}
printf("\n");
}
In C, you would need to pass two additional parameters: the size of the array (as you mentioned), and some way of indicating how to convert t[i] into a string. To convert t[i] to a string, you could create a custom switch statement to decode possible types, pass a pointer to a function that will return the string pointer, or you could pass the printf format specifier (e.g. "%d" for integer).
The problem is larger than you think. If you have an array of size 12, how do you know what data is held in that array? It could be 3 char*'s (on 32 bit system), 3 int32_t's, or even 12 chars. You have no way of knowing how to interpret the data. The best you could do is to implement your own version of a v-table and putting a print or toString function into it.
typedef struct {
void *array;
size_t length;
int element_width;
printer_t to_string;
} container;
printer_t is a type that describes a function pointer that takes an element pointer and returns a string (or prints it, if you don't want to free the string). This is almost never worth doing in C. That doesn't mean it can't be done. I would emphasize, though, that none of this is intended to imply that it should be done.
The function itself would look something like this:
void print(container *thing)
{
size_t offset;
int width;
char *stringified;
width = thing->element_width;
for (offset = 0; offset * width < thing->length; offset += width)
{
stringified = thing->to_string(thing->array + offset);
printf("%s ", stringified);
free(stringified);
}
}
What this does is essentially turn a struct into a faux class with a function pointer for a method. You could be more object-oriented and put the method in the type being printed and make it an array of those instead. Either way, it's not a good idea. C is for writing C. If you try to write in a different language, you'll end up with all sorts of terrible stuff like this.