I have spent the last 2.5 hours creating this linked list and trying to understand why it is not passing a memory address to the head of the list. I'm trying to understand linked lists in C before I move onto what my class is learning about data structures in java. I looked into other questions and I don't understand why it doesn't work. Please excuse the comments I've been making an effort to understand everything. Thanks in advance for your time and help!
The head variable is equal to NULL after the new assignment
head = addFamMember(NULL); in the main thread. But I can see that memory has been allocated inside the add function by printing it's members (name, age, and next pointer). Here's the output:
Enter command to add, print, or quit: add
Enter name and age: brett 28
Added:brett Age:28 POINTING to:(null)
Enter command to add, print, or quit:
Here's the code: I left he comments to possibly help describe my thinking and pinpoint where I'm going wrong.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct S_Family{
char name[16];
int age;
struct S_Family *next;
}Family;
//prototypes
Family *addFamMember (Family *previous);
void CleanUp(Family *start);
void PrintList(Family *start);
int main(){
setvbuf(stdout, NULL, _IONBF, 0);
printf("Enter command to add, print, or quit: ");
char input[16]; //fgets var to store input
char command[16]; //sscanf var to store read info from input
Family *head = NULL; //For a linked list we need to set up the first node and point it NULL
Family *newest = NULL; //We also need a pointer dedicated to updating the latest created node
//This while loop will continue to get input until the command "quit" is typed
//It includes the functionality of printing the list and adding new nodes
while( fgets(input, 15, stdin)){
sscanf(input, "%s", command);
if ( strcmp(command, "quit") == 0) {
printf("\n\nBreaking.........");
break;
} else if ( strcmp(command, "print") == 0) {
PrintList(head);
} else if ( strcmp(command, "add") == 0) {
if ( head = NULL){
head = addFamMember(NULL); //If there are no nodes give head a memory address so now we do (recursion somewhat?)
printf("head:%s ", head->name); //this doesn't print!! Head = NULL above for some reason.
newest = head; //newest cannot stay equal to NULL. this allows us to pass it as a param to add function w/out the start being NULL anymore
printf("newest:%s ", newest->name);
} else {
newest = addFamMember(newest); //Recursion where the new node gets a mem address and gets the previous node as guide to cont. the list
} //now we go to the add function
}
printf("\nEnter command to add, print, or quit: ");
}
CleanUp(head);
return 0;
}
/*We want to return a new family member structure
so we start of with a Family return type. The param
as mentioned before needs to be a pointer to the address
of the previous node. That node will be pushed away from the
NULL in a singly or doubly linked list */
Family *addFamMember (Family *previous) {
/*Now we need to get the member variable info for that newFamMember
and store into the newly created data structure newFamMember*/
char input[16];
printf("Enter name and age: ");
fgets(input,15, stdin);
Family *newFamMember = malloc(sizeof(Family)); //create new address for newFamMember
sscanf(input, "%s %d", newFamMember->name, &newFamMember->age); //takes the input (first a string then a integer) and stores it into its proper place
printf("Added:%s Age:%d POINTING to:%S \n\n",newFamMember->name,newFamMember->age, newFamMember->next->name);
newFamMember->next = NULL; //initialize it's pointer member var but more importantly maintains the linked list by pointing to null.
/*Now we tell the computer what to do if this isn't the first node
or not. If it is then there isn't a previous node so there is no
way to set any other nodes' pointers to point to something else*/
if ( previous != NULL){
previous->next = newFamMember; //if previous is not equal to NULL set the previous' next pointer to newFamMember
printf("previous:%s ", previous->next->name);
}
return newFamMember; //we always want to return a newly added family member. That's this function's purpose
}
/*now we can print the list*/
void PrintList (Family *head) { //start is a pointer so we can pass the value of start
Family *currentMember = head; //we create currentMember and set it equal to start so we can iterate through the list and print each one
int count = 0;
if (currentMember == NULL){
printf("There are no family members\n");
}
while (currentMember != NULL) {
count++;
printf("\n\nmember:%d Name:%s Age:%2d POINTING TO:%s\n",
count, currentMember->name,
currentMember->age,
currentMember->next->name);
currentMember = currentMember->next; //move to the next node in the list headed towards NULL
}
}
void CleanUp(Family *head){
Family *freeMe = head;
Family *holdMe = NULL;
while(freeMe != NULL) {
holdMe = freeMe->next;
printf("\nFree Name:%s Age:%d\n",
freeMe->name,
freeMe->age);
free(freeMe);
freeMe = holdMe;
//PrintList(*start);
}
}
Related
PREFACE: The goal is to prompt a user for input, adding each element (input line) into a linked list.
I have been playing around with some sample code from Learn-C.org, which shows a linked list example.
I have modified the code so that it takes "strings" instead of integers.
My insert function is as follows:
void push(node_t * head, char *data) {
node_t * current = head;
if(head == NULL) {
printf("First element ever!\n");
}
else if(current->data == NULL) {
current->data = data;
current->next = NULL;
}
else {
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(node_t));
current->next->data = data;
current->next->next = NULL;
}
}
Now, in MAIN, I initiate the list as follows:
node_t * test_list = malloc(sizeof(node_t));
Adding elements is done with:
push(test_list, "FOO");
push(test_list, "FEE");
push(test_list, "FAA");
When printing the list, using print_list(test_list), I get the following output:
FOO
FEE
FAA
PROBLEM
However, I have then included a while loop that prompts user for input and adds this to the linked list.
char command[120];
int counter = 0;
while(counter < 3) {
printf("Enter element: ");
fgets((void *)command, sizeof(command), stdin);
push(test_list, command); //Insert
counter++;
}
However, this does not add each element into the link list. Instead, it adds the LAST element into the list three times.
For instance, when providing:
Enter element: Argentina
Enter element: Mexico
Enter element: Sweden
The list prints out as:
FOO
FEE
FAA
Sweden
Sweden
Sweden
EDIT (added print function)
My print function is as follows:
void print_list(node_t * head) {
node_t * current = head;
printf("**** Printing list ****\n");
while (current != NULL) {
printf("%s\n", current->data);
current = current->next;
}
}
What am I missing, and alternatively: How can I fix this? Any help is highly appreciated.
Use strdup to return a copy of the string allocated on the heap.
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
node_t *test_list = malloc(sizeof(node_t));
test_list->next = NULL;
test_list->data = NULL;
while(counter < 3) {
printf("Enter element: ");
fgets((void *)command, sizeof(command), stdin);
push(test_list, strdup(command)); //Insert
counter++;
}
You have an array command with capacity of 120. You use this to read in values. This is ok.
Then you send a pointer to this array to be stored. It gets stored, everything is still fine.
The next time you read input, you read it to the same array, for which you gave a pointer to be stored. So you are changing the content of the memory where that pointer points to. This is not ok.
You need to allocate separate memory areas for each string and handle their deallocations. strdup is the easiest way to get a new memory block with the contents of the user input.
But do remember that you really have to deallocate the memory when you don't need it anymore. In this case you might never remove any strings, but when you do, you can't just remove the element, you have to also free the memory used by the string.
current->data = data; here you are copy only pointer address not data, on that address (address of 'command') last data ('Sweden') will be available.
you should use strcpy(current->data,data) to copy data.
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.
PREFACE: The goal is to prompt a user for input, adding each element (input line) into a linked list.
I have been playing around with some sample code from Learn-C.org, which shows a linked list example.
I have modified the code so that it takes "strings" instead of integers.
My insert function is as follows:
void push(node_t * head, char *data) {
node_t * current = head;
if(head == NULL) {
printf("First element ever!\n");
}
else if(current->data == NULL) {
current->data = data;
current->next = NULL;
}
else {
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(node_t));
current->next->data = data;
current->next->next = NULL;
}
}
Now, in MAIN, I initiate the list as follows:
node_t * test_list = malloc(sizeof(node_t));
Adding elements is done with:
push(test_list, "FOO");
push(test_list, "FEE");
push(test_list, "FAA");
When printing the list, using print_list(test_list), I get the following output:
FOO
FEE
FAA
PROBLEM
However, I have then included a while loop that prompts user for input and adds this to the linked list.
char command[120];
int counter = 0;
while(counter < 3) {
printf("Enter element: ");
fgets((void *)command, sizeof(command), stdin);
push(test_list, command); //Insert
counter++;
}
However, this does not add each element into the link list. Instead, it adds the LAST element into the list three times.
For instance, when providing:
Enter element: Argentina
Enter element: Mexico
Enter element: Sweden
The list prints out as:
FOO
FEE
FAA
Sweden
Sweden
Sweden
EDIT (added print function)
My print function is as follows:
void print_list(node_t * head) {
node_t * current = head;
printf("**** Printing list ****\n");
while (current != NULL) {
printf("%s\n", current->data);
current = current->next;
}
}
What am I missing, and alternatively: How can I fix this? Any help is highly appreciated.
Use strdup to return a copy of the string allocated on the heap.
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
node_t *test_list = malloc(sizeof(node_t));
test_list->next = NULL;
test_list->data = NULL;
while(counter < 3) {
printf("Enter element: ");
fgets((void *)command, sizeof(command), stdin);
push(test_list, strdup(command)); //Insert
counter++;
}
You have an array command with capacity of 120. You use this to read in values. This is ok.
Then you send a pointer to this array to be stored. It gets stored, everything is still fine.
The next time you read input, you read it to the same array, for which you gave a pointer to be stored. So you are changing the content of the memory where that pointer points to. This is not ok.
You need to allocate separate memory areas for each string and handle their deallocations. strdup is the easiest way to get a new memory block with the contents of the user input.
But do remember that you really have to deallocate the memory when you don't need it anymore. In this case you might never remove any strings, but when you do, you can't just remove the element, you have to also free the memory used by the string.
current->data = data; here you are copy only pointer address not data, on that address (address of 'command') last data ('Sweden') will be available.
you should use strcpy(current->data,data) to copy data.
I have a linked list and I am attempting to insert a new node, which seems to be successful at inserting the node where I want it to go, but the variables keep coming out as NULL. Could someone point to where I am causing this to happen?
Here is the print and insert method.
void printList(node *head)
{
node *p;
p = head;
if(p->next == NULL)
printf("No stops currently in the tour.");
else
{
while(p->next != NULL)
{
printf("Tour Stop: %s - Description: %s\n", p->name, p->name);
p = p->next;
}
}
}
void insertInOrder(node *head, node *newNode)
{
printf("What is the stop you want the new stop to come after? Type 'end' to insert at the end of the tour.");
char key[100];
scanf("%s", &key);
getchar();
node *p;
p = head->next;
if(head->next == NULL)
head->next = newNode;
else if(key == "end")
{
while(p->next != NULL)
p = p->next;
p->next = newNode;
printf("\nAT 57, newNode->info = %s and newNode->name = %s", newNode->info, newNode->name);
}
else
{
while(strcmp(p->name, key) != 0)
{
if(p->next == NULL)
{
printf("Couldn't find the tour stop you requested, inserting at end of tour.");
break;
}
p = p->next;
}
p->next = newNode;
}
And here is the createNewNode method I am using to pass into the insert method
node* createNewNode()
{
node *newNode;
newNode = malloc(sizeof(struct node));
printf("Enter the name of the new tour stop.\n");
char newName[100];
fgets(newName, sizeof(newName), stdin);
newNode->name = newName;
printf("Enter information about the tour stop. Max number of characters you can enter is 1000.\n");
char newDescription[1000];
newNode->info = newDescription;
fgets(newDescription, sizeof(newDescription), stdin);
return newNode;
}
You are not copying the string into the structure. You're just copying the pointer to a local variable inside createNewNode():
char newName[100];
fgets(newName, sizeof(newName), stdin);
newNode->name = newName;
This means undefined behavior when you later access that stored pointer since it's no longer valid.
You need to have character space inside the structure, and copy (or just read) the string in there so it remains allocated for as long as the node exists.
There are so many issues with this code I don't even know where to start.
printf("What is the stop you want the new stop to come after? Type 'end' to insert at the end of the tour.");
char key[100];
scanf("%s", &key);
getchar();
If you absolutely need to use scanf (it's advised not to) to read the string you should add a maximum characters to read before the '%s' format specifier, like scanf("%99s", &key). You should read 99 characters instead of 100 so that null-termination won't overflow your array.
else if(key == "end")
{
//code
}
Here instead of comparing the contents of key to the const char* "end" you simply compare the address of the array key to the address of const char* "end", you should use
strcmp instead. (or even better strncmp)
node* createNewNode()
{
node *newNode;
newNode = malloc(sizeof(struct node));
printf("Enter the name of the new tour stop.\n");
char newName[100];
fgets(newName, sizeof(newName), stdin);
newNode->name = newName;
printf("Enter information about the tour stop. Max number of characters you can enter is 1000.\n");
char newDescription[1000];
newNode->info = newDescription;
fgets(newDescription, sizeof(newDescription), stdin);
return newNode;
}
Here the new node's name and info pointers will point to memory that has been released after the call to createNewNode has returned. This is undefined behaviour and your program may segfault or worse.
You should copy the read buffers to new ones allocated on the heap and set your pointers to point at them, or allocate the buffers on the heap at the first place.
int newDescriptionLength = strlen(newDescription) + 1; //plus 1 for null termination
char* newDescriptionCopy = malloc(newDescriptionLength);
strncpy(newDescriptionCopy, newDescription, newDescriptionLength);
newNode->info = newDescriptionCopy;
strncpy will make sure that your newDescriptionCopy string is null-terminated after
all characters of the source string newDescription have been copied.
The allocated buffers should be taken into account when freeing a node.
Also, you should read one character less with fgets too, because supplying the exact count
of characters allowed won't null terminate your string.
You should resolve those issues before delving deeper at your problem because your program is full of undefined behavior and it won't be safe to make assumptions during debugging.
From what I can see of your code (you have not printed the calling functions or init of the linked list, if there is one), it looks like you are never checking the first element (i.e. head). So when the list is completeley empty then head will point to NULL. So using your print function as an example you should have:
void printList(node *head)
{
node *p;
p = head;
// Check if the list contains anything
if (p == NULL)
{
printf("List is empty");
}
else
{
printf("Tour Stop: %s - Description: %s\n", p->name, p->name); // print first/head element
// Continue while there are more elements
while(p->next != NULL)
{
printf("Tour Stop: %s - Description: %s\n", p->name, p->name);
p = p->next;
}
}
}
It may be the same for your insert function, so that you never insert anything?
Note: Unwind also has a very valid point in his answer
I know how the program works but i can't wrap my head around the concenpt. Here is the main function:
void main() {
lista node1, p, q;
int n, i;
int a;
node1 = NULL;
printf("data = ");
scanf("%d", &a);
while (!feof(stdin)) {
if (add_to_list(&node1, a)!=0) {
printf("nod (CTRL-z) = ");
scanf("%d", &a);
}
else printf("can't insert");
}
And here is the add_to_list function
int add_to_list(lista *head, int info) {
lista p, nou;
int cod;
if (nou = (lista)malloc(sizeof(nod))) {
if (*head == NULL) {
nou->data = info;
nou->leg = NULL;
*head = nou; //la adresa listei noastre in primul element se baga noul element creat aici
}
else {
p = *head;
while (p->leg != NULL) {
p = p->leg;
}
nou->data = info;
nou->leg = NULL;
p->leg = nou;
}
cod = 1;
}
else {
cod = 0;
}
return cod;
}
And this is the data structure i'm using
typedef struct nod {
int data;
struct nod *leg;
} *lista;
So the problem is, although i fully understand what happens in the whole program, I can't understand how are nodes continually added.
If you look in the main() function i have node1 set to NULL, then i get the .data (held in int a) for each 'node'. The add_to_list function is called passing the address of node1 and the digit, right? In the function it allocates space since it's null, puts the value of variable a in the .data field then asigns NULL to this node's pointer (it's asumes it might be the last one so it's the right thing to do). Clear until now.
Now returning 'cod 1' to the main function() it means i'm allowed to further input numbers from my keyboard. The thing is, let's say I input the digit '3', again function add_to_list is called passing a null node1 and '3' (var a). After this i don't get it.
my ideea is that node1 is no longer null since it was passed as a 'reference' and it contains the address of the first node. So in the add_to_list() it should jump straight to else part, try to find a node which points to null (the last one) and from there create a new one and connect it to the last one. Am i right? Or am I missing something?
Thank you.
Yes, you are right: the else part works for each node except the first one. And the node1 parameter is modified only once when the first node is added into an [empty] list.
The first time add_to_list() is called the head is NULL so the head is assigned to a new node with the right data. After that it isn't NULL so it will execute the else portion, which goes to the very end of the list then puts the newly created node at the end. If it returns 0 then there was an issue with malloc and that data wasn't inserted. Otherwise it was good. feof() will return 0 as long as you haven't hit the "end" of stdin and this allows you to continue inserting data.
Your function to create node will return NULL only if malloc fails, of if the whole list is null.
in the create node function you are rotation through the whole list to find the end node (that will point to NULL), and insert newly created node there