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
}
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;
}
typedef struct item
{
char itemName[32];
float price;
int quantity;
}ITEM;
typedef struct list
{
void* item[5];
int (*compare)(void*, void*);
int length;
}LIST;
typedef struct order
{
int orderId;
float orderTotal;
LIST* orderItems;
int length;
} ORDER;
int compareItemPrice(void* p1, void* p2){
ITEM* p = (ITEM*)p1;
ITEM* q = (ITEM*)p2;
if(p->price>q->price)
{
return 1;
} else if(p->price<q->price)
{
return -1;
} else {
return 0;
}
}
Code above is my structures and function wrote in C. When I implement code below, it showed me errors. The errors was all about ITEM* p which was incomplete definition of struct list.
ITEM* getExpensiveItem(ORDER* o){ // Maximum item price
ITEM* p = o->orderItems->item;
ITEM* expensiveItem = p;
for(int i=1; i<o->orderItems->length-1; i++)
{
if(compareItemPrice(p, (p+i)) < 0)
{
expensiveItem = p+i;
}
}
return expensiveItem;
}
Code like
struct a
{
int i;
} A;
will give a variable A that you can use like
A.i = 42;
However, it seems that you really are trying to create a new type. So try:
typedef struct a // Notice the "typedef" in start of line
{
int i;
} A;
That will give a a type A that can be used like:
A var;
A* pVar;
var.i = 42;
pVar = &var;
....
Also notice that your struct order uses the type LIST. So LIST must be declared before struct order. Further, the type CUSTOMER must also be declared which it currently isn't.
So your code should probably be like:
#define N 42 // Made this up as it isn't in your code
typedef struct customer // Made this up as it isn't in your code
{
int x;
} CUSTOMER;
typedef struct list
{
void* item[N];
int (*compare)(void*, void*);
int length;
}LIST;
typedef struct order
{
int orderId;
float orderTotal;
LIST* orderItems;
CUSTOMER* customer;
int length;
} ORDER;
typedef struct item
{
char itemName[32];
float price;
int quantity;
}ITEM;
Also notice that this line has a problem:
ITEM* p = o->orderItems->item;
The type of o->orderItems->item is array of void pointer due to void* item[N]; in struct list. In other words: You are trying to assign an array of pointer to a single pointer. I'm not really sure what you want to do but maybe like:
ITEM* p = o->orderItems->item[0];
#include <stdio.h>
#include <stdlib.h>
struct node
{
char name[30];
int age;
struct node *next;
} *list_head,*neos;
main()
{
}
void add_node_to_the_list(char data1[],int data2)
{
neos=(struct node *)malloc(sizeof(struct node));
strcpy(neos->name,data1);
age=data2;
neos->next=list_head;
list_head=neos;
}
void display_list()
{
struct node *p;
p=list_head;
while(p!=NULL)
{
puts(p->name);
printf("%d\n",age);
p=p->next;
}
}
When I compile this code I get an error because I haven't declare the "age" variable, although I have done that inside the struct node, outside the main function. Why?
Here you go:
#include <stdio.h>
#include <stdlib.h>
struct node
{
char name[30];
int age;
struct node *next;
}*list_head,*neos;
main()
{
}
void add_node_to_the_list(char data1[],int data2)/*Ç óõíáñôçóç áõôç ðñïóèåôåé êïìâï óôç ëéóôá*/
{
neos=(struct node *)malloc(sizeof(struct node));
strcpy(neos->name,data1);
neos->age=data2; //the correction is made here
neos->next=list_head;
list_head=neos;
}
void display_list()
{
struct node *p;
p=list_head;
while(p!=NULL)
{
puts(p->name);
printf("%d\n",p->age); //and here
p=p->next;
}
}
Note that you have been trying to access a struct element without pointing it.
Replace age=data2; by neos->age = data2;
and replace printf("%d\n",age); by printf("%d\n", p->age);
There is no age variable, age is a member of struct node.
You have declared it in a structure so to access it you have to pass by your structure
neos->age
age is just an element in a structure.
So assuming we have a structure defined as the following:
struct PlaceHolder {
int int_element
char char_element
} * place_holder;
to access any of the elements you need to access the structure first and reference the element in that structure.
place_holder->int_element = 5;
place_holder->char_element = "a";
In your case you have both list_head and neos as global variables, so to access an element in any of them you have to do:
list_head->age = data2;
neos->age = data2;
I'm having a small problem trying to malloc this struct.
Here is the code for the structure:
typedef struct stats {
int strength;
int wisdom;
int agility;
} stats;
typedef struct inventory {
int n_items;
char **wepons;
char **armor;
char **potions;
char **special;
} inventory;
typedef struct rooms {
int n_monsters;
int visited;
struct rooms *nentry;
struct rooms *sentry;
struct rooms *wentry;
struct rooms *eentry;
struct monster *monsters;
} rooms;
typedef struct monster {
int difficulty;
char *name;
char *type;
int hp;
} monster;
typedef struct dungeon {
char *name;
int n_rooms;
rooms *rm;
} dungeon;
typedef struct player {
int maxhealth;
int curhealth;
int mana;
char *class;
char *condition;
stats stats;
rooms c_room;
} player;
typedef struct game_structure {
player p1;
dungeon d;
} game_structure;
And here is the code I'm having a problem with:
dungeon d1 = (dungeon) malloc(sizeof(dungeon));
It gives me the error "error: conversion to non-scalar type requested"
Can someone help me understand why this is?
You can't cast anything to a structure type. What I presume you meant to write is:
dungeon *d1 = (dungeon *)malloc(sizeof(dungeon));
But please don't cast the return value of malloc() in a C program.
dungeon *d1 = malloc(sizeof(dungeon));
Will work just fine and won't hide #include bugs from you.
malloc returns a pointer, so probably what you want is the following:
dungeon* d1 = malloc(sizeof(dungeon));
Here is what malloc looks like:
void *malloc( size_t size );
As you can see it return void*, however you shouldn't cast the return value.
The memory assigned by malloc must be stored in a pointer to an object, not in the object itself:
dungeon *d1 = malloc(sizeof(dungeon));
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.