C is not printing my valid variable value - c

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));

Related

Structs in Linked List

I'm still fairly new to C programming and I'm having some trouble.
I've written some code to read a file that has information on people's names, ages, weight, and heights. Each new line in the file represents a new person. This information is then stored in a struct, and this struct is then added to a linked list. Essentially I am trying to use this linked list as a queue, with each node being a struct.
This is what the file I am reading will look like: (the format is age, weight, height, name).
20,60,170,Joe
23,70,175,Mike
My issue is that for some reason, every node in the linked list is the exact same, which is the last line of the file text. So for example every time I create a struct and add it to the linked list, each node will have the name 'Mike', age '23', and so forth. I've played around with the code and I notice that there is no issue with the file reading, and the values assigned to the struct members are correct (I printed out the values to check). However when I view the top of the Linked List, then dequeue (remove top), then view the top again, the values are always the same. So I am not sure where my problem is.
Note: I wrote a generic linked list code, and there is no issue with the linked list itself as I have tested it extensively.
This is my code:
#include <stdio.h>
#include "macros.h"
#include <string.h>
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
int main()
{
void* vdPtr;
Person* topVal;
Person person;
LinkedList* list = createLinkedList();
char line[100];
int i=0;
int numPeople=0;
FILE* fp;
int age, weight, height;
char name[51];
fp = fopen("text.txt","r");
while(fgets(line,100,fp) != NULL)/*reading file to see how many lines, and how many people*/
{
numPeople++;
}
rewind(fp);
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
person.AGE = age;
person.WEIGHT = weight;
person.HEIGHT = height;
strcpy(person.NAME,name);
insertLast(list,&person);
/*printing to see whether the values added to struct members are correct*/
printf("%d %d %d %s\n",person.AGE,person.WEIGHT,person.HEIGHT,person.NAME);
i++;
}
/*testing*/
printf("\nCount %d",getLinkedListCount(list));/*seeing how many nodes in the linkedList*/
/*using void pointer to get the top value, then typecasting it to Person pointer*/
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
/*viewing the top person*/
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
/*deqeue*/
removeTop(list);
printf("\nCount %d",getLinkedListCount(list));
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
}
Can anyone tell me where I went wrong and what to do to fix it?
You are continually adding the same pointer to the list. On every new line you overwrite the same variable. So in the end you have one big list of pointers all pointing to the same thing. You have to make a new person struct for every person like this:
#include <stdio.h>
#include "macros.h"
#include <string.h>
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
int main()
{
void* vdPtr;
Person* topVal;
LinkedList* list = createLinkedList();
char line[100];
int i=0;
int numPeople=0;
FILE* fp;
int age, weight, height;
char name[51];
fp = fopen("text.txt","r");
while(fgets(line,100,fp) != NULL)/*reading file to see how many lines, and how many people*/
{
numPeople++;
}
rewind(fp);
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
Person *person = (Person *)malloc(sizeof(Person)); //make new person object
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
person->AGE = age;
person->WEIGHT = weight;
person->HEIGHT = height;
strcpy(person->NAME, name);
insertLast(list, person);
/*printing to see whether the values added to struct members are correct*/
printf("%d %d %d %s\n",person.AGE,person.WEIGHT,person.HEIGHT,person.NAME);
i++;
}
/*testing*/
printf("\nCount %d",getLinkedListCount(list));/*seeing how many nodes in the linkedList*/
/*using void pointer to get the top value, then typecasting it to Person pointer*/
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
/*viewing the top person*/
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
/*deqeue*/
removeTop(list);
printf("\nCount %d",getLinkedListCount(list));
vdPtr = viewTop(list);
topVal = (Person*)(vdPtr);
printf("\ntop is %s %d",topVal->NAME,topVal->AGE);
}
I recommend reading up on how pointers, and memory management work. Also keep in mind that this code does not free the memory it allocates, which is something you still need to do.
Without seeing code for insertLast() it is difficult too answer but it may be that you would create a new struct for each person and then pass it to insertLast :
Person* newPerson;
while (i<numPeople)/*storing file data in the appropriate member for Person struct*/
{
newPerson = (Person *)malloc(sizeof(Person))
fscanf(fp,"%d,%d,%d,%s",&age,&weight,&height,name);
newPerson->AGE = age;
newPerson->WEIGHT = weight;
newPerson->HEIGHT = height;
strcpy(newPerson.NAME,name);
insertLast(list,newPerson);
...
The list seems to save only the address of the data, that why you need to create new data for each person.
A struct that is to be used in a linked list needs to be self referential. i.e. one of the members (typically the last one) is a pointer to the struct itself. This is what allows segments of data to be linked together . (other members can be thought of as the payload, or data.) For example, your struct:
typedef struct
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
}Person;
Can be refactored for example as:
struct Person
{
int AGE;
int WEIGHT;
int HEIGHT;
char NAME[51];
struct Person *node;
};
Look at this simple starter tutorial for creating and using linked lists. (Click the C tab for example code.)

