Adding to the front of a Linked List in C - c

I'm having trouble comprehending linked lists in general. I understand how they work on paper, but once I get to coding them, I never seem to accomplish anything.
Here's my code:
header file:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct List {
int data;
struct List * next;
} List;
implementation file:
#include "test.h"
void addToFront(int data, List * head);
int main(void) {
List * list;
list = malloc(sizeof(List));
list->next = NULL;
List * head;
head = NULL;
addToFront(5,head);
printf("%d",head->data); //print first element
printf("%d",list->data); //print first element
}
void addToFront(int data, List * head) {
if(head == NULL) {
List * newNode = malloc(sizeof(List));
newNode->data = data;
head = newNode;
}
else {
List * newNode = malloc(sizeof(List));
newNode->data = data;
newNode->next = head;
head = newNode;
}
}
I know that for a linked list to be empty, the header is NULL, so I have that checked there. The issue arises as I get a segfault saying that the header is not initialized, well obviously it's not, if I do initializes, I can't keep track of if the list is empty or not, hence the use of a header node.
What can I do now? I don't want to use double pointers, as for my class no one else is using them at any point so far yet (Please don't make me use double pointers), and I'm completely lost on how to proceed here.
I was thinking of trying this without a header node. As such I could have a counter that keeps track of the items in the list, check if its zero and then just add the basic element to the front, otherwise do the same thing I'm doing in my else statement?

The problem is in your addFront function, you only pass the pointer to the head, in order to change what the head points to you need to pass the address of the head:
void addToFront(int data, List ** head)
then
*head = newHead
When you pass only the pointer you are just passing a copy of the pointer to the function so any changes to the pointer you do inside the function are lost once you leave the function scope.
Similar in concept to:
void f(int n)
{
n = 53;
}
To avoid double pointer you can return the new head:
List* addToFront(int data, List* head)
{
...
return newNode;
}
...
head = addToFront(data, head);
...

If you don't want to use double pointer, you can use the header node as a sentinel node, which act solely as a placeholder, so that the first element is linked by head->next, and to check if the list is empty, check head->next == NULL. Try this:
int main(void) {
List *head = malloc(sizeof(List));
head->data = 0;
head->next = NULL;
addToFront(5, head);
List *first = head->next;
if (first) { // safe guard for first element
printf("%d", first->data); //print first element
printf("%d", first->data); //print first element
}
}
void addToFront(int data, List * head) {
List * newNode = malloc(sizeof(List));
newNode->data = data;
newNode->next = head->next;
head->next = newNode;
}

Related

create linked list using char array as data

I am having a problem on assigning char array after I create a node.
I am having trouble on this function I created which it would make a new node and then assign character array into the created node. I don't have any problems when it comes to int but I can't seem to run when I switched to character array.
I get a run time error when I try to run my code.
Any help would be much appreciated.
Thank You!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct node{
char data[MAX];
struct node *next;
};
typedef struct node* nodePtr;
void create(nodePtr head, char data[]);
int main()
{
nodePtr head = NULL;
char str[] = "HELLO";
create(head, str);
return 0;
}
void create(nodePtr head, char data[])
{
if (head == NULL)
{
// empty list
head = (nodePtr) malloc(sizeof(struct node)); // create root
strcpy(head->data, data);
head->next = NULL;
}
else
{ // list not empty
nodePtr current = head; // start at the beginning...
while (current->next != NULL)
{
current = current->next; // walk to the end of the list
}
current->next = (nodePtr) malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
}
}
There is more than one problem with your program.
To begin with, when you add elements to a list that already has a head, are not initializing the next member. This will cause multiple list insertions to fail.
current->next = malloc(sizeof(struct node));
current = current->next;
strcpy(current->data, data);
current->next = NULL; //<-- you forgot this
The other big issue is that you are also leaking your entire list, because you pass the head pointer by value into the function. When the list is empty, the function modifies this value but it's a copy so when the function returns, the value of head in main is still NULL.
There are two options. Either you change your function to expect a pointer to the head-pointer, or you use what's called a "dummy head".
Using a dummy head actually simplifies lists a lot. What this means is your head is actually an unused node whose sole responsibility is to store the actual head in its next-pointer:
struct node head = {}; // dummy head node
create(&head, str);
The above will never actually hit the head == NULL part of the create function because dummy heads guarantee the head is always a valid node. So if you set your list up that way, then your create function can be simplified.
If you don't want to do this, then you need to pass a pointer to your head pointer. That means your create function becomes:
void create(nodePtr *head, char data[])
{
if (*head == NULL)
{
*head = malloc(sizeof(struct node));
strcpy((*head)->data, data);
(*head)->next = NULL;
}
else
{
nodePtr current = *head;
while (current->next != NULL) current = current->next;
current->next = malloc(sizeof(struct node));
current = current->next;
if (current != NULL)
{
strcpy(current->data, data);
current->next = NULL;
}
}
}
And you would invoke the above as:
nodePtr head = NULL;
create(&head, str);
One extra thing you might wish to do is make the function return the node that it created. The reason you might want to do this is that currently if you're inserting many items into the list you have to search to the end every time. If instead you pass the last node as the next head, then no searching is necessary:
nodePtr head = NULL;
nodePtr tail = head;
tail = create(head, "goodbye");
tail = create(tail, "cruel");
tail = create(tail, "world");
This would mean a small modification to your function, but I'm sure you can work that out.

