I want to learn more about using function pointers in C structs as a way to emulate objects-oriented programming, but in my search, I've just found questions like this where the answer is simply to use a function pointer without describing how that would work.
My best guess is something like this
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create() {
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
But that give me compiler warnings warning: assignment from incompatible pointer type
, so obviously I'm doing something wrong. Could someone please provide a small but complete example of how to use a function pointer in a C struct correctly?
My class taught in C does not even mention these. It makes me wonder whether these are actually used by C programmers. What are the advantages and disadvantages of using function pointers in C structs?
The answer given by Andy Stow Away fixes my compiler warning, but doesn't answer my second question. The comments to that answer given by eddieantonio and Niklas R answer my second question, but don't fix my compiler warning. So I'm pooling them together into one answer.
C is not object-oriented and attempting to emulate object-oriented design in C usually results in bad style. Duplicating methods called on structs so that they can be called using a pointer to the struct as I have in my example is no exception. (And frankly, it violates DRY.) Function pointers in structs are more useful for polymorphism. For example, if I had a struct vector that represented a generic container for a linear sequence of elements, it might be useful to store a comparison_func member that was a function pointer to allow sorting and searching through the vector. Each instance of the vector could use a different comparison function. However, in the case of a function that operates on the struct itself, it is better style to have a single separate function that is not duplicated in the struct.
This makes the answer to what is correct more complicated. Is what is correct how to make my above example compile? Is it how to reformat my above example so that it has good style? Or is it what is an example of a struct that uses a function pointer the way C programmer would do it? In formulating my question, I did not anticipate the answer being that my question was wrong. For completeness, I will provide an example of each answer to the question.
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*, int);
};
struct my_struct* my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
return m;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
result->set_data = my_struct_set_data;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
thing->set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
struct my_struct
{
int data;
};
void my_struct_set_data(struct my_struct* m, int new_data)
{
m->data = new_data;
}
struct my_struct* my_struct_create()
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = 0;
return result;
}
int main(int argc, const char* argv[])
{
struct my_struct* thing = my_struct_create();
my_struct_set_data(thing, 1);
printf("%d\n", thing->data);
free(thing);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct
{
void* data;
int (*compare_func)(const void*, const void*);
};
int my_struct_compare_to_data(struct my_struct* m, const void* comparable)
{
return m->compare_func(m->data, comparable);
}
struct my_struct* my_struct_create(void* initial_data,
int (*compare_func)(const void*, const void*))
{
struct my_struct* result = malloc((sizeof(struct my_struct)));
result->data = initial_data;
result->compare_func = compare_func;
return result;
}
int int_compare(const void* a_pointer, const void* b_pointer)
{
return *(int*)a_pointer - *(int*) b_pointer;
}
int string_compare(const void* a_pointer, const void* b_pointer)
{
return strcmp(*(char**)a_pointer, *(char**)b_pointer);
}
int main(int argc, const char* argv[])
{
int int_data = 42;
struct my_struct* int_comparator =
my_struct_create(&int_data, int_compare);
char* string_data = "Hello world";
struct my_struct* string_comparator =
my_struct_create(&string_data, string_compare);
int int_comparable = 42;
if (my_struct_compare_to_data(int_comparator, &int_comparable) == 0)
{
printf("The two ints are equal.\n");
}
char* string_comparable = "Goodbye world";
if (my_struct_compare_to_data(string_comparator,
&string_comparable) > 0)
{
printf("The first string comes after the second.\n");
}
free(int_comparator);
free(string_comparator);
return 0;
}
In your struct definition, change it to
struct my_struct
{
int data;
struct my_struct* (*set_data) (struct my_struct*,int);
};
and now use the above function pointer in main as
thing->set_data(thing,1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With