I currently have a linked list and need to add data to it that is inputted by the user from the keyboard so i have two structs:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo courseinfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
courseinfo array[10];
struct StudentInfo *next;
};
So i have a linked list with 3 nodes currently. I then need to call a function and add a node. The node needs to be inserted in the correct place which is that the studentID before it needs to be less than it and the studentID after needs to be greater so the current IDs i have are 111111111, 333333333, and 444444444 and im trying to add 222222222 so it would go in the second spot so my function looks like:
studentinfo *addStudent(studentinfo *data) //returns type studentinfo* now
{
studentinfo *add;
add = malloc(sizeof(studentinfo));
add->next = NULL; //Now its set to NULL to begin
int knt;
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", add->StudentID);
printf("%s", "First Name: ");
scanf("%s", add->FirstName);
printf("%s", "Last Name: ");
scanf("%s", add->LastName);
printf("%s", "Number of courses: ");
scanf("%d", &add->num_course);
for(knt = 0; knt < add->num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &add->array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", add->array[knt].courseName);
}
if(searchStudentID(data, add->StudentID)) {
puts("immediately inside if");
while(data != NULL) {
puts("Immediately inside while");
if(strcmp(add->StudentID, data->StudentID) < 0) {
puts("inside if");
add->next = data;
data = add;
}
else {
puts("inside first else");
studentinfo *PrevPtr = data;
studentinfo *NPtr = data->next;
while(NPtr != NULL) {
("inside while(NPTR != NULL)");
if(strcmp(add->StudentID, NPtr->StudentID) < 0) {
add->next = PrevPtr;
PrevPtr->next = add;
break;
}
else {
puts("inside a differnet else");
PrevPtr = NPtr;
NPtr = NPtr->next;
}
}
if(PrevPtr->next == NULL) {
puts("inside last if");
add->next = NULL;
PrevPtr->next = add;
}
}
}
}
else {
puts("Found id");
}
return data; //returns data back to call
}
So i added all those puts statement because i wanted to see why the program kept crashing. So the puts statement puts("Inside a different else") is stuck in an infinite loop and keeps printing. The function searchStudentID simply returns 1 if we dont already have the ID and 0 if we already have it. I know that this function works so there is no need to post it.
I think the problem may be in the break; statement because it doesnt exit from the first while loop but only exits from the inner loop but im not positive.The call to this function look like:
list = addStudent(list); //Now the new data is stored in list
Where list is the linked list with 3 nodes
Linked list management is about managing node pointers, not just nodes. You want to do several things to make this considerably easier on yourself:
Separate the input step from the search+insertion step. They don't belong together regardless of how they may seem otherwise. The biggest benefit this brings to you is reducing your list insertion code to what it should be doing (and only what it should be doing): managing the linked list. I've kept yours intact, but you should really be error checking and doing the data reading somewhere else.
Use a pointer to pointer to walk the list. The biggest benefit from this is eliminating the need to special-case head-position insertion. If that is the position a new node will eventually occupy, so be it, but eliminating that special-case further reduces the complexity of the algorithm.
Don't search the list unless you're capable of retaining the search results to be used for insertion logic. It makes little sense to perform an O(N) scan of the linked list to determine if input data is already present, only to search it again to find the position said-data will actually be inserted. Do it once. Find the position where it belongs. If it is already there, do nothing, otherwise, you sit at the precipice of the proper insertion location already.
Finally, don't allocate a new node unless you know you need one. Use an automatic variable that helpfully self-discards if you end up doing nothing.
Putting all of that together gives something like this:
struct CourseInfo {
int courseID;
char courseName[30];
};
typedef struct CourseInfo CourseInfo;
struct StudentInfo {
char StudentID[10];
char FirstName[21];
char LastName[26];
int num_course;
CourseInfo array[10];
struct StudentInfo *next;
};
typedef struct StudentInfo StudentInfo;
StudentInfo *addStudent(StudentInfo *head)
{
StudentInfo **pp = &head, *p = NULL, rec;
int knt;
// TODO: error check your inputs!
printf("%s", "Adding new student:\nStudent ID: ");
scanf("%s", rec.StudentID);
printf("%s", "First Name: ");
scanf("%s", rec.FirstName);
printf("%s", "Last Name: ");
scanf("%s", rec.LastName);
printf("%s", "Number of courses: ");
scanf("%d", &rec.num_course);
for(knt = 0; knt < rec.num_course; knt++) {
printf("%s", "Course ID: ");
scanf("%d", &rec.array[knt].courseID);
printf("%s", "Course Name: ");
scanf("%s", rec.array[knt].courseName);
}
// walk the list pointers, starting with head, looking for
// a node that is equal or greater than the input node
while (*pp && (knt = strcmp((*pp)->StudentID, rec.StudentID)) < 0)
pp = &(*pp)->next;
// leave now if already present
if (*pp && knt == 0)
return head;
// allocate new node
p = malloc(sizeof *p);
if (p == NULL)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
// structure copy.
*p = rec;
// link into proper list position.
p->next = *pp;
*pp = p;
// always return the head (which may have updated above)
return head;
}
That's it. As mentioned, I would personally perform the input operation somewhere other than this function, but I leave that to you to consider.
Best of luck.
Since this function updates the list you either need it to be
studentinfo *addStudent(studentifo *data)
and return the updated head value. Or
void addStudent(studentifo **data)
and do
*data = <new thing>
Issues that I see:
You are not setting add->next to NULL.
You are changing data locally.
add->next = data;
data = add;
changes the value of data locally in the function. It does not change the value in the calling function.
You have the check
while(data != NULL)
following the if statement
if(searchStudentID(data, add->StudentID)) {
but I don't see any code to add the new student when searchStudentID(data, add->StudentID) returns false and when data == NULL to start with.
Related
I am trying to get inputs from the user and then append the struct to the end of the linked list. This works fine but I want to add another feature that would prevent the input being added if all the details are exactly the same. (In this case email, class, first and last name)
The for loop I added in the middle is what I tried to do to achieve this feature. The program goes into the loop without any problems but the input will still be added. How would I fix this?
struct request *append(struct request *list){
char f_name[NAME_LEN+1];
char l_name[NAME_LEN+1];
char e_address[EMAIL_LEN+1];
char c_name[CLASS_LEN+1];
//get input
printf("\nEnter email: ");
scanf("%s", e_address);
printf("\nEnter class: ");
scanf("%s", c_name);
printf("\nEnter child first name: ");
scanf("%s", f_name);
printf("\nEnter child last name: ");
scanf("%s", l_name);
//allocate memory for the structure
struct request* p = (struct request*) malloc(sizeof(struct request));
struct request *temp = list;
//////////WHAT I TRIED BUT DIDN'T WORK
for (p = list, temp = NULL; p != NULL; temp = p, p = p -> next) {
if (strcmp(p -> first, f_name) == 0 && strcmp(p -> last, l_name) == 0 && strcmp(p -> email, e_address) == 0 && strcmp(p -> class, c_name) == 0) {
printf("Output: request already exists");
return list;
}
}
//store the data
strcpy(p->first, f_name);
strcpy(p->last, l_name);
strcpy(p->email, e_address);
strcpy(p->class, c_name);
p->next = NULL;
//if list is empty return pointer to the newly created linked list
if (list == NULL) {
return p;
}
//traverse to the end of the list and append the new list to the original list
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = p;
return list;
}
First off, with those scanf's you should do something like this to avoid buffer overflows.
As to your question, you should malloc p after your for-loop since we should only allocate it if there is no other node with the exact same info (And as paddy said, in your code it causes a memory leak because you set p to point to something else hence losing that newly malloc-ed data).
Your loop is more complex than it needs to be. Admittedly I can't see why the for-loop wouldn't detect a copy, maybe providing some input cases would help clear it up? Either way I'd replace that section of the code with this:
// Get a pointer to the head of the list
struct request *temp = list;
// Find and node with the exact same data
while(temp->next != NULL) {
if(!strcmp(temp->first, f_name) && !strcmp(temp->last, l_name) && !strcmp(temp->email, e_address) && !strcmp(temp->class, c_name)){
printf("Output: request already exists");
return list;
}
temp = temp->next;
}
// Allocate p and reset temp
struct request *p = (struct request*) malloc(sizeof(struct request));
temp = list;
// etc
The program is for a hotel laundry service. The user puts in their room number, first and last name, and the number of items they want to wash. This information is put into a node in a linked list. In the main menu, the user can add more room requests, update a request, print the requests, or quit the program.
The structure can be defined as
struct request{
int room_number;
char first[NAME_LEN+1];
char last[NAME_LEN+1];
int num_items;
struct request *next;
};
I have run into a few issues with my functions:
The append function:
/*
APPEND FUNCTION:
Gets the room number, first name, last name, and the number of items the user wants to wash.
Creates a new node and appends it to the end of the linked list.
*/
struct request *append_to_list(struct request *list)
{
struct request *new_node, *last_node, *search;
new_node = malloc(sizeof(struct request));
//new_node->next = NULL;
if(new_node == NULL)
{
printf("Error allocating memory.\n");
return list;
}
//get room number
printf("Enter room number: ");
scanf("%d", &new_node->room_number);
//search to see if the room number already exists in the LL.
for(search = list; search != NULL; search = search->next)
{
if(search->room_number == new_node->room_number)
{
printf("Room request already exists. Update request using main menu.");
return list;
}
}
//get first and last name
printf("Enter first name: ");
read_line(new_node->first, NAME_LEN+1);
printf("Enter last name: ");
read_line(new_node->last, NAME_LEN+1);
//get the number of items.
printf("Enter the number of items you wish to wash: ");
scanf("%d", &new_node->num_items);
new_node->next = list;
//if list is empty, return pointer to newly created linked list.
if(list == NULL)
{
list = new_node;
return new_node;
}
//else add request to the end of the LL and return pointer to the LL.
else
{
last_node = list;
while(last_node->next!=NULL)
last_node = last_node->next;
}
last_node->next = new_node;
return list;
}
Some issues I have run into are that for some reason I cannot make more than two requests. I get an error and the program crashes.
The update function:
/*
UPDATE FUNCTION:
User enters their room number and the node containing the room number is updated with the number of items the user wants to add on.
*/
void update(struct request *list)
{
struct request *search;
int add_items;
//ask to enter room num
printf("Enter room number: ");
int room;
scanf("%d\n", &room);
//find matching room num
for(search = list; search != NULL; search = search->next)
{
if(search->room_number == room)
{
//ask to enter num of items to be added and update num of items
printf("How many items would you like to add: ");
scanf("%d\n", &add_items);
search->num_items = search->num_items + add_items;
search = search->next;
return;
}
}
//if room num is not found, print a message.
printf("Could not find request.");
return;
}
An issue I had with this function is that the program will just stop when I enter the room number... It does not crash, it just seems like it gets stuck... Not really sure why.
Finally the print function:
/*
PRINTLIST FUNCTION:
Prints all the nodes in list.
*/
void printList(struct request *list)
{
//print room num, first and last name, and num of items for all requests on the list.
while(list != NULL)
{
printf("%d ", list->room_number);
printf("%s ", list->first);
printf("%s ", list->last);
printf("%d\n ", list->num_items);
list = list->next;
}
}
My only issue with this function is that it infinitely prints all the nodes without stopping.
Any help is appreciated. Thank you!
You need to decide whether you want new_node at the end or the beginning of the list. list = new_node puts it at the beginning, the subsequent loop puts it at the end, so you create a cyclic list with no end and your next insert operation gets stuck in an infinite loop. If you want new_node to be at the beginning, you don't need to search for the end. If you want it at the end, then new_node->next must be set to NULL, not to list.
Your for loop body only gets executed once because you've got return in both arms of your if statement.
This is probably because of the bullet point 1 above.
Okay so I am sure this is not too difficult a question but I am lost after trying to figure it out for so long so here is the code first the declaration for my structs.
struct GraphicElement {
char* fileName;
struct GraphicElement* pNext;
};
struct RasterGraphic {
struct GraphicElement* GraphicElements;
};
Then I call a function that takes care of the initialization which I believe is working properly.
int main(void)
{
char response;
BOOL RUNNING = TRUE;
struct RasterGraphic RG;
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
InitRasterGraphic(&RG);
The init function is as follows
void InitRasterGraphic(struct RasterGraphic* pA)
{
pA->GraphicElements = malloc(sizeof(struct GraphicElement));
if (pA->GraphicElements == NULL) return;
//pA->GraphicElements = 0;
//pA->GraphicElements->pNext = NULL;
//pA->GraphicElements->fileName = NULL;
pA->GraphicElements->fileName = (char*)malloc(sizeof(char));
return;
}
So the next part of code is where I am going to ask my question. I have a function that takes a user input of some sort of string. Id like to take that input and add it to the next element. So every time the user calls the function they put in their input and its added to the next element. My code right now is a mess and I know it definitely is probably way off I've tried a bunch of things already. I believe I need to use realloc. What I am not able to wrap my head around here is how to take the input and add it so that later on I can printf all the elements in order. so for example user calls function 3 times and puts in inputs "hello" "world". Later I would like to cycle through and print
graphic 1 is "hello"
graphic 2 is "world"
void InsertGraphicElement(struct RasterGraphic* pA)
{
char response[256];
printf("Insert a GraphicElement in the RasterGraphic\nPlease enter the GraphicElement filename: ");
scanf("%s", &response[0]);
pA->GraphicElements->fileName = realloc(pA->GraphicElements, 256*sizeof(char));
pA->GraphicElements++;
strcpy(pA->GraphicElements->fileName, &response);
if (pA->GraphicElements == 1){
printf("\nThis is the first GraphicElement in the list\n");
}
return;
}
Here are the few issues in your code.
I believe InitRasterGraphic should just initialize the pA->GraphicElements = NULL instead of mallocing it. Since same should be handled in InsertGraphicElement function.
pA->GraphicElements->fileName = (char*)malloc(sizeof(char)); this will just allocate the memory of size single char and there is no point in allocing and reallocing.
scanf("%s", &response[0]); should be scanf("%s", &response[0]);.
pA->GraphicElements++; This is wrong instead use one more member to maintain the number of nodes in the list.
Hence after correcting the above issues your code will look like below.
your RasterGraphic will look like below.
struct RasterGraphic {
int numNodes;
struct GraphicElement* GraphicElements;
};
Your InitRasterGraphic will look like below.
void InitRasterGraphic(struct RasterGraphic* pA)
{
pA->GraphicElements = NULL;
pA->numNodes = 0;
return;
}
Your InsertGraphicElement will look like below.
void InsertGraphicElement(struct RasterGraphic* pA)
{
struct GraphicElement *newNode = malloc(sizeof(*newNode));
if (newNode == NULL) return;
newNode->fileName = malloc(256*sizeof(char));
if (newNode->fileName == NULL) return;
newNode->pNext = NULL;
printf("Insert a GraphicElement in the RasterGraphic\nPlease enter the GraphicElement filename: ");
scanf("%s", newNode->fileName);
if (pA->GraphicElements == NULL)
{
pA->GraphicElements = newNode;
}
else
{
struct GraphicElement *tempHead = pA->GraphicElements;
while(tempHead->pNext != NULL)
{
tempHead = tempHead->pNext;
}
tempHead->pNext = newNode;
}
pA->numNodes++;
if (pA->numNodes == 1){
printf("\nThis is the first GraphicElement in the list\n");
}
return;
}
I was trying to do an example about linked list. First, I added the values to the variables and there was no problem. But when I tried to get values from user, the program crashed when entering midterm 2 grade. I tried other input functions but the result is same. Where is the problem?
#include <stdio.h>
struct student
{
char *name;
int m1,m2,final;
struct student* next;
};
main()
{
addStudent();
system("PAUSE");
}
addStudent()
{
struct student *node = NULL;
struct student *firstnode;
firstnode = (struct student *)malloc(sizeof(struct student));
node = firstnode;
printf("press 0 to exit \n");
while(1)
{
printf("Student name: ");
scanf("%s", node->name)
if(node->name == "0") break;
printf("Midterm 1: ");
scanf("%d", node->m1);
printf("Midterm 2: ");
scanf("%d", node->m2);
printf("Final: ");
scanf("%d", node->final);
node->next = (struct student *)malloc(sizeof(struct student));
node = node->next;
}
node->next = NULL;
node = firstnode;
while(node->next);
while(node->next != NULL)
{
printf("%s - ",node->name);
printf("%d ", node->m1);
printf("%d ", node->m2);
printf("%d ", node->final);
node = node->next;
}
system("PAUSE");
return 0;
}
Fix 1
Remove the line
while(node->next);
Reason: It will put you on an infinite loop in most cases and it is unnecessary.
Fix 2
Replace the loop
while(node->next != NULL) {
}
with
if (node->next != NULL) {
while (node->next->next != NULL) {
}
}
Reason: You are allocating one additional struct each time and keeping it empty for reading next time. So the Linked List will end before the next becomes NULL.
Fix 3
Replace following in struct
char *name;
with
char name[80];
Reason: Memory not being allocated.
Fix 4
Replace at all occurrences of scanf (except for name)
scanf("%d", node->m1);
with
scanf("%d", &node->m1);
Reason: scanf needs memory location of data to be read.
Good luck
Your code has multiple errors.
To start with, the first scanf("%s", node->name) is missing its terminating semicolon.
Next, your function signatures are sloppy. main() should be int main(void). addStudent() should be int addStudent(void). (Or, get rid of its return 0 and let it return void.) Since you don't pre-declare addStudent(), you should define it before main() so that main() can know about it.
The crash, though, is because you haven't allocated memory for node->name. You've allocated memory for a node, but that doesn't give you space to put the name.
I'm very new to C, so I'm not totally sure what's the matter. I can't figure out how to print more than a single integer value in a function.
add function:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof(struct list));
strcpy((*newAlbum).name, name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
show function:
void show()
{
system("clear");
struct list *current_node;
current_node = pFirst;
while(current_node != NULL)
{
printf("Album #%d \n",current_node->id);
printf("Album Name: %s \n",current_node->name);
printf("Album Copies:%d \n",current_node->copies);
printf("\n");
current_node=current_node->pNext;
}
}
My program prints out the current_node->id as if it were current_node->copies, and current_node->copies is printed out as 134516043, which is obviously, wrong.
I think I must be passing something wrong to the function or something, but I can't figure it out. Any tips?
I call the function add like this:
add(name,id,copies);
The list is as so:
/* THE LIST */
struct list{
char name[52];
int id;
int copies;
int sold;
struct list* pNext;
};
struct list *pFirst = NULL;
I call the function with user input with this piece of code:
printf("Enter the name of the new album. \n");
scanf("%s",&name);
printf("Enter the album id. \n");
scanf("%d",&id);
printf("Enter number of copies. \n");
scanf("%d," &copies);
// Pass data to add()
add(name,id,copies);
Your code that you've shown is OK, as long as you don't pass an album name to add() which is longer than 51 characters. If you do, you'll get very weird output, and possibly a crash.
To guard against this, you should use a length-limited copy - for example:
void add(char *name,int id,int copies)
{
/* Pointer to next item */
struct list *newAlbum;
newAlbum = malloc(sizeof *newAlbum);
if (newAlbum) {
snprintf(newAlbum->name, sizeof newAlbum->name, "%s", name); // Set album name
newAlbum->id = id;
newAlbum->copies = copies;
newAlbum->pNext = pFirst;
pFirst = newAlbum;
}
}
(note that sizeof *newAlbum is a little better than sizeof(struct list), since the former is "obviously correct" when reading the line - it will still be corret if the type of newAlbum is ever changed).
The only thing I can see wrong here is that you don't check the length of name. You should use:
strncpy(newAlbum->name, 52, name);
This will prevent overrunning the name buffer.