How can I print the values in my linked list? - c

I have, for a large portion of the day, been trying to write a simple program with linked lists. My main issue seems to be not understanding why the memory I am accessing is not what I think it is. I am printf crazy and outputting every possible form of data I can and still am having trouble understanding why it will not work.
For example when I pass the &head to a function which takes node **location and I want to check whether the value inside location (and therefore head) is NULL or not, should I use if(!*location) return; or should I use if(!location) return;, It seems the later is correct, but why?
And when I want to create a node *current inside a function to keep track of things, should I start with node* current = *head or node* current = head, and most importantly, why? I have noticed that the later is better, but I cannot make sense of it still. Warnings go away when I typecast the statements, but it seems to fix nothing.
Here is some functions I have been writing, can you please give me hints on where I am not making sense in the code. Preferably, I hope to understand why the output seems to be a memory location and then accessing bad memory.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_struct
{
int val;
struct node *next;
} node;
node* return_create_neck(node **head, int value)
{
node* ptr;
*head = ptr = (node *)malloc(sizeof(node));
(*head)->val = value;
(*head)->next = NULL;
return ptr;
}
node* return_append_tail(node **location, int value)
{
node* ptr;
*location = ptr = (node *)malloc(sizeof(node));
(*location)->val = value;
(*location)->next = NULL;
return ptr;
}
void print_linked_list(node **head)
{
if(!head)
return;
node *current = head;
while(current)
{
printf("%d ", current->val);
current = current->next;
}
printf("\n");
return;
}
int main(void)
{
node *head=NULL, *current=NULL;
int i=0;
for( current = return_create_neck(&head, 1);
i < 4;
current = return_append_tail(&current, i+1))
{ ++i; }
printf("Pritning...\n");
print_linked_list(&head);
return 0;
}

Your return_append_tail function doesn't actually append anything, unless called with the correct location, which you do not.
You should call it with &current->next from the main function.

Related

Any idea why I’m losing links?

I have started to learn about linked lists, and I have written this code.
It should be a recursive call to create a new link in a linked list in c.
But, if you’ll check the output, you’ll see it’s passing over the middle links.
I don’t know why I’m losing the middle links.
Btw, I do have a destroy function in my code, I just didn’t write it here.
I do have a different version of a working code, I don’t ask for solutions, I’m only asking why this recursive idea doesn’t work.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct node {
int data;
struct node *next;
}node;
node *create(node **head, int data)
{
if(!*head) {
*head = malloc(sizeof(node));
assert(*head);
(*head)->data = data;
(*head)->next = NULL;
return *head;
}
node *new = NULL;
new = create(&new,data);
(*head)->next = new;
return *head;
}
void display(node *head)
{
assert(head);
node *current = head;
do
{
printf("%d\t",current->data);
current = current->next;
}while(current);
}
int main()
{
int count = 0, data = 0;
node *head = NULL;
printf("Enter list count:\n");
while(count <= 0){
scanf("%d",&count);
if(count <= 0) printf("\nEnter a valid number:\n");
}
while(count){
scanf("%d",&data);
head = create(&head,data);
count--;
}
printf("\nHere are the elements:\n");
display(head);
return 0;
}
As implemented create() either adds a new node to the tail or iterates to the next linked node. Logic changed to affect that. It's confusing that the first argument is called head to changed it to n. Changed main() to retain the head and made the program non-interactive for ease of testing. Recatored display to use a for() loop:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int data;
struct node *next;
} node;
node *create(node **n, int data) {
if(!*n) {
*n = malloc(sizeof(**n));
assert(*n);
(*n)->data = data;
(*n)->next = NULL;
return *n;
}
node *n2 = (*n)->next;
(*n)->next = create(&n2, data);
return n2;
}
void display(node *head) {
assert(head);
for(node *c = head; c; c = c->next) {
printf("%d\t", c->data);
}
}
int main() {
node *head = NULL;
node *tail = NULL;
for(int i = 0; i < 10; i++) {
tail = create(&tail, i);
if(!head) head = tail;
}
display(head);
return 0;
}
and it displays:
0 1 2 3 4 5 6 7 8 9
If you compile your code with NDEBUG (some folks do that for production) then your code no longer has any error handling.
Thank you all for your answers. I see the problem now, after “explaining to the duck” a thousand times. In function create(), under the if() block, I assigned (*head)->next = new; without first making it point to the last link, so it’s just over write the next link in every call to the function.
The solution is:
Add a “current” pointer points to the head(to not lose it’s value)
Iterate through the list until we find the last link,
assign current->next the value of new.
Here is the fixed section:
node *new = NULL;
new = create(&new,data);
node *current = *head;
while(current->next) current = current->next;
current->next = new;
return *head;

