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
}
Related
First, this is merely an academic question. I know C is not the job for doing OOP programming, but this is more of a learning exercise for a beginner learning what's possible and what's not (or perhaps, what might be possible but is not a good idea).
Let's take the following as a starting place, where I have two different objects but I want to give each of them the same two methods: create and print. I've omitted any error checking, freeing, etc. just to simplify matters:
#include <stdio.h>
#include <stdlib.h>
struct Person {
char* name;
int age;
};
struct Car {
char* make;
char* model;
int year;
};
struct Person* create_person(void)
{
struct Person *new = malloc(sizeof (struct Person));
return new;
}
void print_person(struct Person* person)
{
printf("<Person: %s (%d)>\n", person->name, person->age);
}
struct Car* create_car(void)
{
struct Car *new = malloc(sizeof (struct Car));
return new;
}
void print_car(struct Car* car)
{
printf("<Car: %s - %s (%d)>\n", car->make, car->model, car->year);
}
int main(void)
{
struct Car *car = create_car();
*car = (struct Car) {.make="Chevy", .model="Eldorado", .year=2015};
print_car(car);
struct Person *person = create_person();
*person = (struct Person) {.name="Tom", .age=30};
print_person(person);
}
I would think that the first part would be to group the 'methods' into the struct itself. So then we would have:
#include <stdio.h>
#include <stdlib.h>
struct Person {
char* name;
int age;
void (*print)(struct Person*);
};
struct Car {
char* make;
char* model;
int year;
void (*print)(struct Car*);
};
void print_car(struct Car* car);
void print_person(struct Person* person);
struct Person* create_person(void)
{
struct Person *new = malloc(sizeof (struct Person));
return new;
}
void print_person(struct Person* person)
{
printf("<Person: %s (%d)>\n", person->name, person->age);
}
struct Car* create_car(void)
{
struct Car *new = malloc(sizeof (struct Car));
return new;
}
void print_car(struct Car* car)
{
printf("<Car: %s - %s (%d)>\n", car->make, car->model, car->year);
}
int main(void)
{
struct Car *car = create_car();
*car = (struct Car) {.make="Chevy", .model="Eldorado", .year=2015, .print=print_car};
car->print(car);
struct Person *person = create_person();
*person = (struct Person) {.name="Tom", .age=30, .print=print_person};
person->print(person);
}
What would be the next step in making it "more OOP like"? Perhaps using preprocessor glue and generics? What would be an example of the most OOP-like that the two objects could become? Again, I know this isn't what C is meant for, but it's more a learning experience.
You could use approach applied by the Linux kernel.
The implementation of OOP is based using a composition for inheritance, and embedding interfaces into new classes.
The macro container_of lets easily alternate between a pointer to class and a pointer to one of its members. Usually an embedded object will be an interface of the class. To find more details about container_of macro see my answer to other but related question.
https://stackoverflow.com/a/66429587/4989451
This methodology was used to create a huge complex object oriented software, i.e. Linux kernel.
In the examples from the question, the Car and Person classes use an printing interface that we can call struct Printable. I strongly suggest to produce a fully initialized objects in create_... functions. Let it make a copy of all strings. Moreover, you should add destroy_... methods to release resources allocated by create_....
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#define container_of(ptr, type, member) \
(type*)(void*)((char*)ptr - offsetof(type, member))
struct Printable {
void (*print)(struct Printable*);
};
struct Person {
char* name;
int age;
struct Printable printable;
};
void print_person(struct Printable *printable) {
struct Person *p = container_of(printable, struct Person, printable);
printf("<Person: %s (%d)>\n", p->name, p->age);
}
struct Person *create_person(char *name, int age) {
struct Person *p = malloc(sizeof *p);
p->name = strdup(name);
p->age = age;
p->printable.print = print_person;
return p;
}
struct Car {
char* make;
char* model;
int year;
struct Printable printable;
};
void print_car(struct Printable *printable) {
struct Car *c = container_of(printable, struct Car, printable);
printf("<Car: %s - %s (%d)>\n", c->make, c->model, c->year);
}
struct Car *create_car(char *make, char *model, int year) {
struct Car *c = malloc(sizeof *c);
c->make = strdup(make);
c->model = strdup(model);
c->year = year;
c->printable.print = print_car;
return c;
}
void print(struct Printable *printable) {
printable->print(printable);
}
int main() {
struct Car *car = create_car("Chevy", "Eldorado", 2015);
struct Person *person = create_person("Tom", 30);
print(&car->printable);
print(&person->printable);
return 0;
}
produces output:
<Car: Chevy - Eldorado (2015)>
<Person: Tom (30)>
Note that function print() takes a pointer to the Printable interface. The function does not need to know anything about the original class. No preprocessor is used. All casts are done on "library" side, not on clients side. The library initializes the Printable interface, therefore it cannot be misused.
You can easily add other base classes or interfaces like i.e. RefCounted to solve memory management. The i-face would contain a pointer to destructor and refcount itself. Other examples are intrusive linked lists or binary trees.
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;
}
I took this tutorial example Inheritance and Polymorphism in C and because I've customized it for my exact requirements it's throwing an error when I try to call base function.
Question: Why does it fail in line 8 of employee.c and Possible resolution
((Employee *)self)->super.display(self); // Sementation fault: 11
Download Project
main.c
#include "person.h"
#include "employee.h"
#include <stdio.h>
int main() {
Person* person = newPerson("John Doe");
Employee* employee = newEmployee("Jane Doe", "Acme", 40000);
person->display(person); // displaying Person object
puts("------");
employee->display((Person*)employee); // displaying employee info
return 0;
}
Person.h
#ifndef _PERSON_H
#define _PERSON_H
#include <stdlib.h>
typedef struct Person Person;
struct Person {
char* name;
void (*display)(Person*);
};
Person* newPerson(char* name);
#endif
Person.c
#include "person.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
static void display(Person* const self) {
printf("Name: %s\n", self->name);
}
Person* newPerson(char* name) {
Person* person = malloc(sizeof(Person));
person->name = name;
person->display = display;
return person;
}
Employee.h
#include "person.h"
typedef struct Employee Employee;
struct Employee {
Person super;
char* company;
int salary;
void (*display)(Person*);
};
Employee* newEmployee(char* name, char* company, int salary);
Employee.c
#include "employee.h"
#include <string.h>
#include <stdio.h>
static void display(Person* const self) {
puts(((Employee*)self)->super.name); // works
// ((Employee *)self)->super.display(self); // Sementation fault: 11
printf("Company: %s\n", ((Employee *)self)->company);
printf("Salary: %d\n", ((Employee*)self)->salary);
}
Employee* newEmployee(char* name, char* company, int salary) {
Employee* employee = malloc(sizeof(Employee));
employee->super.name = name;
employee->company = company;
employee->salary = salary;
employee->display = display;
return employee;
}
Probably, for every class in the chain, starting with the base Person, you should make method implementations available under separate names:
Person.h
typedef struct _Person Person;
typedef struct _Person {
void* derived;
char* first;
char* last;
void (*display)(Person*);
} Person;
Person* newPerson(char* first, char* last);
void Person_display(Person *); // analogous to Person::display in C++
Person.c
Person* newPerson(char* first, char* last) {
Person* person = (Person*)malloc(sizeof(Person));
person->derived = person; // pointing to itself
person->first = first;
person->last = last;
person->display = Person_display; // Initializing interface for access to functions
return person;
}
Employee.h
void Employee_display(Person const *); // available to lower subclasses
And in Employee.c
static void display(Person* const self) {
Person_display(self); // calling the superclass implementation
Employee *employee = self->derived;
printf("Company: %s\n", employee->company);
printf("Salary: %d\n", employee->salary);
}
Person* newEmployee(char* first, char* last, char* company, int salary) {
Person* person = newPerson(first, last); // calling base class constructor
Employee* employee = malloc(sizeof(Employee));
person->derived = employee; // pointing to derived object
employee->company = company; // initialising derived class members
employee->salary = salary;
person->display = Employee_display; // Changing base class interface to access derived class functions
return person;
}
Note that this is consistent with usual C++ virtual method contracts: calling display() from the base class ctor resolves to the base class's implementation and the derived class's method is only available after the base class subobject has been fully constructed.
The problem was because embedded struct in Employee didn't have display function pointer initialized and pointed to a function
struct Employee {
Person super;
...
}
Solution: Change the embedded structure Person to pointer type and call newPerson for super
employee.h
typedef struct Employee Employee;
struct Employee {
Person *super; // change this pointer type
char* company;
int salary;
void (*display)(Person*);
};
Employee* newEmployee(char* name, char* company, int salary);
employee.c
static void display(Person* const self) {
((Employee*)self)->super->display(((Employee*)self)->super);
printf("Company: %s\n", ((Employee *)self)->company);
printf("Salary: %d\n", ((Employee*)self)->salary);
}
Employee* newEmployee(char* name, char* company, int salary) {
Employee* employee = malloc(sizeof(Employee));
employee->super = newPerson(name); // call constructor here
employee->company = company;
employee->salary = salary;
employee->display = display;
return employee;
}
What you're currently trying to do is this.
First, you define a 'parent' structure:
typedef struct _Person {
void* derived;
char* first;
char* last;
void (*display)(Person*);
} Person;
Next, you define a 'derived' structure:
typedef struct _Employee {
Person* super;
char* company;
int salary;
void (*display)(Person*);
} Employee;
And finally you cast one type to the other:
return (Person*)employee;
which is wrong. It takes memory allocated for the Employee struct and tries to interpret it as Person. In other words, regards super as derived, company as first and bit pattern in salary as last. I hope you realize that's not quite what you meant.
The Person subobject of your Employee is actually pointed-to by super. Of course you can return employee->super from newEmployee(), this will be a correct instance of Person, but this is really a Person, a concrete instance of Person. It's not polymorphic anymore, and the employee-specific part of the object will then be lost, unrecoverable, unreachable and leaked — there's no way to downcast Person to Employee.
You have two options.
Change the declaration of struct _Employee to
typedef struct _Employee {
Person super;
This way you have immediate up- and downcasts (simply cast Employee * to Person *, and vice versa). All the Person properties of an Employee will then be accessible via its super: employee->super.display = display (where the display being assigned is that static procedure defined in Employee.c; to access Employee-specific portion of the object, it needs to downcast it to Person).
The obvious caveat to this approach is some loss of type safety (given a pointer to Person you cannot tell whether it is a Person or an Employee; this can be worked around by explicitly defining a concrete type descriptor in the base class:
struct _Person {
enum { PERSON, EMPLOYEE, STRANGER, UNDERCOVER_AGENT } concreteClass;
Now you have a run-time type information, but you have limited the allowed set of subclasses to your Person which is not how polymorphic types are commonly implemented.)
Stick to the original design with void *derived pointing to concrete subclass-specific part of the object.
As a side note, your original idea with derived pointing to the struct itself in case it is an instance of Person is a rather elegant way to distinguish instantiable base classes from those abstract :) : by convention, abstract class's constructor sets derived to NULL and leaves it to the derived class's ctor to set that to proper value; and each virtual method first checks whether it is non-NULL and throws an exception otherwise.
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.
I'm having issues writing a function that allocates a struct in C. Ideally, I want to have the function fill the fields of the struct with parameters passed into it.
I have defined the struct in my header file like so:
typedef struct {
char name[NAME_SIZE]; //Employee name
int birthyear; //Employee birthyear
int startyear; //Employee start year
} Employee;
And this is what I have for my function currently:
void make_employee(char _name, int birth_year, int start_year) {
Employee _name = {_name,birth_year,start_year}; //allocates struct with name
} /* end make_employee function */
Any advice on how to accomplish this?
The problem with your current code is that the struct your creating is created on the stack and will be cleaned up as soon as the function returns.
struct foo
{
int a;
int b;
};
struct foo* create_foo( int a, int b )
{
struct foo* newFoo = (struct foo*)malloc( sizeof( struct foo ) );
if( newFoo )
{
newFoo->a = a;
newFoo->b = b;
}
return newFoo;
}
This will get you a heap allocated object. Of course, you'll need a function to free that memory or this is a memory leak.
void destroy_foo( struct foo* obj )
{
if( obj )
free( obj );
}
void print_foo( struct foo* obj )
{
if( obj )
{
printf("foo->a = %d\n",obj->a);
printf("foo->b = %d\n",obj->b);
}
}
(btw, this style gets you part of the way toward an "object oriented" C. Add some function pointers to the struct (to get polymorphic behavior) and you have something interesting; though I'd argue for C++ at that point.)
You have to return a pointer allocated via malloc:
Employee* new_employee(char *_name, int birth_year, int start_year) {
struct Employee* ret = (struct Employee*)malloc(sizeof(struct Employee));
ret->name = _name;
ret->birth_year = birth_year;
ret->start_year = start_year;
return ret;
}
two more things: (1) you should make the struct definition of name a char* instead of char[NAME_SIZE]. Allocating a char array makes the struct much bigger and less flexible. All you really need is a char* anyway. And (2) change the function definition to char*.
Why does the make Employee return void? You need to return the Employee from the make_employee function!
Are you having trouble with the compiler complaining about the x = {a,...} syntax? Write it the long way then: Emp e; e.field1 = a; ...
Are you having weird overwriting / bogus numbers problems? If you allocate a struct in the function it will become invalid (and prone to being overwriten) as soon as the function returns! To go around this you either have to:
Return a copy of the struct (this is OK for small structs):
Employee make_emp(int a){
Emp emp; //Allocate temporary struct
emp.filed1 = a; //Initialize fields;
return emp; // Return a copy
}
Allocate the struct in the heap instead and deal with it through references (ie.: pointers) instead:
Employee* make_emp(int a){
Emp* emp = malloc(sizeof(Emp)); //Allocate the struct on the heap
//And get a reference to it
emp->filed1 = a; //Initialize it
return emp; //Return the reference
}
Don't forget to free() the Employee after you are done with it in this case!
Employee * make_employee(char *_name, int birth_year, int start_year)
{
Employee *employee;
if (employee = (struct Employee *)memalloc(sizeof(Employee)) == NULL)
{
return NULL;
}
else
{
strcpy(&(employee->name), _name);
employee->birthyear = birth_year;
employee->startyear = start_year;
return employee;
}
}