Why function inside an struct works C language - c

As shown in this small script.
#include <stdio.h>
struct student{
short count;
void (*addCount)();
};
void student_addCount(struct student a){
a.count++;
}
int main(){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount();
student.addCount();
student.addCount();
student.addCount();
student.addCount();
printf("%d\n",student.count);
}
I have added a pointer to a function inside a struct, but I do not know why this works as the function 'addCount' is not receiving any arguments and it actually adds up the number of times specified.
I am compiling this code with GCC 6.3.0 in different environments such as ideone.com, wandbox.org and the compiler in WSL.
here is the proof that it works with ideone.
https://ideone.com/Cam4xY

That's not a function inside a structure, it's a function pointer inside a structure.
void (*addCount)();
defines addCount as a pointer to a function. The function returns void and takes an unspecified number of arguments.
That's what the empty parentheses mean. That's an old-style non-prototype function declaration. There is rarely, if ever, a good reason to use non-prototype function declarations or definitions. If you want to specify tht a function takes no arguments, use (void) rather than ().
student.addCount = student_addCount;
The function student_addCount takes a struct student argument, but its type is still compatible with the type of your pointer member. Assigning it like this essentially disables checking on calls. This is why old-style function declarations are a bad idea.
student.addCount();
This is an indirect call via the function pointer. Since the function pointer type doesn't specify how many arguments are expected, the call is legal. Since the actual function being called requires a single argument of type struct student, the behavior is undefined. With old-style function declarations, it's entirely up to you, the programmer, to get the arguments right; the compiler won't help you.
Since you're getting what appear to be valid results, it's likely that the argument you expected to be passed happened to be in the right place in memory, perhaps on top of the stack. The function is called and it assumes, quite reasonably, that you've passed a proper argument value. It looks for that argument in memory, or in a register, and finds ... something.
Here's a version of your program without the undefined behavior:
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student a);
};
void student_addCount(struct student a){
a.count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
student.addCount(student);
printf("%d\n",student.count);
}
The output is 0 -- because the count being incremented is a member of the parameter, which is a local object.
Here's a version that does what you probably want. It passes a pointer to the structure, so the count member of your original struct student object is incremented by the function. The output is 5.
#include <stdio.h>
struct student{
short count;
void (*addCount)(struct student *a);
};
void student_addCount(struct student *a){
a->count++;
}
int main(void){
struct student student;
student.addCount = student_addCount;
student.count = 0;
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
student.addCount(&student);
printf("%d\n",student.count);
}

Related

Is it possible to modify the content of a struct pointer inside a function?

I am C begginer, I was trying to create a function that modify the content of a struct pointer, but it couldn't make it, instead, the content remains the same.
Here my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int code;
}person;
void enter(person *struct_pointer);
void main(void)
{
person *person_1 = NULL;
enter(person_1);
printf("CODE: %i\n", person_1->code);
free(person_1);
}
void enter(person *struct_pointer)
{
struct_pointer = malloc(sizeof(*struct_pointer));
struct_pointer->age = 10;
struct_pointer->code = 5090;
}
In the example above when I print code of person_1 it does not print nothing, so I assume is because person_1 is still pointing to NULL.
Can someone pls explain how can I do this, and if it cannot be made why.
Thanks
To change an object (pointers are objects) in a function you need to pass it to the function by reference.
In C passing by reference means passing an object indirectly through a pointer to it. Thus dereferencing the pointer the function has a direct access to the original object.
So your function should be declared and defined the following way
void enter(person **struct_pointer)
{
*struct_pointer = malloc(sizeof(**struct_pointer));
if ( *struct_pointer )
{
( *struct_pointer )->age = 10;
( *struct_pointer )->code = 5090;
}
}
and called like
enter( &person_1 );
Otherwise in case of this function declaration
void enter(person *struct_pointer);
the function will deal with a copy of the value of the passed pointer and changing the copy within the function will not influence on the original pointer.
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
You can modify the contents of the struct. It doesn't work for you because you are creating a new struct in the enter function rather than editing the original. Just remove the first line (the one with malloc) and instead allocate the struct in the declaration of the person_1variable.

OOP and forward declaration of structure in C

