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;
}
Related
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...).
I'm having trouble with a certain "program flow" that I'm trying to implement.
The output in the following MWE is supposed to say "Sum: 10" but it says "Sum: 0" because the function set_array_element does not set array elements. Why doesn't it?
#include <stdio.h>
#include <stdlib.h>
typedef struct example example;
struct example {
int nrOf;
double a[];
};
void initialize_example_array(example *e);
void set_array_element(double *el);
example new_example(int nrOf)
{
example *e = malloc(sizeof(example) + nrOf*sizeof(double));
e->nrOf = nrOf;
initialize_example_array(e);
return *e;
}
void initialize_example_array(example *e)
{
printf("%d\n", e->nrOf);
for(int i=0; i<e->nrOf; i++)
{
set_array_element(&e->a[i]);
}
}
void set_array_element(double *el)
{
*el = 1;
}
int main(int argc, const char * argv[]) {
example e = new_example(10);
printf("%d\n", e.nrOf);
int i, s=0;
for(i=0; i<e.nrOf; i++)
{
printf("%f\n", e.a[i]);
s+= e.a[i];
}
printf("Sum: %d\n", s);
return 0;
}
The flexible array member, this is the member a of struct example, is not a pointer. It's address is calculated using the address of the struct.
A struct with a flexible array member cannot be assigned using the simple assignment operator, like it is done in your example:
example e = new_example(10);
where the function returns:
return *e;
You will have to return the pointer:
example* new_example(int nrOf)
{
example *e = malloc(sizeof(example) + nrOf*sizeof(double));
e->nrOf = nrOf;
initialize_example_array(e);
return e;
}
example* e = new_example(10);
printf("%d\n", e->nrOf);
...
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.
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);
...
}
I am trying to sort a struct run array called results by a char, but when I print the array, nothing is sorted. Have a look at this:
struct run {
char name[20], weekday[4], month[10];
(And some more...)
};
typedef struct run run;
int name_compare(const void *a, const void *b)
{
run *run1 = *(run **)a;
run *run2 = *(run **)b;
return strcmp(run1->name, run2->name);
}
int count_number_of_different_persons(run results[])
{
int i = 0;
qsort(results, sizeof(results) / sizeof(run), sizeof(run), name_compare);
for(i = 0; i <= 999; i++)
{
printf("%s\n", results[i].name);
}
// not done with this function yet, just return 0
return 0;
}
The output from the above is just a list of names in the order they were originally placed
int count_number_of_different_persons(run results[])
This doesn't really let you use sizeof on the array, because array is decayed to pointer.
This
run *run1 = *(run **)a;
also looks weird, shouldn't it be
run *run1 = (run*)a;
?
One problem is in name_compare. Try this instead:
int name_compare(const void *a, const void *b)
{
run *run1 = (run *)a;
run *run2 = (run *)b;
return strcmp(run1->name, run2->name);
}
Check the following code:
As #michel mentioned, sizeof(array) provides size of the pointer, not the size of the array itself, as while passing array it is treated as a pointer. Hence either send the number of elements to the function count_number_of_different_persons or define a MACRO of number of elements. Hope this helps. :).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOE 3
struct run
{
char name[20];
};
typedef struct run run;
int name_compare (const void *a, const void *b )
{
return strcmp (((run *)a)->name, ((run *)b)->name);
}
int count_number_of_different_persons(run results[], int noOfElements)
{
int i=0;
qsort(results, noOfElements, sizeof (run), name_compare);
for (i=0; i<noOfElements; i++)
printf ("%s\n",results[i].name);
}
int main ( int argc, char * argv[])
{
run a, b, c;
run arg[NOE];
strcpy (a.name, "love");
strcpy (b.name, "you");
strcpy (c.name, "i");
arg[0] = a;
arg[1] = b;
arg[2] = c;
count_number_of_different_persons(arg, sizeof(arg)/sizeof(run));
};