I don't understand why this error continues to pop. This is the function i'm trying to build: /person is a struct. Person* is a pointer.
void(*CreateNext)(struct Person *this, int isNextNext, ...)
{
Person* person;
person = (Person*)malloc(sizeof(Person));
person = CreatePerson(person);
this->next = person;
}
The error is on the first line and on the '{'
//This is the struct:
struct Person {
char* name;
int id;
int numOfKids;
char** kids;
struct Person* next;
void (*Print)(struct Person* this);
void (*KillNext)(struct Person* this);
struct Person* (*SelfDestruct)(struct Person* this);
void (*CreateNext)(struct Person* this, int isNextNext, ...);
};
You are declaring a variable (a pointer to a function) outside the scope of a function.
You want CreateNext to be the name of a function, not the name of a variable. The declaration should be
void CreateNext(struct Person *this, int isNextNext, ...)
{
Person* person;
person = (Person*)malloc(sizeof(Person));
person = CreatePerson(person);
this->next = person;
}
BTW, you shouldn't cast the return of malloc(). Casts are evil.
Related
I'm trying to emulate the most basic (toy) case of a vtable in C. Here is a basic example:
typedef struct Person {
int id;
char *name;
} Person;
And let's say we add in one method (i.e., function pointer):
typedef struct Person {
int id;
char *name;
void (*print_name)(Person);
} Person;
And now we'll initialize it and fill in the pieces with this (let’s ignore memory leaks):
#include <stdio.h>
#include <stdlib.h>
typedef struct Person Person;
typedef struct Person {
int id;
char *name;
void (*print)(Person *self);
} Person;
void print_name(Person *person) {
printf("Hello %s\n", person->name);
}
Person *init_person(void) {
Person *person = malloc(sizeof(Person));
person->print = print_name;
}
int main(void) {
Person *p = init_person();
p->name = "Greg";
p->print(p);
return 0;
}
Running code here.
If I were to factor out the functions from the Person and put it in a Person_VTable, such as the following:
typedef struct Person {
int id;
char *name;
Person_VTable *vtable;
} Person;
typedef struct Person_VTable {
???
} Person_VTable;
What would be the proper way to (1) create the vtable, and (2) initialize the Person object with the new vtable? Note, I know this is an entirely trivial example and it can be done in better ways, but I'm seeing how it can be done with an external 'vtable' to the main object I'm working work.
Also, does this also mean if I have a vtable, instead of just having the one 'self' to reference the object it's coming from when in the struct itself, such as:
void (*print)(Person *self);
I need to have two indirections, so I know both the object and the vtable location? Something like:
void (*print)(Person *self_obj, Person_VTable *self_vt);
If so, that's a lot of overhead!
A basic vtable is nothing more than an ordinary struct containing function pointers, which can be shared between object instances. There are two basic ways one can implement them. One is to make the vtable pointer an ordinary struct member (this is how it works in C++ under the hood):
#include <stdio.h>
#include <stdlib.h>
typedef struct Person Person;
typedef struct Person_VTable Person_VTable;
struct Person {
int id;
char *name;
const Person_VTable *vtable;
};
struct Person_VTable {
void (*print)(Person *self);
};
void print_name(Person *person) {
printf("Hello %s\n", person->name);
}
static const Person_VTable vtable_Person = {
.print = print_name
};
Person *init_person(void) {
Person *person = malloc(sizeof(Person));
person->vtable = &vtable_Person;
return person;
}
int main(void) {
Person *p = init_person();
p->name = "Greg";
p->vtable->print(p);
return 0;
}
Another is to use fat pointers (this is how it’s implemented in Rust):
#include <stdio.h>
#include <stdlib.h>
typedef struct Person Person;
typedef struct Person_VTable Person_VTable;
typedef struct Person_Ptr {
Person *self;
const Person_VTable *vtable;
} Person_Ptr;
struct Person {
int id;
char *name;
const Person_VTable *vtable;
};
struct Person_VTable {
void (*print)(Person_Ptr self);
};
void print_name(Person_Ptr person) {
printf("Hello %s\n", person.self->name);
}
static const Person_VTable vtable_Person = {
.print = print_name
};
Person_Ptr init_person(void) {
Person_Ptr person;
person.self = malloc(sizeof(Person));
person.vtable = &vtable_Person;
return person;
}
int main(void) {
Person_Ptr p = init_person();
p.self->name = "Greg";
p.vtable->print(p);
return 0;
}
In C, the preferred way is the former, but that’s mostly for syntax reasons: passing structs between functions by value doesn’t have a widely-agreed-upon ABI, while passing two separate pointers is rather unwieldy syntactically. The other method is useful when attaching a vtable to an object whose memory layout is not under your control.
In essence, the only advantages of vtables over ordinary function pointer members is that they conserve memory (each instance of the struct only needs to carry one vtable pointer) and protect against memory corruption (the vtables themselves can reside in read-only memory).
You can do this without making too many changes. To start, we will define the Person and Person_VTable types:
typedef struct Person Person;
typedef struct Person_VTable {
void (*print) (Person* self);
} Person_VTable;
typedef struct Person {
int id;
char* name;
Person_VTable *vtable;
} Person;
Here we have replaced the previous Person function pointer with a pointer to the Person_VTable type, which will hold our functions. The Person_VTable itself is almost identical to what the functions in the Person type were previously -- notice even that the function signatures are the same. For example:
// old
typedef struct Person {
// ...
void (*print)(Person *self);
} Person;
// new
typedef struct Person_VTable {
// ...
void (*print)(Person *self);
} Person_VTable;
Our init function is also similar, however now we need to malloc for the Person_VTable object, since that is now held outside our main Person object. This will give us:
Person* init_person(void) {
Person *person = malloc(sizeof(Person));
// malloc the vtable and attach the print method to it.
person->vtable = malloc(sizeof(Person_VTable));
person->vtable->print = print_name;
return person;
}
Finally, to put everything together with a working example here:
#include<stdio.h>
#include<stdlib.h>
typedef struct Person Person;
typedef struct Person_VTable {
void (*print) (Person* self);
} Person_VTable;
typedef struct Person {
int id;
char* name;
Person_VTable *vtable;
} Person;
void print_name(Person* person) {
printf("Hello %s\n", person->name);
}
Person* init_person(void) {
Person *person = malloc(sizeof(Person));
person->vtable = malloc(sizeof(Person_VTable));
person->vtable->print = print_name;
return person;
}
int main(void) {
Person* self = init_person();
self->name = "Greg";
self->vtable->print(self);
return 0;
}
Let's say I have some hashmap that can refer to itself, something like:
typedef struct Person {
char* name;
Person* mother;
Person* father;
} Person;
Person *Bob = malloc(sizeof(Person));
bob->name = "Bob";
bob->mother = Kathy;
bob->father = Bill;
What are the suggested ways to get around the error: unknown type name ‘Person’ error?
Person is not defined yet, since the typedef only takes effect after the semicolon concluding it. To refer to the struct from within itself, use struct Person. The following code compiles with no errors on GCC 10.2.0.
typedef struct Person {
char* name;
struct Person* mother;
struct Person* father;
} Person;
int main() {
Person Kathy = { "Kathy", NULL, NULL };
Person Bill = { "Bill", NULL, NULL };
Person Bob = { "Bob", &Kathy, &Bill };
return 0;
}
The problem is that the name Person used within the structure definition as a type specifier for data members mother and father
typedef struct Person {
char* name;
Person* mother;
Person* father;
} Person;
is not yet declared.
Either use a typedef before the structure definition like
typedef struct Person Person;
struct Person{
char* name;
Person* mother;
Person* father;
};
Or use the declared structure tag in the structure definition like
typedef struct Person {
char* name;
struct Person* mother;
struct Person* father;
} Person;
While the typedef is not defined, the struct tag is so you can prepend that to the elements of the struct. For example:
typedef struct Person {
char* name;
struct Person* mother;
struct Person* father;
} Person;
#include <stdlib.h>
int main(void) {
// parents (ignore their parents)
Person *Kathy = malloc(sizeof(Person));
Kathy->name = "Kathy";
Person *Bill = malloc(sizeof(Person));
Bill->name = "Bill";
// person
Person *Bob = malloc(sizeof(Person));
Bob->name = "Bob";
Bob->mother = Kathy;
Bob->father = Bill;
printf("Name: %s | Mom: %s, Dad: %s\n", Bob->name, Bob->mother->name, Bob->father->name
free(Bob); free(Kathy); free(Bill);
}
Name: Bob | Mom: Kathy, Dad: Bill
To be specific: Function overriding with the ability to call the base overridden methods.
There are two pieces to this. One is the pre-compiled library code (1), and the other is the User of the Library code (2). I'm implementing a smallest possible, classic Person and Employee example here.
Will highly appreciate a response from a hardcore C developer who knows OOP concepts. I'm developing both Library and User of the Library code, so I've control in both places.
1 A) Library Code (Pre-compiled)
person.h
typedef struct Person Person;
struct Person {
char* name;
void (*display)(const Person *self);
};
Person* PersonNew(char* name);
person.c
static void display(const Person *self) {
printf("Name: %s\n", self->name);
}
Person* PersonNew(char* name) {
Person* self = malloc(sizeof(Person));
if(self == NULL) return NULL;
self->name = strdup(name);
self->display = display;
return self;
}
1 B) Library can receive structs with composed Persons via pointers because it's library's responsibility to print these structs (therefore library doesn't know the existence of Employee struct)
void print(Person *person) {
person->display(person); // problem, can only print name, no company
}
2) The user of the Library Code
employee.h
typedef struct Employee Employee;
struct Employee {
Person super;
char* company;
void (*display)(const Employee *self);
};
Employee* EmployeeNew(char* name, char* company);
employee.c
static void display(const Employee *self) {
self->super.display(&self->super); // re-use super display
printf("Company: %s\n", self->company);
}
Employee* EmployeeNew(char* name char* company) {
Employee* employee = malloc(sizeof(Employee));
if(employee == NULL) return NULL;
free(employee->super); // I also have memory leak issue.
employee->super = *PersonNew(name); // library method to get struct with functions.
employee->company = strdup(company);
employee->display = display; // it's own version of display
return employee;
}
main.c
Employee *employee = EmployeeNew("John", "Acme");
print(employee); // problem, calls base method, prints name only
// employee->display(); // works fine, but the requirement is somehow enable library code to be able to call employee version of display.
Since you put Person at the beginning of Employee hence there is no issue, but if you move to other location, it might lead to exception.
The Employee struct will look like:
struct Employee {
char* name;
void (*display)(const Person *self);
char* company;
void (*display)(const Employee *self);
};
Hence when you pass to print, since the print accepts only upper part of Employee:
struct Employee {
char* name;
void (*display)(const Person *self);
};
the call of display will redirect to display of Person. hence there is only name printing.
To override Person's display, let change these two structs to:
struct Person {
void (*display)(const Person *self);
char* name;
};
struct Employee {
void (*display)(const Employee *self);
Person super;
char* company;
};
By moving all operands to beginning of struct, it will work -> but this is dangerous.
A quick and rather unsophisticated way to do it could be something like the following.
typedef struct Person Person;
typedef void (*DISPLAYPROC)(const Person* self);
struct Person {
char* name;
DISPLAYPROC display;
};
void ConstructPerson(Person* self, const char* name);
Person* NewPerson(const char* name);
void person_display(const Person* self);
void person_display(const Person* self) {
printf("Name: %s\n", self->name);
}
void ConstructPerson(Person* self, const char* name)
{
self->name = _strdup(name);
self->display = person_display;
}
Person* NewPerson(const char* name) {
Person* self = (Person *)malloc(sizeof(Person));
if (self == NULL) return NULL;
ConstructPerson(self, name);
return self;
}
void print(Person* person) {
person->display(person); // dispatched at runtime to the right 'display'
}
typedef struct Employee Employee;
struct Employee {
Person super;
char* company;
};
void ConstructEmployee(Employee* self, const char* name, const char* company);
Employee* NewEmployee(const char* name, const char* company);
void employee_display(const Employee* self);
void employee_display(const Employee* self) {
person_display((const Person*)self);
printf("Company: %s\n", self->company);
}
void ConstructEmployee(Employee* self, const char* name, const char* company)
{
ConstructPerson(&self->super, name);
self->super.display = (DISPLAYPROC)employee_display;
self->company = _strdup(company);
}
Employee* NewEmployee(const char* name, const char* company) {
Employee* self = (Employee *)malloc(sizeof(Employee));
if (self == NULL) return NULL;
ConstructEmployee(self, name, company);
return self;
}
int main()
{
Person* person = NewPerson("Bob");
print(person); // calls person_display
Employee* employee = NewEmployee("John", "Acme");
print((Person*)employee); // calls employee_display
free(person);
free(employee);
}
A few notes:
Person is embedded as a field (not a pointer) in Employee so that the casts are legal between Person* and Employee*;
the New/Construct functions separate the initialization from the allocation, which was mentioned in the comments before.
the display functions are made visible (not static) so that a "derived" class can call the "base" function.
Left for the reader to fill in:
Destruct functions paired with the Construct ones, so that the allocated strings get duly freed;
separation of data initialization from "vtable" initialization, so that for example the display pointer is not initialized twice in ConstructEmployee (once in the nested ConstructPerson then overwritten immediately after in ConstructEmployee).
Filling in Destruct function for the review only. Destruction of Derived class first before the Base class.
employee.c
void EmployeeDestruct(Employee *self) {
free(self->company); // destruct derived first
PersonDestruct(&self->super); // then destruct base
}
person.c
void PersonDestruct(Person *self) {
free(self->name);
// free(self); // removing since it'd fail badly for local stack vars
}
I am new to C. I got asked to modify this program so that the variables student and anotherStudent are not global but are local to main.It will still be printed by printStudnets. typedef is not allowed to use.
I understand if declare struct in main and it would be ascessible to the main function only.Do I have to declare struct in each function to achieve this?
#include <stdio.h>
#include <stdlib.h>
struct student_s {
char* name;
int age;
struct student_s* next;
} student;
struct student_s anotherStudent;
void printOneStudent(struct student_s student)
{
printf("%s (%d)\n", student.name, student.age);
}
void printStudents(const struct student_s* student)
{
while (student != NULL) {
printOneStudent(*student);
student = student->next;
}
}
int main(void)
{
student.name = "Agnes McGurkinshaw";
student.age = 97;
student.next = &anotherStudent;
anotherStudent.name = "Jingwu Xiao";
anotherStudent.age = 21;
anotherStudent.next = NULL;
printStudents(&student);
return EXIT_SUCCESS;
}
You don't need to use typedef in order to define a new structured type. This is perfectly valid:
struct student_s {
char* name;
int age;
struct student_s* next;
}; // Remove "student". Now you don't have a global variable.
A consequence of this is that student_s is not a name of your structured type; it is a tag of your structured type. Therefore, declaring objects of structured type corresponding to student_s must start with the keyword struct:
int main(void)
{
struct student_s student;
... // The rest of your code remains the same
}
I'm trying to create a structure, that has a function pointer. That function pointer points to a function, that takes a pointer of said structure. This is a real chicken-or-the-egg problem because the prototype needs to know about the structure and the structure needs to know about the prototype. Is there a way to predefine the struct? I'm new to C so if anyone has any insight I would greatly appreciate it.
Thanks,
-devnull
#include <stdio.h>
/* predefine struct person? */
void printInfo(struct person *);
struct person{
char *name;
int age;
const void *pf = printInfo;
};
int main(){
struct person master = {"Master", 23};
return 0;
}
void printInfo(struct person *p){
printf("Name:\t%s\n", p->name);
}
struct person;
typedef void (*fp)(struct person*);
struct person {
char * name;
fp fptr;
};
void afunc( struct person * p ) {
// stuff
}
int main() {
struct person p = { "fred", afunc };
}
You can add the struct person; before the function, but you cannot assign the function in struct person as far as I know,
#include <stdio.h>
struct person;
typedef void (FUNCTYPE)(struct person *);
void printInfo(struct person *);
struct person{
char *name;
int age;
FUNCTYPE *pf;
};
int main(){
struct person master = {"Master", 23, printInfo};
(master.pf)(&master);
return 0;
}
void printInfo(struct person *p){
printf("Name:\t%s\n", p->name);
}
The example above prints Name: Master
The only thing I would add is that all struct pointers have the same width and alignment (6.2.5/27 (C99 Standard)), so you don't actually require the forward definition of the struct.