Linked List Reversal has errors

In our class right now we're covering nodes and linked lists, and are working on our first linked list program.
We've been given the following guidelines by the teacher:
Make sure your main function will accept 10 characters from STDIN and create a linked list with those characters (so your nodes will have a char member). Then, add an additional function called reverse. The purpose of the reverse function will be to create a copy of the linked list with the nodes reversed. Finally, print off the original linked list as well as the reversed linked list.
I've gotten it all written out, and I've compiled it with no errors - but the program doesn't work as intended, and I'm not entirely sure why. I'm sure it has something to do with how I've set up the pointers to "walk" the nodes - as the debug I put in shows it looping twice per user input letter. Specifications are that we're only supposed to use one function, and we pass a Node* to the function, and it returns the same. The function cannot print out anything - only make the second list that is a reverse of the first.
Any help would be greatly appreciated, I'm not terribly good at this yet and I'm sure I've made some rather silly mistakes.
#include <stdio.h>
#include <stdlib.h>
//struct declaration with self-reference to make a linked list
struct charNode {
char data;
struct charNode *nextPtr;
struct prevNode *prevPtr;
};
typedef struct charNode Node; //makes Node an alias for charNode
typedef Node *NodePtr; //makes NodePtr an alias for a pointer to Node (I think?)
//function declaration for a reverse function
Node* reverse(Node *stPtr);
int main(void)
{
//main function takes 10 letters and puts them in a linked list
//after that, it calls the reverse function to create a reversed list of those characters
//lastly it prints both lists
NodePtr newNode = NULL;
char input;
Node* revStart;
unsigned int counter = 0;
printf("Enter 10 letters to make a list: ");
NodePtr currentPtr = NULL; //sets currentPointer to startNode.
NodePtr previousPtr = NULL; //set previousPointer to null to start
while(counter<= 10)
{
scanf("%c", &input); //gather next letter
NodePtr newNode = malloc(sizeof(Node)); //creates a new node
if (newNode != NULL) //checks to make sure the node was allocated correctly
{
newNode->data = input; //makes the new node's data == input
newNode->nextPtr = NULL; //makes the nextPtr of the newNode NULL
}
currentPtr = newNode; //sets currentPtr to the address of the newNode
if(previousPtr == NULL) { //first time around previousPtr == NULL
newNode->nextPtr = newNode;
previousPtr = newNode; //sets previousPtr to the address of the new node (1st time only)
} else { //afterwards, currentPtr won't be NULL
previousPtr->nextPtr = currentPtr; //last node's pointer points to the current node
previousPtr = newNode; //update previous pointer to the current node
}
++counter;
//debug
printf("\nLoop #%d\n", counter);
}
revStart = reverse(newNode);
puts("The list is: ");
while (newNode != NULL){
printf("%c --> ", newNode->data);
currentPtr = currentPtr->nextPtr;
}
puts("NULL\n");
}
//reversing the nodes
Node* reverse(Node *stPtr)
{
//make a new node
NodePtr currentPtr = stPtr->nextPtr; //get the next letter ready (this will point to #2)
NodePtr prevRevPtr = NULL; //previous reverse node pointer
Node* revStart;
for(unsigned int counter = 1; counter <= 10; ++counter)
{
NodePtr revNode = malloc(sizeof(Node));
if(revNode != NULL) //if reverseNode is allocated...
{
if(prevRevPtr = NULL) //if previousReversePointer = NULL it's the "first" letter
{
revNode->data = stPtr->data; //letter = current letter
revNode->nextPtr = NULL; //this is the "last" letter, so NULL terminate
prevRevPtr = revNode; //previousReversePointer is this one
}else //after the first loop, the previous ReversePointer will be set
{
revNode->data = currentPtr->data; //set it's data to the pointer's data
revNode->nextPtr = prevRevPtr; //reverseNode's pointer points to last node entered
currentPtr = currentPtr->nextPtr; //moves to next letter
prevRevPtr = revNode; //changes previous reverse node to current node
if(counter == 10)//on the last loop...
{
revStart = revNode; //set revStart as a pointer to the last reverse node
//which is technically the "first"
}
}
}
}
return revStart;
}
Assuming your list is properly wired from inception, reversing a double-linked list is basically this:
Node *reverse(Node *stPtr)
{
Node *lst = stPtr, *cur = stPtr;
while (cur)
{
Node *tmp = cur->nextPtr;
cur->nextPtr = cur->prevPtr;
cur->prevPtr = tmp;
lst = cur;
cur = tmp;
}
return lst;
}
That's it . All this does is walk the list, swapping pointers, and retaining whatever the last node processed was. When done correctly the list will still be end-terminated (first node 'prev' is null, last node 'next' is null, and properly wired between.
I strongly advise walking a list enumeration through this function in a debugger. With each iteration watch what happens to cur as it marches down the list, to the active node's nextPtr and prevPtr values as their swapped, and to lst, which always retains the last-node processed. It's the new list head when done.
Okay so we don't need to contend with no line breaks in commments:
Node *reverse(Node *list) {
Node *rev = NULL;
while (list) {
Node *elt = list; // pop from the list
list = list->next;
elt->next = rev; // push onto reversed list.
rev = elt;
}
return rev;
}
As you wrote in comments, you probably don't need to have a previous pointer; you can just create a singly linked list.
There are several issues in your code, including:
When malloc returns NULL, you still continue with the loop -- only part of the code is protected by the if that follows, but not the rest. You should probably just exit the program when this happens.
Your algorithm does not maintain a reference to the very first node, i.e. the place where the linked list starts. When you print the list you should start with the first node of the list, but instead you start with newNode, which is the last node you created, so obviously not much will be printed except that last node. Moreover, both other pointers you have, will also point to the last node (currentPtr, previousPtr) when the loop ends.
newNode->nextPtr = newNode; temporarily creates an infinite cycle in your list. This is resolved in the next iteration of the loop, but it is unnecessary to ever make the list cyclic.
In the reverse function you have if(prevRevPtr = NULL)... You should get a warning about that, because that is an assignment, not a comparison.
Some other remarks:
The reverse function unnecessarily makes distinction between dealing with the first node and the other nodes.
It is also not nice that it expects the list to have 10 nodes. It would be better to just rely on the fact that the last node will have a NULL for its nextPtr.
It is a common habit to call the first node of a linked list, its head. So naming your variables like that is good practice.
As you are required to print both the initial list and the reversed list, it would be good to create a function that will print a list.
As you need to create new nodes both for the initial list and for the reversed list, it would be good to create a function that will create a node for you.
(I know that your teacher asked to create only one function, but this is just best practice. If this doesn't fit the assignment, then you'll have to go with the malloc-related code duplication, which is a pitty).
As you defined the type NodePtr, it is confusing to see a mix of Node* and NodePtr in your code.
Your question was first not clear on whether the reversal of the list should be in-place or should build a new list without tampering with the initial list. From comments it became clear you needed a new list.
I probably didn't cover all problems with the code. Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
struct charNode {
char data;
struct charNode *nextPtr;
};
typedef struct charNode Node;
typedef Node *NodePtr;
NodePtr reverse(Node *stPtr);
void printList(Node *headPtr);
NodePtr createNode(int data, NodePtr nextPtr);
int main(void) {
NodePtr headPtr = NULL; // You need a pointer to the very first node
NodePtr tailPtr = NULL; // Maybe a better name for currentPtr
printf("Enter 10 letters to make a list: ");
for (int counter = 0; counter < 10; counter++) {
char input;
scanf("%c", &input);
NodePtr newNode = createNode(input, NULL);
if (headPtr == NULL) {
headPtr = newNode;
} else {
tailPtr->nextPtr = newNode;
}
tailPtr = newNode;
}
NodePtr revHeadPtr = reverse(headPtr);
puts("The list is:\n");
printList(headPtr);
puts("The reversed list is:\n");
printList(revHeadPtr);
}
void printList(NodePtr headPtr) {
while (headPtr != NULL) {
printf("%c --> ", headPtr->data);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
puts("NULL\n");
}
NodePtr createNode(int data, NodePtr nextPtr) {
NodePtr newNode = malloc(sizeof(Node));
if (newNode == NULL) { // If malloc fails, exit the program
puts("Cannot allocate memory\n");
exit(1);
}
newNode->data = data;
newNode->nextPtr = nextPtr;
return newNode;
}
NodePtr reverse(NodePtr headPtr) {
NodePtr revHeadPtr = NULL;
while (headPtr != NULL) {
revHeadPtr = createNode(headPtr->data, revHeadPtr);
// You can just move the head pointer: it is a variable local to this function
headPtr = headPtr->nextPtr;
}
return revHeadPtr;
}

Singly linked list - push_back

I have to create method push_back which will add an item to the end of my list.
But I have one constraint - I can't check if head is empty (if head is null)
I don't have idea how I can do this. Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node* next;
};
void print(struct node* head)
{
struct node* iterator = head;
while (iterator != NULL)
{
printf("%d\n", iterator->value);
iterator = iterator->next;
}
printf("\n");
}
void pushBack(struct node** head, int value)
{
struct node* element = (struct node*)malloc(sizeof(struct node));
struct node* iterator = *head;
element->value = value;
element->next = NULL;
if (iterator == NULL) //can't!
{
*head = element;
return;
}
while (iterator->next != NULL)
{
iterator = iterator->next;
}
iterator->next = element;
}
int main(void)
{
struct node* head = NULL;
pushBack(&head, 4);
pushBack(&head, 5);
pushBack(&head, 52);
pushBack(&head, 1);
print(head);
return 0;
}
Any ideas how I can get working push_back method without checking head and without empty nodes?
My teacher asked after classes, where we was discussing about linked list, if it's possible to do this - no one knew how it can be done.
I think you may have misunderstood your instructors wishes. I believe the instructor desired you not check if (head); Instead check if (*head). They're not the same condition.
In your code, head is a pointer to pointer. Though you may pedantically wish to check that someone did not pass you a null pointer to pointer, the fact is all you really care about is whether the pointer it points to is null (thus the dereference).
And that considerably reduces your code lineage.
void pushBack(struct node** head, int value)
{
while (*head)
head = &(*head)->next;
*head = malloc(sizeof(**head));
(*head)->value = value;
(*head)->next = NULL;
}
Yes of course you can do this. Thats a very good use for a pointer-to-a-pointer. You can even use pushBack() like this:
pushBack(&(element->next), 4);
if element is a pointer to the last element!
If you return the new element from pushBack, you can add new elements in constant time O(1), because you don't have to iterate through all the previous elements.
If head points to the last element in the list then you just say
newItem->next = head;
head = newItem;
of course this operations is more often called a "push". I've not heard the term push back.
This sounds like a data structures class problem. The answer should be in the reading assignments.
But anyway. I believe the answer is to use a circular linked list. What this is, is a head pointer to an empty node. The empty node marks the beginning AND end of the list. Doing it this way simplifies all of the list operations, because it completely removes the need to operate on the head pointer.

