I have a task to make something that looks like Hotel Booking program in C.
Basically I should have 2 structures, one for reservations of rooms in the hotel (that contains information about that room like its ID, floor, how many beds are there and stuff like that, pointer to person that reserved the room and list of people that will be in that room) and the other structure for persons (which contains, lets say, name and surname of person).
The problem I am having is segmentation fault that I get since I probably didn't make those structures right.
Here is a part of my code, that is supposed to add a guest inside the list (that is located in reservation structure):
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#define MAXSTR 25
#define FORMAT_LEN 15
typedef struct person //structure that holds info about person
{
char name[MAXSTR + 1];
char surname[MAXSTR + 1];
}Guest;
typedef struct persons // list of persons
{
Guest person;
struct persons* next;
} Persons;
typedef struct //Pointer to first person in list
{
Persons* list;
} List;
typedef struct room //structure that holds info about rooms that are reserved
{
unsigned int ID;
unsigned int floor;
unsigned int bedcount;
struct tm dateArrival;
struct tm dateDep;
bool cancelled;
unsigned int price;
Guest* person;
List* list;
}Reservation;
typedef struct rooms
{
Reservation room;
struct rooms* next;
} Reservations;
bool PutGuestInsideList(List* list);
char* EnterString(char* str);
int main()
{
Reservations* room = NULL;
List list = { NULL };
printf("New guest: \n");
if(PutGuestInsideList(room->room.list) == false)
printf("Try again. \n");
}
bool PutGuestInsideList(List* list)
{
if(list == NULL)
return false;
Persons* newpers = (Persons*) malloc(sizeof(Persons));
if(newpers == NULL)
return false;
printf("Name: ");
EnterString(newpers->person.name);
printf("Surname: ");
EnterString(newpers->person.surname);
list->list = newpers;
return true;
}
char* EnterString(char* str)
{
if (str == NULL)
return str;
char format[FORMAT_LEN] = "";
sprintf(format, "%%%u[^\n]", MAXSTR);
scanf(format, str);
scanf("%*[^\n]");
scanf("%*c");
return str;
}
If there is something I left out in my explanation ask me in the comments. Thanks!
In main :
int main()
{
Reservations* room = NULL;//here you initialise pointer with NULL
List list = { NULL };
printf("New guest: \n");
if(PutGuestInsideList(room->room.list) == false)// and here you try to access it
printf("Try again. \n");
}
At if statement you are accessing member room.list on pointer room even if room is NULL.
BTW: Use (or learn to use) debugger, you will be able to debug your programs faster.(that's why they are called debuggers)
You dereferenced room which is NULL in the line if(PutGuestInsideList(room->room.list) == false). You can not dereference a NULL pointer. The room pointer should be properly set in your main function.
I think you need to spend some time on google looking up tutorials on pointers in C. As others are pointing out, room is set to null but you dereference it.
Reservations* room = NULL;
// and then
if(PutGuestInsideList(room->room.list) == false)
you also need to review these lines:
EnterString(newpers->person.name);
EnterString(newpers->person.surname);
Neither person.name nor person.name is given a buffer to write in. They are pointers which do not point anywhere but you attempt to use them.
Related
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.)
Hello i am slowly learning c and trying my best.
Can someone tell me why my variables are undefined?
"processId, userId, arrivalTime, priority, expectedTimeRemaining, expectedPctCPU, realTime" are all giving an error!
Please help, i provided my code. I tried reading up about structures and pointers. Followed resources, and now i am trying to implement it myself.
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define _CRT_SECURE_NO_WARNINGS
typedef enum States { NEW, READY, RUNNING, BLOCKED, SUSPENDED, EXIT, SUSPEND_READY } State;
char stateNames[7][14] = { "New", "Ready", "Running", "Blocked", "Suspended", "Exit", "SuspendReady" };
// partial - skips info needed to actually conduct process switch - contents of registers, program counter, stack pointers, ... pointers to page tables ...
// we ARE going to need some way of indicating IO needs so can decide when they should block
struct processblock {
int processId;
int userId; // pointer instead?
State processState; // Not input - initially NEW
int arrivalTime; // time units in simulation, not actual time
int priority; // base priority
int currentPriority; // can be upped or lowered based on what has happened with the process - not input - initially same as base priority
int timeWaitingSoFar; // Not input - initially zero
int timeProcessingLastRun; // Not input - initially zero
int timeProcessingSoFar; // Not input - initially zero
int expectedTimeRemaining;
struct event* waitingOn; // ??? // Not input - initially zero
int expectedMemoryNeed;
int expectedPctCPU; // to get an idea of whether CPU bound or IO bound
bool realTime; // whether a real-time process or not (real-time processes may need immediate attention)
struct processblock* nextPtr; // not used in this program - but preparing for linked list version
};
//fill in the array from file
int fillArrayFromFile(struct processblock processor[], FILE*fPtr, int maxSize) {
int count = 0;
//unsure if realtime is a parameter, pls check and confirm with me
while ((count < maxSize) && fscanf("fPtr,%d,%d,%d,%d,%d,%d,%d", processId, userId, arrivalTime, priority, expectedTimeRemaining, expectedPctCPU, realTime) != EOF) {
//fill in each part of the array
processor[count].processId = count;
}
}
You should use a linked list to store the data you need, here there is an example, this code reads the lines of a file named test.txt that has this layout:
100,101,20,1,50,1,0
102,105,30,1,55,1,1
101,10,40,0,56,1,1
and store all the values in a linked list, that contains your structure. I hope you'll learn something new, happy coding!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define _CRT_SECURE_NO_WARNINGS
typedef enum States { NEW, READY, RUNNING, BLOCKED, SUSPENDED, EXIT, SUSPEND_READY } State;
char * stateNames[7] = { "New", "Ready", "Running", "Blocked", "Suspended", "Exit", "SuspendReady" };
struct processblock {
int processId;
int userId;
int arrivalTime;
int priority;
int expectedTimeRemaining;
int expectedPctCPU;
int realTime; // scanf can't read boolean
State processState;
int currentPriority;
int timeWaitingSoFar;
int timeProcessingLastRun;
int timeProcessingSoFar;
int expectedMemoryNeed;
};
struct Node
{
struct processblock pblock;
struct Node *next;
};
typedef struct Node * List;
void NewNode(List * p , struct processblock pb) //function that creates new linked list nodes
{
List temp;
temp = (List)malloc(sizeof(struct Node));
temp->pblock = pb;
temp->next = *p;
*p = temp;
}
int fillArrayFromFile(char *filename, List * p) {
FILE *fPtr;
int count = 0;
struct processblock pb;
char * buffer;
buffer = malloc(sizeof(struct processblock));
if(!(fPtr= fopen(filename, "r")))
{
perror("No File");
fclose(fPtr);
return 0;
}
while(fgets(buffer,sizeof(struct processblock),fPtr))//read every line of file and store them in a buffer
{
if(sscanf(buffer,"%d,%d,%d,%d,%d,%d,%d", &pb.processId, &pb.userId, &pb.arrivalTime, &pb.priority, &pb.expectedTimeRemaining, &pb.expectedPctCPU, &pb.realTime) == 7 ) // read from the buffer
{
NewNode(p, pb); // creates new node from filled structure
count++;
}
}
free(buffer);
fclose(fPtr);
return count;
}
void ViewElements(List p)
{
struct processblock pb;
while(p != NULL)
{
pb = p->pblock;
printf("%d,%d,%d,%d,%d,%d,%d\n", pb.processId, pb.userId, pb.arrivalTime, pb.priority, pb.expectedTimeRemaining, pb.expectedPctCPU, pb.realTime);
p = p->next;
}
}
int main()
{
List HeadNode = NULL;
printf("Loaded %d lines\n", fillArrayFromFile("test.txt", &HeadNode));
ViewElements(HeadNode);
return 0;
}
I need to understand why give this error message "stop working". Here is my code.
#include <stdio.h>
struct student{
int id;
char name[20];
char *title;
};
int main()
{
struct student *st;
st->id = 23;
//st->name = "shaib";
st->title = "title";
printf ("%d", st->id);
printf ("%s", st->title);
return 0;
}
You define a pointer but it is not init, so is Undefined Behavior.
You can create a space in heap memory using malloc function.
int main()
{
struct student *st = malloc(sizeof(struct student));
if ( st != NULL)
{
st->id = 23;
..
}
else
{
fprintf(stderr, "No space for variable\n");
}
free(st);
return 0;
}
As you can see, each time you allocate memory with malloc you are responsible for freeing it. Otherwise you have memory leak
Second problem is that
st->name = "shaib";
is not the way you fill an array with a C-String.
You can achieve it with:
strcpy(st->name, "shaib");
So, you need to allocate some memory for your new struct:
1) Add a #include in order to...
2) Replace the struct declaration for a malloc()
Tip: use a better format for your print outputs with \t and \n
Here's the working code:
#include <stdio.h>
#include <stdlib.h>
struct student{
int id;
char name[20];
char *title;
};
int main()
{
struct student *st = malloc(sizeof (struct student));
st->id = 23;
//st->name = "shaib";
st->title = "title";
printf ("%d\t", st->id);
printf ("%s\n", st->title);
return 0;
}
You're creating a pointer to the student structure, but you're not setting it to point to anything.
You'll need to allocate memory for st (the student structure) before you can use it.
You are not allocating memory for st.
You can do it like this: st = malloc(sizeof (student));
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
I am (trying to) write a server-side daemon in c, and it accepts connections from clients. I need a struct that keeps information on each open connection, so I have created an array of my defined struct, and I have it dynamically re-sizing with realloc.
The problem I have is creating the struct within the array. I keep getting this error:
test.c:41: error: conversion to non-scalar type requested
What am I doing wrong?
I spend most of my time in PHP, and am a noob with c. I realize that I am making some simple, beginner mistakes (in other words, feel free to make fun of me). If I am doing something stupid, please let me know. I've put my quality time in with google, but have not figured it out. I have reproduced the issue on smaller scale, as below:
here is my test.h:
typedef struct test_ test;
and here is my test.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
//define the struct
struct test_ {
int id;
char *ip;
int user;
char *str;
};
//yes, the list needs to be global
test *test_list;
//
// add an item to the global list
//
int add(int id, char *ip, int size)
{
//
// increment size
if(id>size) {
size = id;
//try to expand the list
test *tmp = realloc(test_list,size);
if(tmp) {
//it worked; copy list back
test_list = tmp;
} else {
//out of memory
printf("could now expand list\n");
exit(1);
}
}
//
// HERE IS THE TROUBLE CODE::
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
test_list[id].id = id;
test_list[id].ip = malloc(strlen(ip));
strcpy(test_list[id].ip,ip);
test_list[id].user = 0;
test_list[id].str = NULL;
}
//
// main
//
int main(void)
{
//initialize
int size = 1;
test_list = malloc(size*sizeof(test));
//add 10 dummy items
int i;
for(i=0; i<10; i++) {
size = add(i, "sample-ip-addr", size);
}
//that's it!
return 0;
}
Try changing
test *tmp = realloc(test_list,size);
to
test *tmp = realloc(test_list,size*sizeof(test));
then delete
test_list[id] = (struct test)malloc(sizeof(test)+(sizeof(int)*5)+strlen(ip)+1);
When you allocate for test_list, there's already space for each member of the struct allocated, so you don't need to do it again. You just have to allocate for any pointers within the struct
The return value from 'malloc' is the memory address you've allocated. You can't cast it to a struct. What would that even mean?
You want something like: test_list=realloc(test_list, num_alloc * sizeof(test_));