how to print the entire linked list?

I am working on creating a linked list program in C. I am having trouble displaying the entire list. All I can get to display is the first and last elements. Not sure what is going on. I have tried changing the links to every different way I can think of, and none of them will quite work. I am pretty sure this is just a simple mistake I am making somewhere. I would appreciate any help and suggestions.
Here is the code
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
}
*start = NULL;
void display();
void create ();
int main(void)
{
int numberOfElements = 0;
printf("How many elements do you want to enter?\n");
scanf("%d",&numberOfElements);
for (int i = 0; i < numberOfElements; ++i){
printf("Please enter data for element number %d\n", i+1);
createList();
}
display();
return 0;
}
void display(){
struct node *tempNode;
printf("Now displaying the list\n");
tempNode = start;
while (tempNode != NULL){
printf("%d---> ",tempNode->data);
tempNode = tempNode->next;
}
printf("NULL\n");
}
void createList(){
struct node *newNode, *current;
newNode = (struct node *)malloc(1 * sizeof (struct node));
//printf("Please enter the data for each element\n");
scanf("%d", &newNode ->data);
// For testing
printf("You entered %d\n",newNode->data);
newNode->next = NULL;
if(start == NULL){
start = newNode;
current = newNode;
}
else {
current->next = newNode;
current = newNode;
}
}
So when the user enters some data, say two elements, of 22 and 28, the display should be 22--->28--->NULL instead what is displayed is 22--->NULL
Thank you
Your code expects/requires that the variable current in createList maintain its value between calls of the function. By default it doesn't work that way in C. The value of variables inside a function doesn't keep their value from call to call.
If you want a variable in a function to behave that way, you need to use the keyword static.
So if you change:
struct node *newNode, *current;
to
struct node *newNode;
static struct node *current;
the variable current will keep its value between calls and your code will (probably) work.
In more technical terms you should read about "automatic storage duration" and "static storage duration".
That said, it's not a good idea to do something like that - in fact, it's a rather bad idea. Also it's a bad idea to have start as a global variable.
Instead you should define two variables in main- for instance head and tail - and pass these (or their address) to the insert-function.
Something like:
int main(void)
{
struct node* head = NULL;
struct node* tail = NULL;
createList(&head, &tail);
createList(&head, &tail);
createList(&head, &tail);
display(head);
return 0;
}
void createList(struct node* pHead, struct node* pTail)
{
// malloc and initialize new node
if (*pHead == NULL)
{
*pHead = newNode;
*pTail = newNode;
return;
}
(*pTail)->next = newNode;
*pTail = newNode;
}
The reason is, current is locally scoped in your CreateList function, though you're persisting the current node in the current, when CreateList exits, current is vanished, during another call of the CreateList, current knows nothing from previous execution, as it's created as brand-new variable for this particular invocation of the function. But you're persisting the value only for first node as start is globally scoped, it exists unless your program finishes execution.
So, make current global variable, that fixes the bug:
Look at this: https://ideone.com/yWQLDL

Is this a proper implementation of a DeleteList function? [LINKED LIST via heaps]

I must write a function DeleteList() that takes a list, deallocates all of its memory and sets its head pointer to NULL (the empty list).
It seems to work, but idk if it truly works because the way in which I implemented (which I assume is the wrong way) is very different than the one in the solution. I assume it only deletes a few nodes or there is an issue with the memory management.
int Length(struct node* head)
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
void DeleteList(struct node** headRef)
{
int len = Length(*headRef);
for(int i = 0;i<len;i++)
free(*headRef);
*headRef = NULL;
}
You are not actually freeing the whole linked list but you are freeing head node repeatedly. I would suggest you to use below approach.
void DeleteList(struct node** headRef) {
struct node *ptr = *headRef;
struct node *temp = NULL;
while(ptr)
{
temp = ptr;
ptr = ptr->next;
free(temp);
}
*headRef = NULL;
}