I am studying C language and have recently learned how to write the OOP using C. Most part of it was not hard that much to understand for me except the name of structures type used to create new class.
My textbook used struct dummy_t for forward declaration and typedef struct {...} dummy_t for its definition. In my understanding, these are two different type because the former is struct dummy type and the later is struct type without a name tag but the sample code from the textbook worked well.
So I deliberately modified the sample code so that the difference in the names of structures will be much clearer. Below are the lines of code I tried.
//class.h
struct test_a;
struct test_a * test_init(void);
void test_print(struct test_a*);
//class.c
#include <stdio.h>
#include <stdlib.h>
typedef struct dummy{
int x;
int y;
} test_b;
test_b * test_init(void){
test_b * temp = (test_b *) malloc(sizeof(test_b));
temp->x = 10;
temp->y = 11;
return temp;
}
void test_print(test_b* obj){
printf("x: %d, y: %d\n", obj->x, obj->y);
}
//main.c
#include "class.h"
int main(void){
struct test_a * obj;
obj = test_init();
test_print(obj);
return 0;
}
// It printed "x: 10, y: 10"
As you can see, I used struct test_a for forward declaration and typedef struct dummy {...} test_b for definition.
I am wondering why I did not get the compile error and it worked.
I am wondering why I did not get the compile error
When you compile main.c the compiler is told via a forward declaration from class.h that there is a function with the signature struct test_a * test_init(void);
The compiler can't do anything other than just trusting that, i.e. no errors, no warnings can be issued.
When you compile class.c there is no forward declaration but only the function definition, i.e. no errors, no warnings.
It's always a good idea to include the .h file into the corresponding .c file. Had you had a #include "class.h" in class.c the compiler would have been able to detect the mismatch.
..and it worked
What happens is:
A pointer to test_b is assigned to a pointer to test_a variable
The variable is then passed as argument to a function expecting a pointer to test_b
So once you use the pointer it is used as it was created (i.e. as pointer to test_b). In between you just stored in a variable of another pointer type.
Is that ok? No
Storing a pointer to one type in a object defined for another pointer type is not ok. It's undefined behavior. In this case it "just happened to work". In real life it will "just happen to work" on most systems because most systems use the same pointer layout for all types. But according to the C standard it's undefined behavior.
It 'worked' because you did not include class.h in class.c. So the compiler can't see the implementation does not match the declaration.
The proper way is (but without the typedef for clarity):
// class.h
struct test_a;
struct test_a* test_init(void);
//class.c
#include "class.h"
struct test_a {
int x;
int y;
};
struct test_a* test_init(void)
{
...
}
The struct test_a in the header file makes the name test_a known to the compiler as being a struct. But as it does not now what is in the struct you can only use pointers to such a struct.
The members are defined in the implementation file and can only be used there.
If you want to use a typedef:
// header
typedef struct test_a_struct test_a;
test_a* test_init(void);
//implementation
struct test_a_struct {
int x;
int y;
};
test_a* test_init(void)
{
...
}

Pointers + structs + functions in C identifier undefined

