I am just working on a liberty functions in which we define our own datatypes for student and book I have to write a code which finds student by id and book by id these are the two functions. In this functions the pointers which I pass are different but the logic is the same so I got a though that why can't we write one function and pass which thing we want. I mean when we pass the student list it will return the index of student when we pass the book list it will return the book index of the book. Can we use void pointers for that??? Thank you everyone!!!
int findBookId(Book* booklist,int* bcount,unsigned int* tbid)
{
int i;
for (i=0; i<*bcount; i++)
{
if (booklist[i].id==*tbid)
{
return i;
}
}
return NOT_FOUND;
}
int findStuId(Student* stulist,int* scount,unsigned int* tsid)
{
int i;
for (i=0; i<*scount; i++)
{
if (stulist[i].id==*tsid)
{
return i;
}
}
return NOT_FOUND;
}
Assuming you have a student structure:
struct student {
int id;
char name[20];
};
You can imitate qsort() function, to design a parameter to receive a callback function and to receive the size and size of each element if you'd like use void *.
int find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
Then, define a "tester":
int student_tester(const void *p1, const void *p2)
{
struct student *sp = (struct student *) p1;
int id = *(int *) p2;
return sp->id == id;
}
In main() function:
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list,
sizeof(struct student), student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
This is a bit complicated. You can create macros to simplify it if you don't care.
Rename find_ele to _find_ele, and create a macro:
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
And create another macro to define a "tester":
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
Now you can define a "tester" like this:
define_tester(student_tester, struct student, int,
p->id == value);
Complete code:
#include <stdio.h>
int _find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
struct student {
int id;
char name[20];
};
define_tester(student_tester, struct student, int,
p->id == value);
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list, student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
Yes you can use void*, but while dereferencing you should know the exact type of the pointer.
So, when you can your function, add another parameter:
type = 0 for Books
= 1 for students
And then your function becomes:
int findId(void* list,int* count,unsigned int* tbid, int type)
{
Book* booklist=NULL;
Student* stulist=NULL;
int i;
if(type===0)
booklist = (Book*) list;
else if(type==1)
stulist = (Student*) list;
else
// Handle this undefined case
// And now use the same type variable to decide which pointer to use to match the values
. . . .
}
Yes you can use void pointer, if you are trying to store address of your array..Your array may contain integer types or some other datatypes stored, it doesn't matter, but right typecasting while de-referencing the void pointer is important.
I don't think you can use void* in these functions.
If you changed your functions to one and created something like:
int findObjId(void* objlist,int* count, unsigned int* objid)
{
int i;
for (i=0; i<*scount; i++)
{
if (objlist[i].id==*objid)
{
return i;
}
}
return NOT_FOUND;
}
you won't be able to extract the data from objlist. Neither *objlist, nor objlist[i] can be dereferenced to evaluate to an object. The compiler will definitely stop you from using any such statement.
If you have the option, switch to C++. Using templates, you can accomplish your goal without breaking a sweat.
Related
I'm trying to make a small library for particle management that allows to "expand" struct with user's data (texture, animation frames, etc). The library would know only the size of the expanded struct.
How do I iterate through the array of unknown struct types but known size of a struct?
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
int main(){
size_t size = sizeof(inherited);
int count = 10;
void *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( &( (size)b )[i] );
}
free(b);
return 0;
}
I assume the code that does the malloc and calls callback doesn't know anything about the type of the object, only its size.
#include <stdlib.h>
void *alloc_and_init(size_t nmemb, size_t size, void (*callback)(void *))
{
void *b = calloc(nmemb, size);
if (b)
{
char *p = b;
for (size_t i = 0; i < nmemb; i++)
{
callback(p);
p += size;
}
}
return b;
}
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
void init_inherited(void *p)
{
inherited *obj = p;
/* do initialization of obj->* here */
}
int main(void)
{
int objcount = 10;
inherited *objarr;
objarr = alloc_and_init(objcount, sizeof(*objarr),
init_inherited);
/* ... */
free(objarr);
}
for( inherited *p = b, *e = p + count; p < e; p++ ){
callback(p);
}
char *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( b + i * size );
}
Polymorphism in C is always rather clunky. Basically you have to construct a "vtable" manually. The naive, simplified version below lets each object have its own function pointer. You'll end up with something rather contrived like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct base_t base_t;
typedef void callback_t (const base_t* arg);
struct base_t
{
int type;
callback_t* callback;
};
typedef struct
{
base_t base;
int value;
} inherited_t;
void callback_base (const base_t* arg)
{
puts(__func__);
}
void callback_inherited (const base_t* arg)
{
const inherited_t* iarg = (const inherited_t*)arg;
printf("%s value: %d\n", __func__, iarg->value);
}
int main (void)
{
// allocate memory
base_t* array [3] =
{
[0] = malloc(sizeof(inherited_t)),
[1] = malloc(sizeof(base_t)),
[2] = malloc(sizeof(inherited_t)),
};
// initialize objects
*(inherited_t*)array[0] = (inherited_t){ .base.callback=callback_inherited, .value = 123 };
*(array[1]) = (base_t){ .callback=callback_base };
*(inherited_t*)array[2] = (inherited_t){ .base.callback=callback_inherited, .value = 456 };
for (int i = 0; i < 3; i++)
{
array[i]->callback(array[i]); // now we get polymorphism here
}
}
A more professional version involves writing a translation unit (.h + .c) per "class" and then combine allocation with initialization in the "constructor". It would be implemented with opaque type, see How to do private encapsulation in C? Inside the constructor, set the vtable corresponding to the type of object allocated.
I'd also boldly claim that any OO solution using void* arguments has some design flaw. The interface should be using the base class pointer. Void pointers are dangerous.
I have difficulty applying the pass by reference and pass by value separation in structs.How can I swap the elements of the fixed size struct array as below.
struct try{
int num;
char name[10];
};
int main(){
struct try book[3];
void swapper(/********/);// <-what should be the argument of this function
}
void swapper(/********/){//swap second and third element of struct array
/*how the swap may be done?
temp=book[2];
book[2]=book[3];
temp=book[3];*/
}
There are a lot of ways to do what you're asking. One approach:
#include <stdio.h>
struct try {
int num;
char name[10];
};
void
swapper(struct try *a, int b, int c)
{
struct try tmp = a[b];
a[b] = a[c];
a[c] = tmp;
}
void
display(const struct try *t, size_t count)
{
while( count-- ){
printf("%d: %s\n", t->num, t->name);
t += 1;
}
}
int
main(void) {
struct try book[] = {
{ 1, "foo"},
{ 2, "bar"},
{ 3, "baz"}
};
display(book, sizeof book / sizeof *book);
swapper(book, 1, 2);
display(book, sizeof book / sizeof *book);
return 0;
}
I want to perform a simple task working with function pointers in C.
The task is to get an array (from any type, i.e: int / char*), and sum /concatenate each 2 elements in the array.
for the char* type, it works fine, but for the int type, the loop seems to jump each 2 elements in the array (and thus overflow the array):
#define N1 4
#define N2 4
typedef void*(*Fn_Sum)(void*, void*);
typedef void(Fn_Prt)(void*);
int sum_num(int a, int b){
return a + b;
}
char* sum_char(char* a, char* b){
char *result = malloc(strlen(a) + strlen(b) + 1);
if (!result) {
printf("ERROR: malloc failed !\n");
return NULL;
}
strcpy(result, a);
strcat(result, b);
return result;
}
void print_num(int a){
printf("%d", a);
}
void print_string(char* a){
int i = 0;
while (a[i] != '\0') {
printf("%c", a[i]);
i++;
}
}
void PrintSums(void** P, int n, Fn_Sum fsum, Fn_Prt fprt){
for(int i = 0; i < n - 1; i++){
(fprt)(fsum(P[i], P[i+1]));
printf(", ");
}
printf("\n");
}
int main() {
int V[N1] = {1,2,3,4};
char* S[N2] = {"a", "d", "c", "d"};
PrintSums(V, N1, sum_num, print_num);
PrintSums(S, N2, sum_char, print_string);
return 0;
}
expected output is :
3, 5, 7,
ab, bc, cd,
actual outputs:
4, 725939, 4925336,
ad, dc, cd,
Create an abstract interface for iterator over the elements. A draft of such interface could look like this:
struct iterator {
...
};
// ptr - a pointer to beginning of the array
// size - size of one element in the array
void it_init(iterator *t, void *ptr, size_t size);
bool it_eq(iterator *t, iterator *o); // compare iteratores
void it_add(iterator *t, size_t n);
void it_inc(iterator *t);
// return a pointer to the element
void *it_get(iterator *t);
Remember to always pass to user callbacks a context variables. Otherwise users will have to use global variables, which make code messy. Create an abstract interface with destructors and constructors of your summing object. Handle errors properly:
// is passed a pointer to user context
// returns 0 on success
typedef int (*Fn_Sum)(void*, void*);
// is passed a pointer to user context
// returns 0 on success
typedef int (Fn_Prt)(void*);
// returns 0 on success
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx);
After that, implement objects that expose the interface that you want:
struct num { .. };
void num_sum(struct num *t, int el);
void num_print(struct num *t, int el);
// expose interface to PrintSums
// that just calls internal api
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
An example whole program looks like this:
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// iterator
typedef struct iterator {
void *ptr;
size_t size;
} iterator;
void it_init(iterator *t, void *ptr, size_t size) {
*t = (iterator){ ptr, size, };
}
// eq is from test(1) shell command. "eq" means "equal"
bool it_eq(iterator *t, iterator *o) {
return t->ptr == o->ptr;
}
void it_add(iterator *t, size_t n) {
t->ptr = (char*)t->ptr + t->size * n;
}
// increment the iterator
void it_inc(iterator *t) {
it_add(t, 1);
}
// return a pointer to the element
void *it_get(iterator *t) {
return t->ptr;
}
// interface
typedef int (*Fn_Sum)(void*, void*);
typedef int (Fn_Prt)(void*);
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx){
iterator end = it;
it_add(&end, n);
for(; !it_eq(&it, &end); it_inc(&it)) {
int err = fsum(sumctx, it_get(&it));
if (err) return err;
err = fprt(sumctx);
if (err) return err;
printf(", ");
}
printf("\n");
return 0;
}
// num object
struct num {
int sum;
};
void num_init(struct num *t) {
t->sum = 0;
}
void num_sum(struct num *t, int el){
t->sum += el;
}
void num_print(struct num *t){
printf("%d", t->sum);
}
void num_free(struct num *T) {
// nothing, just exists for uniform API
}
// accessors for PrintSums
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
// string object
struct str {
char *str;
};
void str_init(struct str *t) {
t->str = NULL;
}
int str_sum(struct str *t, const char *str) {
const size_t str_len = t->str == NULL ? 0 : strlen(t->str);
void *p = realloc(t->str, str_len + strlen(str) + 1);
if (p == NULL) {
free(t->str);
t->str = NULL;
return -1;
}
t->str = p;
memcpy(t->str + str_len, str, strlen(str) + 1);
return 0;
}
void str_print(struct str *t) {
if (t->str == NULL) {
printf("(nul)");
} else {
printf("%s", t->str);
}
}
void str_free(struct str *t) {
free(t->str);
}
// interface for PrintSums
int str_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct str *t = ctx;
const char **el = el0;
str_sum(t, *el);
return 0;
}
int str_PrintSums_Fn_Prt(void *ctx) {
struct str *t = ctx;
str_print(t);
return 0;
}
// and finally main
int main() {
int err = 0;
int V[] = {1,2,3,4};
iterator numit;
it_init(&numit, V, sizeof(*V));
struct num numsum; // the object that will hold the sum
num_init(&numsum);
err = PrintSums(numit, sizeof(V)/sizeof(*V), num_PrintSums_Fn_Sum, num_PrintSums_Fn_Prt, &numsum);
if (err) abort();
num_free(&numsum);
char *S[] = {"a", "d", "c", "d"};
iterator strit;
it_init(&strit, S, sizeof(*S));
struct str strsum; // the object that will hold the sum of strings
str_init(&strsum);
err = PrintSums(strit, sizeof(S)/sizeof(*S), str_PrintSums_Fn_Sum, str_PrintSums_Fn_Prt, &strsum);
if (err) abort();
str_free(&strsum); // YES! Remember to pick out the trash
}
and outputs on godbolt:
1, 3, 6, 10,
a, ad, adc, adcd,
The pointers to a constructor and destructor of "sum objects" could be passed to PrintSums too. That said one could start thinking about creating a virtual table for all these pointers (ie. one struct with function pointers that are needed for PrintSums...).
Is it possible to have a function in C return a 'dynamic' return type
example
printResult (NumOrChar());
void* NumOrChar(void) {
// return int or char
}
void printResult (void* input) {
if (isdigit(input)) {
printf("It's a number");
}
else {
printf("It's not a number");
}
Functions can certainly return void *. But that is a specific pointer type with properties that make it suitable for conveying pointers to objects of any type. It is not a general-purpose wildcard type. Moreover, it does not carry any kind of information about the actual type, if any, of the object to which it points, so there is no way to determine that type dynamically. A C++ programmer might describe this situation as C not providing any RTTI.
Instead, you can return a type that can convey objects of a variety of types, known in advance, with a mechanism to discriminate among those. For example,
union num_or_string {
struct { _Bool is_num; };
struct { _Bool _x1; int num; };
struct { _Bool _x2; char *string; };
};
union num_or_string NumOrChar(void) {
// return a union num_or_string containing an int or a char *
}
void printResult (union num_or_string) {
if (num_or_string.is_num) {
printf("It's a number: %d\n", num_or_string.num);
} else {
printf("It's a string: %s\n", num_or_string.string);
}
}
You can use _Generic in some circumstances
int func_int(int *p)
{
printf("%s\n", __FUNCTION__);
return 5; /* does not make too much sense */
}
float func_float(float *p)
{
printf("%s\n", __FUNCTION__);
return 5.0f; /* does not make too much sense */
}
double func_double(double *p)
{
printf("%s\n", __FUNCTION__);
return 5.0; /* does not make too much sense */
}
#define func(p) _Generic((p), \
int *: func_int, \
float *: func_float, \
double *: func_double)(p) \
Instead of having a block of ifs, one can use a structure of function pointers as a virtual table, including to_string. The following dynamically creates the Type, which can be Num or Letter.
#include <stddef.h> /* offsetof */
#include <stdio.h> /* [|s|sn]printf, fgets, stdin */
#include <stdlib.h> /* malloc, free, strtol */
#include <ctype.h> /* isdigit */
#include <errno.h>
#include <assert.h>
struct Type;
typedef void (*TypeToString)(const struct Type *const, char (*const)[32]);
typedef void (*TypeAction)(struct Type *const);
struct Type {
const struct TypeVt *vt;
};
/* Num extends Type. */
struct Num {
struct Type base;
int value;
};
static struct Num *num_upcast(struct Type *const type) {
return (struct Num *)(void *)((char *)type - offsetof(struct Num, base));
}
static const struct Num *const_num_upcast(const struct Type *const type) {
return (const struct Num *)(const void *)((const char *)type
- offsetof(struct Num, base));
}
static void num_to_string(const struct Type *const type, char (*const a)[32]) {
const struct Num *const num = const_num_upcast(type);
snprintf(*a, sizeof *a, "%d", num->value); /* C99. */
}
static void num_delete(struct Type *const type) {
struct Num *const num = num_upcast(type);
free(num);
}
/* Letter extends Type. */
struct Letter {
struct Type base;
char letter;
};
static struct Letter *letter_upcast(struct Type *const type) {
return (struct Letter *)(void *)((char *)type
- offsetof(struct Letter, base));
}
static const struct Letter *const_letter_upcast(const struct Type *const type) {
return (const struct Letter *)(const void *)((const char *)type
- offsetof(struct Letter, base));
}
static void letter_to_string(const struct Type *const t, char (*const a)[32]) {
const struct Letter *const letter = const_letter_upcast(t);
sprintf(*a, "%c", letter->letter);
}
static void letter_delete(struct Type *const type) {
struct Letter *const letter = letter_upcast(type);
free(letter);
}
static const struct TypeVt {
const char *name;
const TypeToString to_string;
const TypeAction delete;
} num_vt = { "num", &num_to_string, &num_delete },
letter_vt = { "char", &letter_to_string, &letter_delete };
static void type_to_string(const struct Type *const t, char (*const a)[32]) {
assert(t);
t->vt->to_string(t, a);
}
static void type_delete(struct Type *const t) {
assert(t);
t->vt->delete(t);
}
static struct Type *num(const int value) {
struct Num *num = malloc(sizeof *num);
if(!num) return 0;
num->base.vt = &num_vt;
num->value = value;
return &num->base;
}
static struct Type *letter(const char letter) {
struct Letter *l = malloc(sizeof *l);
if(!l) return 0;
l->base.vt = &letter_vt;
l->letter = letter;
return &l->base;
}
static struct Type *read_type(void) {
struct Type *type;
char buffer[64];
if(!fgets(buffer, sizeof buffer, stdin)) return 0;
if(isdigit(buffer[0])) {
long n;
errno = 0;
n = strtol(buffer, 0, 0);
if(errno) return 0;
type = num(n);
} else {
type = letter(buffer[0]);
}
return type;
}
int main(void) {
char a[32];
struct Type *type = 0;
int is_success = 0;
do {
if(!(type = read_type())) break;
type_to_string(type, &a);
printf("\"%s\" is of type %s.\n", a, type->vt->name);
is_success = 1;
} while(0); {
if(type) type_delete(type);
}
if(!is_success) return perror("Failure"), EXIT_FAILURE;
return EXIT_SUCCESS;
}
Probably overkill for your function, but as one has more types, this becomes increasingly attractive. One can consider a union of similar spaced types so that it could be allocated entirely on the stack.
$ bin/numorchar
524645 3456542563456
"524645" is of type num.
$ bin/numorchar
6245635724564357652654245634576
Failure: Result too large
$ bin/numorchar
ata gfddsgsdg
"a" is of type char.
$ bin/numorchar
"
" is of type char.
I guess you are speaking about the C# feature (according to my Google search).
In C, it's not possible unless doing it yourself (other answers show examples). It can be easy or hard depending of your needs. You should think about switching to another language if you really want this (they are sometimes called variants in them).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do function pointers in C work?
Surfing on stackoverflow I found this example:
/* Validation functions start */
void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue();
}
int getNextRandomValue(void)
{
return rand();
}
int main(void)
{
int myarray[10];
populate_array(myarray, 10, getNextRandomValue);
...
}
I was wondering, imagine getNextRandomValue had a parameter getNextRandomValue(int i), how would I include this and making the function accepting inputs?
Many thanks
Common practice is to pass a pointer to "data" together with the function. When function gets called, pass that "data" pointer into function and assume that the function itself knows what to do with that data. In fact the data is usually a pointer to a structure. So the code looks like this:
struct func1_data {
int a;
int b;
};
struct func2_data {
char x[10];
};
int function1(void *data) {
struct func1_data *my_data = (typeof(my_data)) data;
/* do something with my_data->a and my_data->b */
return result;
}
int function2(void *data) {
struct func2_data *my_data = (typeof(my_data)) data;
/* do something with my_data->x */
return result;
}
and assume we have
int caller(int (*callback), void *data) {
return callback(data);
}
Then you call all this like this:
struct func1_data data1 = { 5, 7 };
struct func2_data data2 = { "hello!" };
caller(function1, (void *) &data1);
caller(function2, (void *) &data2);
It's probably a good idea to get familiar with function-pointer syntax. You need to change the argument to int (*getNextValue)(int).
Then your code should be like this...
void populate_array(int *array, size_t arraySize, int (*getNextValue)(unsigned int))
{
unsigned int seedvalue = 100;
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue(seedvalue);
}
int getNextRandomValue(unsigned int seed)
{
srand(seed);
return rand();
}
int main(void)
{
int myarray[10];
populate_array(myarray, 10, getNextRandomValue);
...
}