Push and append an item into a linked list in C

I have a weird problem. I have this piece of code, but it doesn't work. The weird part is that inside the function, the list is changed (printf commands indicate this), but when call this function, nothing will be added to the list (my list is not empty).
void pushToList(node* list, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = list;
list = newNode;
printf("here, list->value = %d \n", list->value);
printf("here, list->next->value = %d \n", list->next->value);
}
// ----------------------------------
// if (list==NULL) {
// newNode->next = NULL;
// list = newNode;
// } else {
// newNode->next = list;
// list = newNode;
// }
I call this function for example in my main function like this:
node* node1;
pushToList(node1, 1111);
And here is my struct and typedef in a separate header file (that I have included in my function file):
#ifndef STACKELEMENT_H
#define STACKELEMENT_H
struct stackElement {
int value;
struct stackElement* next;
};
typedef struct stackElement node;
#endif /* STACKELEMENT_H */
Another weird behavior is that I have the following function for appending an item, and this function only works if my list is not empty:
int appendtoList(node* head, int val) {
node* current = head;
node* newNode = (node*) malloc(sizeof (node));
if(newNode == NULL){
fprintf(stderr, "Unable to allocate memory for the new node\n");
exit(-1);
}
newNode->value = val;
newNode->next = NULL;
while (current->next) {
current = current->next;
}
current->next = newNode;
// if (head->next == NULL) {
// head->next = newNode;
// } else {
// while (current->next != NULL) {
// current = current->next;
// }
// current->next = newNode;
// }
//
return 0;
}
use node**list as argument type in your function.
when u pass a pointer to a function like struct node *x to
void max (struct node*p);
the pointer is passed by value AND
if u want to really manipulate the contents to which x points to use struct node** as the argument type and pass &x to the function.
Same logic should apply to your problems.
The problem was with the return type, i.e. the scope of a variable which in this case is a pointer variable. mbratch also pointed out this, thank you very much, but actually before reading mbratch's comment, I suddenly remembered a point from a lecture note about "accessing an object outside of its lifetime" which I think is different from "call by value/call by reference" problem.
Just some clarifications for people who may run into this problem and may get confused:
since we are allocating memory for the struct newNode INSIDE the function pushToList (even though using dynamic memory allocation command), the memory assigned to this variable would be free/destroyed when the function ends and the control returns back to the callee function (in this case, main()). So you should set the return type of your function to node* (a pointer to a node struct) and in your function return the head. Like this:
node* pushToList(node* head, int val) {
node* newNode = (node*) malloc(sizeof(node));
newNode->value=val;
newNode->next = head;
head = newNode;
return head;
}
In appendToList function, in addition to this mistake, as mbracth pointed out, I was doing another mistake by checking head->next (although implicitly) rather than head itself (to see if it's NULL): if head is NULL, you can not access head->next. Indeed two answers marked as the correct answers in some other posts here on stackoverflow misleaded me to this mistake. Anyway, here is the correct way:
if (head == NULL) {
head = newNode;
} else {
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}

Adding element to front of linked list in C

I'm following the Stanford CS Ed Library tutorial on Linked Lists. I am trying to add a new list to the front of my linked list, and it's not working based on the printout I get from the Length function defined below.
#include <stdio.h>
#include <stdlib.h>
//build new struct for node
//node has value and points to next node
struct node{
int value;
struct node *next;
};
//declare a new struct node that contains 3 nodes (head, middle, tail)
struct node *Build123(){
struct node *head, *middle, *tail = NULL;
head = malloc(sizeof(struct node));
middle = malloc(sizeof(struct node));
tail = malloc(sizeof(struct node));
head->value = 3;
head->next = middle;
middle->value = 5;
middle->next = tail;
tail->value = 9;
tail->next = NULL;
return head;
};
//declare a function Length and variable counter to calculate size of list
int Length(struct node *head) {
int count = 0;
struct node *iterator = head;
while (iterator != NULL) {
count++;
iterator = iterator->next;
}
return count;
}
//declare function Push to add new lists that would be added to the front
void Push (struct node **headRef, int value){
struct node *newNode;
newNode = malloc(sizeof(struct node));
newNode->value = value;
newNode->next = *headRef;
}
int main(){
//instantiate the 3 element linked list named beast
struct node *beast = Build123();
//add 2 elements to the front of the linked list via pass by reference
Push(&beast, 6);
Push(&beast, 12);
//calculate length of linked list after elements have been added
int len = Length(beast);
//print length of linked list to screen
printf("%d\n",len);
return 0;
}
I get 3, when I expect to receive 5. Would you please assist me to find the error in the code that prevents me from obtaining the value I expect? I could not figure out why despite much tinkering. Thank you!
The problem is that when you do something like Push(&beast, 6); what beast points to is unchanged by the function Push. Even though Push adds more elements to the linked list, when you call Length on beast later it calls it on the same node that beast originally had at the start - so it is completely unknowing of the extra, added nodes.
At the end of Push(), you need to do this:
*headRef = newNode;
so that beast will correctly point to the new start of the list.
You don't modify headRef in your Push function, so your list's head never actually changes. beast always stays pointing to the original node it was created to point to. Add this line:
*headRef = newNode;
In Push(), and you'll be set.
At the end of the push() method, you have to add:
*headRef = newNode
This is because headRef should always point to the first node in your linked list.

Resources