why won't %s print from a linked list [duplicate]

This question already has answers here:
How can I correctly assign a new string value?
(4 answers)
Closed 3 years ago.
I created a linked list that contains a char array. Then I tried to print it using %s and it would not print. I know I have to transform the char by adding in '\0' so that it can print using '/0'. But I'm not sure why.
For example if I input:
Bob 20
It should print:
New student created: Bob is 20 years old.
BUT: it's printing (without "Bob"):
New student created: is 20 years old.
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
NOTE: I understand the code below will work and print the correct name, where I add an additional method to change the char array called copyStr(), but I'm not sure why....
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[50];
int age;
struct student *next;
};
struct student *createStudent(char studentName[], int studentAge);
void copyStr(char *source, char *target);
int main(void) {
struct student *studptr;
int myAge;
char myName[50];
scanf("%s %d", myName, &myAge);
studptr = createStudent(myName, myAge);
printf("New student created: %s is %d years old.\n", studptr->name, studptr->age);
free(studptr);
return 0;
}
struct student *createStudent(char studentName[], int studentAge){
struct student * ptr;
ptr = (struct student *)malloc(sizeof(struct student));
//we need to translate the char into a string
copyStr(studentName, ptr->name);
ptr->name[50] = studentName[50];
ptr->age = studentAge;
ptr->next = NULL;
return ptr;
}
void copyStr(char *source, char *target){
int i = 0;
while(source[i] != '\0')
{
target[i] = source[i];
i++;
}
target[i] = '\0';
}
Arrays do not have the assignment operator.
This statement
ptr->name[50] = studentName[50];
tries to assign the non-existent element with the index 50 of the array pointed to by the pointer studentName to the non-existent element of the array ptr->name.
Instead you should use the standard C function strcpy declared in the header <string.h>.
For example
strcpy( ptr->name, studentName );
Adding to #Vlad's answer, Right way to copy arrays is by iterating over them, thereby, picking each element in char array and copying it to new location. strncpy does exactly that along with buffer overflow checks, which makes it better than strcpy.
Please have a look at strcpy documentation, which says : "ensure size of the array pointed by destination shall be long enough to contain the same C string as source (including the terminating null character), and should not overlap in memory with source"
On a completely different side note, if you're looking for one-liner assignment, you're allowed to do this:
char sample[] = {"randomText"};
char sample2[11] = {"randomText"};

Segmentation fault when I try to printf

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

How to allocate memory with different type in C?

I have the following code in C:
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
How could I find the pointer to the memory point to the first element of struct Student in the memory?
I try to do it in the following way:
int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
Student * student_p = p.student[NUM_OF_PEOPLE];
}
It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?
What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.
You are looking for this.
First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
Student student;
} StudentAndId;
typedef struct
{
int id;
StudentAndId students[];
} People;
Note the lack of size in the array inside People. Now you do this:
People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));
Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.
Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.
This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.
Try this:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int age;
int phoneNumber;
} Student;
typedef struct
{
int id;
int student[1];
} People;
#define NUM_OF_PEOPLE 10
int main()
{
People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
int* id = (int*)(p+1);
Student* s = (Student*)(id+NUM_OF_PEOPLE);
printf("Size of People : %d\n", sizeof(People));
printf("p points to : %p\n", p);
printf("id points to : %p\n", id);
printf("s points to : %p\n", s);
}
Here's a sample output:
Size of People : 8
p points to : 0x80010460
id points to : 0x80010468
s points to : 0x80010490
You may want to add the id field to your Student data structure, e.g.:
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.
I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.
As a sample code, you may want to consider the following:
#include <stdio.h> /* For printf() */
#include <stddef.h> /* For offsetof() */
#include <stdlib.h> /* For dynamic memory allocation */
typedef struct {
int id;
int age;
int phoneNumber;
} Student;
#define ARRAY_OF_ANY_SIZE 1
typedef struct {
int count;
Student students[ARRAY_OF_ANY_SIZE];
} People;
int main(int argc, char* argv[]) {
People* people;
const int numberOfStudents = 3;
int i;
/* Dynamically allocate memory to store the data structure */
people = malloc(offsetof(People, students[numberOfStudents]));
/* Check memory allocation ... */
/* Fill the data structure */
people->count = numberOfStudents;
for (i = 0; i < numberOfStudents; i++) {
people->students[i].id = i;
people->students[i].age = (i+1)*10;
people->students[i].phoneNumber = 11000 + i;
}
/* Print the data structure content */
for (i = 0; i < people->count; i++) {
printf("id: %d, age=%d, phone=%d\n",
people->students[i].id,
people->students[i].age,
people->students[i].phoneNumber);
}
/* Release the memory allocated by the data structure */
free(people);
return 0;
}
Output:
id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002

Defining a pointer in a struct

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;

Resources