Patrick
Patrick

Reputation: 3367

Functions as members of structs

As another Javascript developer learning C, I'm trying to implement a basic object.

UserStruct.h

#ifndef USERSTRUCT_H
#define USERSTRUCT_H

struct User {
    int age;
    int (* getAge)();
};
typedef struct User User;

int getAge(User);
User initUser(int);
#endif /* USERSTRUCT_H */

UserStruct.c

#include "./UserStruct.h"
int getAge(User this) {
  return this.age;
} 

User initUser(int age){  
  User user;
  user.age = age;
  user.getAge = getAge;
  return user;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "./UserStruct.h"
int main(int argc, char** argv) {
   User user = initUser(15); // sets age to 15..
   user.age = 2222;
   printf("%d\n",user.getAge(1234)); // note the int passing here..
   printf("%d\n",user.age);
  return (EXIT_SUCCESS);
}

Questions!:
1. Can someone explain the syntax int (* getAge)(); inside the UserStruct definition?
2. getAge expects a User to be passed to it, how come it works with an int being passed in? This is especially strange as the implementation of getAge uses return this.age.

While I did figure out how to fix it, I'm still not sure why this behaves the way it does. (The solution is to pass a pointer of the User into getAge)

Upvotes: 3

Views: 113

Answers (2)

Sir Jo Black
Sir Jo Black

Reputation: 2096

I've modified your code in a way that it runs better.

The getAge field of the structure User is a pointer to a function. I've modified its prototype to obtain it points a function that receives a pointer to the structure from which you want get the age field contents. (I used a pointer to the structure to avoid to transfer the entire structure by means the stack)

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>

struct User {
    int age;
    int (* getAge)(struct User *);
};

typedef struct User User;

int getAge(User *);
User initUser(int);

int getAge(User * this_) {
  return this_->age;
}

User initUser(int age){
  User user;
  user.age = age;
  user.getAge = getAge;
  return user;
}

int main(int argc, char** argv) {
   User user = initUser(15); // sets age to 15..

   // user.age = 2222;

   printf("%d\n",user.getAge(&user)); // note the pointer used as parameter

   printf("%d\n",user.age);
  return (EXIT_SUCCESS);
}

Upvotes: 2

Nahuel Fouilleul
Nahuel Fouilleul

Reputation: 19335

C is not an object oriented language as it existed before object, but your example is demonstrating that it can be used with objects.

  • int (* getAge)() is a function pointer, the function takes any parameters () and returns int, to specify that the function takes no parameter should be defined (void)

  • getAge is a "method" of class user it needs an object instance, in object languages the syntax would be user.getAge() which passes implicitly this as first argument, in C it's explicit: getAge(user).

The problem is that an int can be used as pointer which means user.getAge(1234) will use 1234 as an address to a user so will take the second int field as an address to fuction getAge and jump to this address.

Upvotes: 3

Related Questions