Inject function in doubly linked list arbitrarily points back to head element after call to pop()

EDIT: I think my question is completely different from the proposed duplicate. It's asking about the general case whereas my question is asking for a very specific case where the reason for the weird behavior should be traceable given how specific it is.
I have some really weird behavior in my doubly LL implementation.
Basically, if I pop() (from the head) an element and then inject() (add at the tail) some other element, that last tail element now points to the head of the list for seemingly no reason (I guess instead of NULL by default or at least a random address).
I figured out how to fix the problem. When injecting, I wasn't pointing the new node's "next" to NULL.
However, I would still like to understand why the injected node would choose to point to the head without specific direction of where to point.
The effect is that if I travel the list starting from the head (but not starting from the tail), I keep looping forever as the last tail element points back to the head of the list.
EDIT: So I tried printing out the address that the pointer is pointing to just after the call to malloc in inject(), and for some crazy reason the pointer is created already pointing to the head's address; but this only happens if I call pop() before calling inject(). Incredibly weird...
int pop()
{
node* temp = head;
int value = temp->value;
head = temp->next;
free(temp);
head->previous = NULL;
size--;
return value;
}
void inject(int value)
{
if (tail == NULL)
{
tail = malloc(sizeof(node));
tail->value = value;
tail->next = NULL;
tail->previous = NULL;
head = tail;
size++;
}
else
{
node* new_node = malloc(sizeof(node));
printf("pointing to: %p\n", new_node->next);// points to head after pop() call
new_node->value = value;
tail->next = new_node;
new_node->previous = tail;
tail = new_node;
//new_node->next = NULL;
size++;
}
}
The commented out line in inject() solves the problem but still doesn't explain why the tail would point back to the head if I inject after a pop.
Below is the code before main() in case:
typedef struct node{
int value;
struct node* next;
struct node* previous;
}node;
node* head = NULL;
node* tail = NULL;
int head_value();
int tail_value();
void push(int);
int pop();
void inject(int);
int eject();
int size = 0;
node* new_node = malloc(sizeof(node));
printf("pointing to: %p\n", new_node->next);// points to head after pop() call
new_node->next will contain whatever garbage malloc wants to put in there. It might happen to point to head, but you never initialized it, so that printf is trying to find meaning in garbage.
Your code scatters memory management all over the place. Rather than try to fix it, let's rewrite it using my stock advice about structs: always write functions to initialize and destroy them. Always, even if it seems silly and trivial. It avoids scattering that code all over the place, doing it slightly differently every time. It allows you to unit test the basic functions of the struct before trying to use it.It lets you focus on the algorithm, not the memory management.
First, let's make a tweak to your struct. node is a very bad name for a type. It's likely you (or somebody else) is going to want to call a variable node and cause a conflict. I've called it Node, capitalized to avoid confusion with variables and builtins.
typedef struct Node {
int value;
struct Node* next;
struct Node* previous;
} Node;
Now we can write Node_new and Node_destroy.
Node *Node_new() {
Node *node = malloc(sizeof(Node));
node->value = 0;
node->next = NULL;
node->previous = NULL;
return node;
}
void Node_destroy( Node *node ) {
free(node);
}
Node_destroy might seem silly, but it frees you (or anyone else) from having to remember how to destroy a Node. And it lets you change the internal structure of Node without changing the rest of the code (which happened while writing this).
You're using globals. Globals make everything more complicated and restrict what you can do with the code. Instead, wrap things like head, tail, and size into its own structure and pass that around.
typedef struct {
Node *head;
Node *tail;
size_t size;
} LinkedList;
And it needs its own create and destroy functions.
LinkedList *LinkedList_new() {
LinkedList *list = malloc(sizeof(LinkedList));
list->head = NULL;
list->tail = NULL;
list->size = 0;
return list;
}
void LinkedList_destroy( LinkedList *list ) {
for( Node *node = list->head; node != NULL; node = node->next ) {
Node_destroy(list->head);
}
free(list);
}
Note that LinkedList_destroy takes responsibility for cleaning up all its nodes, its one less thing for the user of LinkedList to worry about and potentially screw up.
LinkedList_destroy can call Node_destroy without knowing anything about how Node works. This is how we immediately benefit from the encapsulation and abstraction of Node. But don't use recursion, the list can be arbitrarily long and recursion risks a stack overflow.
Now we can write push and pop assured that things are properly created and destroyed. Note that they take a LinkedList rather than using globals.
void LinkedList_push(LinkedList *list, int value)
{
Node *node = Node_new();
node->value = value;
switch( list->size ) {
/* The list is empty, this is the first node */
case 0:
list->head = list->tail = node;
break;
default:
list->tail->next = node;
node->previous = list->tail;
list->tail = node;
break;
}
list->size++;
}
int LinkedList_pop( LinkedList *list ) {
Node *popped = list->tail;
switch( list->size ) {
/* The list is empty, nothing to pop */
case 0:
fprintf(stderr, "LinkedList was empty when popped.\n");
exit(1);
break;
/* Popped the last node */
case 1:
list->head = list->tail = NULL;
break;
/* Only one node left, it's both the head and tail */
case 2:
list->tail = list->head;
list->tail->previous = list->tail->next = NULL;
break;
default:
list->tail = popped->previous;
list->tail->next = NULL;
break;
}
/* Have to do this at the end because size_t is unsigned
it can't go negative */
list->size--;
int value = popped->value;
Node_destroy(popped);
return value;
}
I've used a switch so I can clearly demarcate all the special cases.
I'm not saying this is the best implementation of push and pop, or that it's even bug free, but they can be written without worrying about whether the structs have been properly initialized or freed. You can focus on the logic, not the memory management.
And then to demonstrate it all works...
void LinkedList_print( LinkedList *list ) {
for( Node *node = list->head; node != NULL; node = node->next) {
printf("%d\n", node->value);
}
}
int main() {
LinkedList *list = LinkedList_new();
for( int i = 0; i < 3; i++ ) {
LinkedList_push(list, i);
}
while( list->size != 0 ) {
printf("list->size: %zu\n", list->size);
LinkedList_print(list);
LinkedList_pop(list);
}
LinkedList_destroy(list);
}
$ ./test
list->size: 3
0
1
2
list->size: 2
0
1
list->size: 1
0

