I've create a structure Person and had these variables in it, then I added a new field named father and its type is pointer to a person.
I have to initialize the data of FJames as following: fname = Whatever, lname = Bond, age = 80, job = Farmer, father = NULL
Then initialize the data of James as following: fname = James, lname = Bond, age = 40, job = Actor, father = FJames
Then display all the data.
I'm getting an error " initializing struct Person * with an expression of incompatible type "Person"
What to do? :/
I don't even think I'm doing it right, please help!
/#include <stdio.h>
typedef struct {
int age;
char *fname;
char *lname;
char *job;
struct Person *father;
}Person;
int main(int argc, const char * argv[])
{
Person James;
Person FJames = {80,"Whatever","Bond","Painting",NULL};
James.age = 40;
James.fname = "James";
James.lname = "Bond";
James.job = "Engineering";
James.father = FJames;
}
You don't declare struct Person actually.
You're declaring anonymous structure and typedef it to person. You then should use it as just Person, not struct Person.
struct Person {
struct Person *father; // this will work
}
or if you want typedef
typedef struct s_Person {
struct s_Person *father
} Person;
typedef struct {
int age;
char *fname;
char *lname;
char *job;
struct Person *father; // << This is a pointer to a Person
} Person;
James.father = FJames;
FJames is not a Person*. He's a Person. You need to malloc him in order to get a Person*. Or take his address with &
This code has some other issues, but that's the one that's giving you the error in question.
James.father = &FJames should be what you need.
There are other minor problems. These days initialising a char* from a string constant is frowned upon, because char* implies that the memory being pointed at can be altered.
Here's a working program:
#include <stdio.h>
#include <stdlib.h>
typedef struct Person {
int age;
char *fname;
char *lname;
char *job;
struct Person *father;
} Person;
int main(int argc, const char * argv[])
{
Person James;
Person FJames = {80,"Whatever","Bond","Painting",NULL};
James.age = 40;
James.fname = "James";
James.lname = "Bond";
James.job = "Engineering";
James.father = &FJames;
fprintf(stdout, "%d\t%s\t%s\t%s\tpops:\t%s\t%s\n", James.age, James.fname, James.lname, James.job, (James.father)->fname, (James.father)->lname);
return EXIT_SUCCESS;
}
Corrections:
You should correct your typedef so that it declares Person.
When setting James.father it should dereference FJames so that you are setting it to the value of the pointer to FJames.
Your main() function should return an int, so return EXIT_SUCCESS (defined in stdlib.h) to note that you exited properly.
Advice:
When dereferencing properties of James.father, use precedence and arrow notation to dereference its values.
If you are using gcc, compile with -Wall option to enable all compilation warnings. This will help note warnings that point where corrections are needed.
That last line should be
James.father = &FJames;
The father field is a pointer, but FJames is a Person. You can use & to get the address of FJames.
Edit
The struct definition should also be changed in addition to that, in one of the ways aragaer suggested, e.g.:
typedef struct s_Person {
// ...
struct s_Person *father;
} Person;
Related
I have a new typedef struct and an init function for it.
#include <stdlib.h>
#include <stdio.h>
typedef struct PERSON
{
char * name;
char * surname;
int month;
int day;
} * Person;
Person init_person(char * name, char * surname, int month, int day)
{
Person person = calloc(1, sizeof(Person));
person->name = name;
person->surname = surname;
person->month = month;
person->day = day;
return person;
}
int main(int argc, char * argv[])
{
Person person = init_person("Hello", "World", 12, 12);
printf("\n%s\n", person->name);
printf("\n %i %i \n", person->month, person->day);
return 0;
}
When the code is run, the expected output should be:
Hello
12 12
But instead, I am getting:
Hello
0 1769108595
When I swap around the printf function statements, I do get the desired output. I have written similar code using structures before but I have not faced such a problem. Could it be a memory problem?
See Is it a good idea to typedef pointers? TL;DR — No, except perhaps for function pointers or pointers to opaque types, neither of which is relevant here.
And the problem is that you've been suckered into allocating insufficient memory by the pointer typedef. You have:
Person person = calloc(1, sizeof(Person));
That allocates enough space for one pointer to a struct PERSON. You need to use something equivalent to:
Person person = calloc(1, sizeof(*person));
to allocate enough space for what person will point to.
Or you need to remove the pointer from the typedef and make corresponding changes to the code. That will be better in the long run.
You don't want to declare your structure as a pointer,
typedef struct PERSON
{
char * name;
char * surname;
int month;
int day;
} Person;
And if you need to make it a pointer,
Person *person = (Person *) malloc(sizeof(Person));
i have this two structures
typedef struct pokemon_move_t {
char* name;
PokemonType type;
int power_points, max_power_points;
int strength;
} *PokemonMove;
typedef struct pokemon_t {
char* name;
PokemonType type;
int experience;
int health_points;
PokemonMove* moves;
int number_of_moves, max_number_of_moves;
} *Pokemon;
and i have a function that receives pokemon struct and i'm trying to reach the name field in the function and it shows me the error message in the title,i tried everything that suggested before and it didn't work, the function is(not complete) :
int pokemonMoveName(Pokemon pokemon){
char* name= pokemon->moves->name; //the error is in this line
return 0;
}
The element moves is:
PokemonMove * moves;
Which is:
struct pokemon_move_t ** moves;
And not:
struct pokemon_move_t * moves;
... it is a pointer to a pointer to a structure and not to a structure itself.
I think that you don't want this!
Either you have to remove the * at the typedef or the * in the struct.
If moves really is a pointer to a pointer you'll have to access it the following way (or similar):
char* name= (*(pokemon->moves))->name;
... which is equal to:
char* name= pokemon->moves[0]->name;
... or, if moves points to an array:
char* name= pokemon->moves[index]->name;
I think you mean the following declaration of the data member
typedef struct pokemon_t {
char* name;
PokemonType type;
int experience;
int health_points;
PokemonMove moves;
^^^^^^^^^^^^^^^^^
int number_of_moves, max_number_of_moves;
} *Pokemon;
In this case this statement
char* name= pokemon->moves->name;
will be valid.
The type PokemonMove is already declared like a pointer type.
typedef struct pokemon_move_t {
char* name;
PokemonType type;
int power_points, max_power_points;
int strength;
} *PokemonMove;
^^^^^^^^^^^^
Hie guys. I am studying structures and pointers using the book called Pointers in C: A Hands on Approach and on page 107, I came across an incomplete example of struct type casting. I tried to make it work by just implementing the function receivedata() ,adding headers and making a few changes.
This is the complete code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct signature
{
char sign;
char version;
};
struct id
{
char id;
char platform;
};
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
static void receivedata(struct data *d);
static struct signature *extractsignature(struct data *d);
static struct id *extractid(struct data *d);
int main(int argc, char *argv[])
{
/* Actual line in book is :
* struct data *img; with no memory allocation or assignment to NULL.
* Had errors so i allocated memory on the heap before passing the value to
* Receivedata(); */
struct data *img = malloc(sizeof(struct data));
receivedata(img);
/* Actual line in book is :
* struct id *idval = extractid(&img);
* struct signature *sig = extractsignature(&img);
* This is obviously erroneous because &img is a pointer
* to a pointer (struct data**) which is not the data type for
* the extract functions' argument */
struct id *idval = extractid(img);
struct signature *sig = extractsignature(img);
printf("For signature:\n");
printf("sign = %c", sig->sign);
printf(" version = %c\n\n", sig->version);
printf("For id:\n");
printf("id = %c", idval->id);
printf(" platform = %c", idval->platform);
printf("\ndata = %s", img->data);
return 0;
}
static struct signature *extractsignature(struct data *d)
{
struct signature *sig = (struct signature *)d;
return sig;
}
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
static void receivedata(struct data *d)
{
struct data *dptr = d;
char *ch = "CODING IS COOL!";
dptr->sig.sign = 's';
dptr->sig.version = '1';
dptr->idv.id = 'i';
dptr->idv.platform = 'p';
strncpy(dptr->data, ch, strlen(ch));
return;
}
What I would like to understand is the casting inside the function extractid() and extraxtsignature() because it seems we are casting struct data * so as to retrieve its individual members. I ran the program and what i get is the value of the first member of struct data for both sig member and id members. Here is the output when struct id comes first in the struct data:
For signature:
sign = i version = p
For id:
id = i platform = p
data = CODING IS COOL!
and this when struct signature is the first element:
For signature:
sign = s version = 1
For id:
id = s platform = 1
data = CODING IS COOL!
and finally, this when char data[100] is the first element:
For signature:
sign = C version = O
For id:
id = C platform = O
data = CODING IS COOL!
May you please explain this type of casting, when to use it and the best practices. Thank you very much.
struct data
{
struct id idv;
struct signature sig;
char data[100];
};
For the above definition, the extractid function below is valid and will get right results.
static struct id *extractid(struct data *d)
{
struct id *idv = (struct id *)d;
return idv;
}
This is because, struct id is the first member of the struct data. So, when you have struct data *d, the d points to the starting address of struct data and which is same as the starting address of the first member struct id.
So, if you are casting for the first member of the struct, then it is right as per the code you have provided above.
Why am I getting a segmentationfault when it tries to print the second member in the list?
After printing the first element of the list, the debugger opens the stdio.h and says:
At C:\TDM-GCC-32\include\stdio.h:255
At C:\TDM-GCC-32\include\stdio.h:256
At C:\TDM-GCC-32\include\stdio.h:258
At C:\TDM-GCC-32\include\stdio.h:259
Here is the code.
#include <stdio.h>
#include <stdlib.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char Name, char Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = Name;
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
Ausgabe(liste);
return 0;
}
The error is in the declaration of the add() function. The strings should be char pointers, not chars.
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse){
The signature of the function add is inconsistent to the declaration and usage to the members of Student. Change the signature as follows.
void add(char* Name, char* Adresse, unsigned long Mtnr, short Kurse)
On the long run, it might also be necessary to create copies of Name and Adresse in add, as the caller of add might deallocate them, perhaps causing undesired behaviour.
While Marc Is correct with his observation, there is one more thing you may want to fix here.
When you add a record, you allocate it, but you do not allocate the content of it's pointers (Specifically = for the name and address pointers). The add function just point them to the input's address. this is a problem because the data in the address supplied to the add function is likely to change if, for example, it's a user input, or some other external buffer.
in the code snipped below I fixed the 'name', but left the address as is. please run it and see what happens. (assaf's record displays david's address)
hope this helps
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student {
char *Name;
char *Adresse;
unsigned long Mtnr;
short Kurse;
struct Student *next;
struct Student *previous;
};
typedef struct Student Student;
Student *liste = NULL, *ende = NULL;
void add(char *Name, char *Adresse, unsigned long Mtnr, short Kurse) {
Student *add;
ende->next = malloc(sizeof(Student));
add = ende->next;
add->Name = malloc(strlen(Name)+1);
strcpy(add->Name, Name);
add->Adresse = Adresse;
add->Mtnr = Mtnr;
add->Kurse = Kurse;
add->previous = ende;
add->next = NULL;
ende = ende->next;
}
void Ausgabe(Student *Anfang) {
while (Anfang != NULL) {
printf("%s %s %d %d \n", Anfang->Name, Anfang->Adresse, Anfang->Mtnr, Anfang->Kurse);
Anfang = Anfang->next;
}
}
int main() {
char name_buf[100];
char address_buf[100];
liste = malloc(sizeof(Student));
ende = liste;
liste->Name = "Anna Musterfrau";
liste->Adresse = "Am Schwarzberg-Campus 3";
liste->Mtnr = 22222;
liste->Kurse = 2;
liste->next = NULL;
liste->previous = NULL;
add("Hans Peter", "Kasernenstrasse 4", 4444, 4);
sprintf(name_buf,"assaf stoler");
sprintf(address_buf,"maria 8");
add(name_buf, address_buf, 8888, 8);
sprintf(name_buf,"david david");
sprintf(address_buf,"some street 9");
add(name_buf, address_buf, 9999, 9);
Ausgabe(liste);
return 0;
}
EDIT: Op asked some questions, and the comment space is limited, so I'll add below:
A pointer is just an object pointing somewhere in memory. it's size is fixed. the content it's pointing to will vary.
When you include a pointer to a string in a structure, the space where the string is kept need to be allocated / accounted for. it is not part of the sizeof(struct).
In your original example the pointers were pointing to constant strings (which reside in the static code, usually the data section, allocated by the compiler), which is why your original code was able to access the strings.
In a more realistic case, the input data is not part of the program data, but is received by some input method (which my *buf was to emulate). as such, pointing your name and address at it would break the program, as the pointer you point to may have it's content changed. therefor copying of the data (string / array) is needed, and since we copy the data, we need to allocate space for it, and point our (name/address) pointer at it.
Alternate option is to use non-pointer array for name and address as in:
struct Student {
char Name[20];
char Adresse[60];
unsigned long Mtnr;
...
}
In this scenario, sizeof (struct Student) would actually include all the space for those fields. you still need to use strcpy or memcpy, as well as check for and handle strings that are too long to fit in your pre-defined length.
Hope this helps
To asign a char value into the struct 'field', I have to use strcpy ?
I tried this:
struct student{
char name[50];
int age;
};
int main(){
struct student std;
std.name = "john"; //Doesnt work
strcpy(std.name, "john"); //It DOES work
std.age = 20;
return 0;}
Why when comes to char I can not simply use the ' = ' to assign a value ?
How may I pass a struct initialized in main(){} as a parameter to a function and change it's values inside the function without the need of a return.
Do I just use the '*' like:
void MyFunction(struct student *std){
std->Name = "John";
std->Age = 20;
}
int main(){
struct student me;
Myfunction(me);
}
Is that the correct way to do so ?
No matter which way you pass the struct (by value or by pointer), you cannot directly assign a string literal to a char array. You can only use strcpy or strncpy or something else that copies the characters one by one.
But there is a workaround, you can directly assign struct to another one. C compiler will perform a bitwise copy of the struct.
struct student s1;
strcpy(s1.name, "john");
s1.age = 10;
struct student s2;
s2 = s1; // now s2 is exactly same as s1.
Attach an example of use pointer to pass struct:
void handle_student(struct student *p) { ... }
int main() {
struct student s1;
handle_student(&s1);
}
This is just an additional information
While declaring the structure variable, it can be initialized as below.
int main(){
struct student s1 = {"John", 21};
//or
struct student s = {.name= "John" };
}