I'm having issue with an assignment for my CS class. I've been working with a friend, and we've identified that our code has a memory leak, but we can't find what the problem is. Essentially, the code is supposed to create a linked list with digits from 2-1000. Then, the code uses deletemultiples in order to delete numbers that aren't prime. It does this by taking a number and deleting any multiples of that number in the linked list. When we used valgrind, it returned a memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct node{
int info;
struct node *next;
};
typedef struct node node;
node *inserthead(node *head, int a);
node *inserttail(node *head, int a);
node *deletemultiples(node *head, int a);
void printlist(node *head);
void freelist(node *head);
int main(){
node *head1 = NULL;
int i,j;
for(i = 2;i <= 1000;i++)
head1 = inserttail(head1,i);
for(i = 2; i <= 32; i++){
head1 = deletemultiples(head1,i);
}
printlist(head1);
freelist(head1);
}
node *inserthead(node *head, int a){
node *ptr;
ptr = (node*)malloc(sizeof(node));
ptr->info = a;
ptr->next = head;
return(ptr);
}
node *inserttail(node *head, int a){
node *ptr;
node *ptr2 = head;
ptr = (node*)malloc(sizeof(node));
ptr->info = a;
ptr->next = NULL;
if(head == NULL)
return(ptr);
else if (head->next == NULL){
head->next = ptr;
return(head);
}
while(head->next != NULL)
head = head->next;
head->next = ptr;
return(ptr2);
}
void printlist(node *head){
while(head!=NULL){
printf("%i ",head->info);
head = head->next;
}
printf("\n");
}
void freelist(node *head){
node *ptr = head;
while(head != NULL){
head = head->next;
free(ptr);
ptr = head;
}
}
node *deletemultiples(node *head, int a){
node *ptr = head, *temp = head;
while (ptr != NULL) {
if(ptr->info % a > 0){
ptr = ptr->next;
temp = temp->next;
}
else{
ptr = ptr->next;
temp->next = ptr;
}
}
return(head);
}
If anyone can help us figure out what we did wrong, it would be greatly appreciated!
Your deletemultiples() function never frees the nodes it unlinks, so freelist() never reaches them when it walks the list to delete it. Delete the nodes you remove the same way you did in freelist().
Alternatively, you could create an array of 1,000 nodes (It’s a good habit to turn constants like that into symbolic names.) and link and unlink nodes within that array as weak references. You would free the entire array in a single call when you destroy all lists that depend on it.
Kudos for looking for memory leaks in your code. It’ll save you a lot of grief.
Related
This question already has answers here:
Linked lists - single or double pointer to the head
(3 answers)
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 10 months ago.
#include<stdio.h>
#include<stdlib.h>
void insert_front(struct node* head, int block_number);
void insert_rear(struct node* head, int block_number);
void print_list(struct node* head);
struct node {
int block_number;
struct node* next;
};
int main(void)
{
struct node* list = NULL;
insert_front(list, 10);
insert_rear(list, 20);
insert_front(list, 30);
insert_rear(list, 40);
print_list(list);
return 0;
}
void insert_front(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
void insert_rear(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL) {
head = p;
}
else {
struct node* q = head;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
}
}
void print_list(struct node* head)
{
struct node* p = head;
while (p != NULL) {
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
When I ran it, there was no result at all.
Now, in the insert_front function p->block_number = block_number, a message appears saying that the NULL pointer 'p' is being dereferenced... (The same thing appears in the insert_rear function.)
Could it be that I am declaring the pointer wrong?
Both insert_front and insert_rear need to convey possibly head modification back to the caller, and the caller needs to reap that information. Both should be declared to return struct node *, do so, and the code in main react accordingly. E.g.:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
struct node * insert_front(struct node *head, int block_number);
struct node * insert_rear(struct node *head, int block_number);
void print_list(struct node *head);
struct node
{
int block_number;
struct node *next;
};
int main(void)
{
struct node *list = NULL;
list = insert_front(list, 10);
list = insert_rear(list, 20);
list = insert_front(list, 30);
list = insert_rear(list, 40);
print_list(list);
return 0;
}
struct node *insert_front(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
struct node *insert_rear(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL)
{
head = p;
}
else
{
struct node *q = head;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
}
return head;
}
void print_list(struct node *head)
{
struct node *p = head;
while (p != NULL)
{
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
Output
--> 30 --> 10 --> 20 --> 40
I leave the memory leaks for you to resolve.
In C all variables are passed by value – if you pass a pointer, then it is copied, too (not the pointed to object, of course...), and function parameters, apart from being initialised from outside, are nothing more than local variables. Thus via head = p; you just assign the local copy of the outside pointer, not the latter itself!
To fix that you have two options:
Return the new head and make the user responsible for re-assigning the returned value to his own head pointer.
Accept the head as pointer to pointer.
With second approach a user cannot forget to re-assign the (potentially) new head, so that's what I'd go with:
void insert_whichEver(node** head, int block_number)
{
// use `*head` where you had `head` before...
}
void demo()
{
node* head = NULL;
insert_front(&head, 1012);
}
And in insert_front drop return head;, a function with void cannot return anything concrete and does not require a return at all (but bare return; can be used to exit a function prematurely).
I am making a linked list program which utilizes several functions to simplify adding or removing nodes from the list. I believe that my logic is alright with allocating and adding a new node but I am still getting a seg fault. Could you look over my logic and explain what is causing the seg fault? I am very inexperienced with linked lists. Thank you!
This is my function declarations
#define SIMPLELL_H
#include<stdio.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
}node_t;
node_t* head;
void printList();
void append(int num);
void addFront(int num);
void deleteList();
void removeNode(int num);
int length();
#endif
This is the function definitions
void printList(){
// declare temp to traverse the LL and print each value
node_t *temporary = head;
while(temporary != NULL){
printf("%d, ", temporary->data);
temporary = temporary->next;
}
if (head == NULL){
printf("This list is empty.\n");
}
}
void append(int num){
//declare temporary pointer to traverse LL
node_t *tmp = head;
node_t *prev = NULL;
//malloc the new node
node_t *new = malloc(sizeof(node_t));
if(head == NULL){
//initialize the new node
new->data = num;
new->next = NULL;
head->next = new;
}
else{
//initialize the new node
new->data = num;
new->next = NULL;
//loop to traverse to the last value in the node
while(tmp != NULL){
prev = tmp;
tmp = tmp->next;
}
prev->next = new;
}
}
void addFront(int num){
//allocate memory for new node and allocate local variable equal to head
node_t *new = malloc(sizeof(node_t));
new->data = num;
new->next = head;
head = new;
}
void deleteList(){
node_t *tmp = head;
node_t *prev = NULL;
while(tmp != NULL){
prev = tmp;
tmp = tmp->next
free(prev);
}
}
void removeNode(int num){
//temp is used to traverse the ll until I find the node with the value
//then the previous value is linked to the next value removing the middle value.
node_t *temp = head;
node_t *prev = NULL;
if(head == NULL){
printf("List is not initialized\n");
return;
}
while(temp->data != num){
prev = temp;
temp = temp->next;
if (temp->data == num){
prev->next = temp->next;
free(prev);
}
else{
printf("Value is not in the list\n");
return;
}
}
int length(){
int length = 0;
node_t *temp = head;
while (temp != NULL){
length += 1;
temp = temp->next;
}
return length;
}
This is the driver function which I should not have to change
#include "SimpleLL.h"
#include "SimpleLL.c"
int main()
{
/*head is a global variable*/
head = NULL;
int size =0;
removeNode(1);
append(2);
append(3);
addFront(1);
append(4);
printList();
size = length();
printf("size now %d\n",size);
removeNode(8);
printList();
removeNode(1);
printList();
removeNode(4);
printList();
deleteList();
printList();
size = length();
printf("size after deletion %d\n",size);
return 0;
}
removeNode contains no test for reaching the end of the list. So if the value is not found in the list, it will dereference the NULL pointer at the end and crash.
This will be the case in the very first test, which attempts to remove a node when the list is empty, as well as for removeNode(8).
Your removeNode function also needs to free() the node it removed. Currently it is freeing the node that came after the one removed, which is still in the list and will cause undefined behavior when you access it later.
I am trying to populate my linked list in C, but id does not word how
I want to. I want to keep a pointer "p" and keep adding to the list with the same pointer. However when I try to print, it prints only the data of the head!
#include<stdio.h>
#include <stdlib.h>
typedef struct{
int data;
struct node *next;
}node;
int main(){
node *head = NULL;
head = malloc(sizeof(node));
if(head==NULL){
printf("ta foirer quelque chose frero!");
return 1;
}
(*head).data=3;
(*head).next=NULL;
node *p = NULL;
p = (node*) head->next;
p = malloc(sizeof(node));
p->data = 5;
p->next = NULL;
p= (node *)p->next;
int i=0;
while(i<5){
p = malloc(sizeof(node));
i++;
p->data = i;
p->next=NULL;
p= (node *)p->next;
}
p = head;
while(p){
printf("\n%d",p->data);
p =(node*) p->next;
}
return 0;
}
I am getting as output
3
and I am expecting to get
3
5
0
1
2
3
4
#include<stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
};
typedef struct Node node;
void insert(node* h, int v) {
node* tmp = h;
while(tmp->next)
tmp = tmp->next;
node* newnode = malloc(sizeof(node));
newnode->data = v;
newnode->next = NULL;
tmp->next = newnode;
}
int main(){
node *head = NULL;
head = malloc(sizeof(node));
if(head==NULL){
printf("ta foirer quelque chose frero!");
return 1;
}
head->data=3;
head->next = NULL;
node *p = NULL;
insert(head, 5);
int i=0;
while(i<5){
insert(head, i++);
}
p = head;
while(p){
printf("%d\n",p->data);
p = p->next;
}
return 0;
}
If you notice, I changed the layout of your code a bit, and made it cleaner. What you needed was to traverse to find the node that appears before the place to add the new node, which in this case is the end. Usually this is a separate pointer in a different struct that contains the head and this is called the tail of a linked list. You were simply not keeping track of where to really add the node. This insert function above does that.
Using the delete_SLL function I want to delete the head of this singly linked list(head = 4). Although I get the correct output, the var struct Node* "temp" holding the value of the head isn't NULL. What is it about the variable "temp" that the free function not like? Is the node temp not Malloc-ed when setting it equal to the list head?
Source:Deleting a Node
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int item;
struct Node* next;
};
struct List{
struct Node* head;
struct Node* tail;
};
int SLL_empty(struct List* lst){
return lst->head == NULL ;
}
//newLst work
struct List newLst(){
struct List lst;
lst.head = NULL;
lst.tail = NULL;
return lst;
}
//Inserts a node to the front of the list[WORKS]
void insert_SLL(struct List* lst, int x){
struct Node* nde = (struct Node*)malloc(sizeof(struct Node));
nde->next = lst->head;
nde->item = x;
if (SLL_empty(lst))
lst->tail=nde;
lst->head = nde;
}
//Deletes a given Node
void delete_SLL(struct List* lst, int x){
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));;
temp = lst->head;
struct Node* prev = NULL;`enter code here`
//If the head has the key
if (temp != NULL && temp->item == x){
lst->head = temp->next;
temp->next = NULL;
free(temp);
}
// stops once the key is found
while(temp != NULL && temp->item != x){
prev = temp;
temp= temp->next;
}
//If not in list
if (temp == NULL) return;
//If middle
if (temp != NULL && temp->item == x){
prev->next = temp->next;
temp->next = NULL;
}
//if at the end
if (temp != NULL && temp->item == lst->tail->item){
lst->tail= prev;
prev->next = NULL;
}
free(temp);
}
int SLL_pop(struct List *list){
struct Node* nde = list->head;
int item = nde->item;
list->head = nde->next;
free(nde);
if (SLL_empty(list))
list->tail = NULL;
return item;
}
int main(int argc, const char * argv[]) {
int i;
struct List list = newLst();
for (i = 0; i < 5; ++i)
insert_SLL(&list, i);
// printf("The length of the linkedLst is: %d\n",SLL_length(&list));
delete_SLL(&list, 4);
while ( list.head != NULL )
printf("Node: %d\n", SLL_pop(&list));
return 0;
}
The main purpose of free() is to ask the OS take the allocated memory back to the system. You might not be able to "see" that but if you try to access any element at the "temp" afterward, you should get an error.
While the "temp" in the program is only a variable. C doesn't require to, and can't change the given pointer to NULL due to pass-by-value sense. It's the programmer's work to remember that this pointer is no longer valid.
Or you can set it to NULL manually each time you free a pointer.
I have written following code in C. I am pretty new to C. The insert and Print functions seem to work fine but I get a prompt that says program stopped working when I call Reverse function.
Where dis I go wrong ?
//WAP to reverse a Linked List using recursion
#include<stdio.h>
#include<stdlib.h>
struct Node{
int data;
struct Node* next;
};
struct Node* head; //global variable
struct Node* Reverse(struct Node* p){
if(p->next == NULL){ //since for last node link part is null
head = p;
printf("break condition");
return head;
}
printf("calling reverse");
Reverse(p->next);
struct Node* q = p->next;
q->next = p;
p->next = NULL;
}
void Insert(int x){
struct Node* temp= (struct Node*)malloc(sizeof(struct Node));
temp->data = x;
//temp->next = NULL; //redundant
//if(head!= NULL){
temp->next = head; //temp.next will point to null when head is null nd otherwise what head was pointing to
//}
head = temp;
}
void Print(){
struct Node* temp1 = head; //we dont want tomodify head so store it in atemp. bariable and then traverse
while(temp1 != NULL){
printf(" %d", temp1->data);
temp1= temp1->next;
}
printf("\n");
}
int main(){
struct Node* head = NULL;
Insert(2);
Insert(4);
Insert(5);
Insert(1);
Print();
head = Reverse(head);
// Print();
}
There are two issues with the program above:
1) You have two head variables. One is a global variable, and the other is a variable local to the main function. That local variable is the one that is passed to Reverse(). Since the first thing that function does is dereferencing it, the program crashes. Removing the local head variable in the main() function should address it.
2) The Reverse() function correctly returns head when it reaches the exit condition, but what happens the rest of the time? It's missing a return in the non-exit condition case. Here's a diff that would address the issue:
printf("calling reverse");
- Reverse(p->next);
+ struct Node* ret;
+ ret = Reverse(p->next);
struct Node* q = p->next;
q->next = p;
p->next = NULL;
+ return ret;