So this is my code and I don't understand why I get that identifier "pers" is undefined, when I'm clearly pointing at it from another function, which is as far as I know, the utility of pointers.
I've gone through some research but nothing seemed to solve my issue since I'm dealing with structs and all that.
Also one of the requirements is that tle so called "leer_persona();" cant have any value in the parenthesis
#include <stdio.h>
typedef struct{
int num;
char letra;
}tdni;
typedef struct{
char nom[20];
tdni dni;
}tpersona;
tpersona leer_persona();
void mostrar_persona(tpersona p);
int main(){
tpersona pers;
pers = leer_persona();
mostrar_persona(pers);
return 0;
}
tpersona leer_persona(){
int i=0;
int *fp;
fp = &pers;
Thanks.
Pers has function scope in "main()". It is not visible outside of "main()".
https://www.geeksforgeeks.org/scope-rules-in-c/
Function scope begins at the opening of the function and ends with the
closing of it.
See this link for more details: C - Scope Rules
If you want to use "pers" in another function, you'd typically pass it as a function parameter, e.g. tpersona leer_persona(tpersona * pers). In this example, I passed parameter "pers" by reference, instead of copying by value.

C: Putting a function pointer in a structure where the function uses that structure as an argument

I seem to have run into a chicken and egg problem.
I want to have a structure that as one of its members is a function pointer. However this function pointer wants to use that same structure as it's argument. This creates an issue where I have to define the function pointer before I can include it as a member, but I can't properly define it until I've defined the structure.
I have found that if I simply leave the argument list for the function pointer blank it SEEMS to work, though what I have read is that this is potentially fraught with issues.
Below is what I currently have:
#include <stdio.h>
typedef void (*IO_fun_ptr_t)();
typedef struct IO_config_t{
int address;
IO_fun_ptr_t IO_fun_ptr; //pointer to the function to be used
} IO_config_t;
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}
The result is:
The address is 16
Push any key to continue:
This works but I'm concerned about the potential implications of leaving that argument blank.
As a bit of an aside, I originally thought that I should be able to use void* as an argument as a placeholder for pointer to an unknown argument type, but I would get compile errors when doing so at the point where I assign the pointer to my function:
typedef void (*IO_fun_ptr_t)(void *);
(Error[Pe144]: a value of type "void (*)(IO_config_t *)" cannot be
used to initialize an entity of type "IO_fun_ptr_t")
Any advice on how to do this better and cleaner?
Use forward-declarations.
This is a way of stating that a structure exists, but without providing details of all the members of the structure until later.
#include <stdio.h>
// 1.) Forward declaration: Here is the name of the structure
// but member-details are omitted.
struct IO_config_t;
// 2.) typedef of the structure
// Still no details on the members.
typedef struct IO_config_t IO_config_t;
// 3.) The parameter to the function is listed, using the definition
// from step 2.) (note: Still no details on the members yet)
typedef void (*IO_fun_ptr_t)(IO_config_t* input);
// 4.) Now we actually detail the members of the structure
struct IO_config_t{
int address;
IO_fun_ptr_t IO_fun_ptr;
};
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}
This is demonstrated in the short program: https://ideone.com/p3jBYt
So I had searched through stack exchange and couldn't find anything so humbled myself to asking a question. Just as I'm getting to the end of writing everything up, I glance over to the "Similar Questions" box to the right, and I happen to see the following question that I didn't come across before:
How to properly define a function pointer in struct, which takes struct as a pointer?
And in its answer I found my answer. I simply have to define the function pointer in the structure itself, not before hand. (I had tried, but forgot to include the struct keyword in the definition so it didn't work since the type def wasn't complete I am guessing).
Below is what compiles clean and seems to work:
#include <stdio.h>
typedef struct IO_config_t{
int address;
void (*IO_fun_ptr)(struct IO_config_t *); //pointer to the function to be used
} IO_config_t;
void print_address (IO_config_t *input){
printf("The address is %d \n", input->address);
printf("Push any key to continue:");
getchar();
}
void main()
{
IO_config_t input = {.address = 16,
.IO_fun_ptr = &print_address};
input.IO_fun_ptr(&input);
}

How to correctly assign function pointers to elements of typedef struct

Here I provide the concrete example nevertheless. I have a typedef (from a header file maplec.h defining OpenMaple).
typedef struct {
void (M_DECL *textCallBack) ( void *data, int tag, char *output );
void (M_DECL *errorCallBack) ( void *data, M_INT offset, char *msg );
...
} MCallBackVectorDesc, *MCallBackVector;
In my code I want to assign the callback functions to use. In the examples from the manual (http://www.maplesoft.com/applications/view.aspx?SID=4383&view=html) this is done with
MCallBackVectorDesc cb = { textCallBack,
0, /* errorCallBack not used */
...
};
However I want to keep a reference to this variable cb in a structure which I defined as
struct open_maple {
MCallBackVectorDesc *call_back_vector;
};
Then I initialize with
open_maple->call_back_vector = (MCallBackVectorDesc *)malloc((size_t)sizeof(MCallBackVectorDesc));
(open_maple->call_back_vector)->textCallBack = &textCallBack;
(open_maple->call_back_vector)->errorCallBack = 0;
This code does not produce any compiler warnings nor Segfaults, but I do not seem to receive any calls of textCallBack either, while the online example version would work. I tried other definitions and assignments, but always got warnings or Segfaults.
It boils down to the question: How do I correctly assign the pointers to the callback functions collected in the typedef struct if I do not want to assign them at initialization (in the declaration of the variable cb)?
Edit 1
It has been suggested below that the error occurs because I am referencing the textCallBack function as &textCallBack function which generates a pointer from a pointer. However the example works neither with nor without the &. Note also that the following code works:
/* some standard libraries */
#include <stdlib.h>
#include <stdio.h>
void function(void){
printf("IAMHERE\n");
};
int main()
{
void (*myfunction)(void) = &function;
myfunction();
return 0;
}
I am using gcc -o test test.c to compile it.
Edit 2
Some more investigations showed that the problem is supposedly related to my use of OpenMaple.
textCallBack is defined as a pointer to function.
You're taking the address of it -- pointer to pointer to function.
Is that really what you intend to store into your structure?

Resources