Managing Linked List Memory

Recently I have been using C a lot (I normally use higher level languages) and have been running into a problem when managing lists.
Specifically, adding nodes to a linked list. I often end up writing something similar to the sample code below. As far as I can see, it should all work fine however no new nodes are appended to the list.
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
struct ListNode* next;
int data;
} ListNode;
ListNode* createListNode(int data){
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = data;
node->next = NULL;
return node;
}
void addListNode(ListNode* list, ListNode* newListNode){
ListNode* current;
if(list == NULL){
list = newListNode;
}else{
current = list;
while (current->next != NULL) {
current = current->next;
}
current->next = newListNode;
}
}
int main(void) {
int ii;
ListNode* list = NULL;
ListNode* newListNode = NULL;
int fakeData[3] = {1, 2, 3};
for(ii=0; ii<=2; ii++){
newListNode = createListNode(fakeData[ii]);
addListNode(list, newListNode);
}
printf("%d", list->data);
printf("%d", list->next->data);
printf("%d", list->next->next->data);
return 0;
}
When stepping through the code with a debugger, addListNode works as expected in a local context however, when returning to main the changes are lost and list is still equal to NULL. But list is defined in main so it should be in scope and available until that function ends. Right?
If I make a small change to main like this.
for(ii=0; ii<=2; ii++){
if(ii==0){
list = createListNode(fakeData[ii]);
}else{
newListNode = createListNode(fakeData[ii]);
addListNode(list, newListNode);
}
}
It works fine. Why would that be?
I could do it like this, but I don't want to have linked list specific code floating everywhere.
Clearly, I'm missing something quite fundamental.
void addListNode(ListNode* list, ListNode* newListNode)
This should be ListNode **list, otherwise the function really won't change it's value.
The list = newListNode; command won't have any effect outside the function.
Use ListNode **list, and when you want to change the value just say *list = newListNode;

Resources