Why am I getting a segmentation fault when I try to run mergesort on my C++ linked list? (SEGFAULT) - c++

I am implementing a linked list with a merge sort function for a class project. My program compiles, but when I try to run it I get segmentation fault(core dumped). I debugged my program using GDB, and found that the segfault happens with the pointer frontRef and backRef in my listSplit() function (line 98 in the code below).
Can someone please help me? For the life of me I can't figure out why I am getting a segfault. I would greatly appreciate help with this.
#include "orderedList.h"
orderedList::orderedList() {
listLength = 0;
traversalCount = 0;
head = nullptr;
tail = nullptr;
}
void orderedList::add(int n) {
listLength++;
struct node* point = new node;
point->value = n;
point->next = nullptr;
if (head == nullptr) {
head = point;
tail = point;
}
else {
point->next = head;
head = point;
}
}
void orderedList::merge(struct node** headRef) {
struct node *listHead = *headRef;
struct node *a;
struct node *b;
if ((listHead == nullptr) || (listHead->next == nullptr)) {
return;
}
listSplit(listHead, &a, &b);
merge(&a);
merge(&b);
*headRef = sortedMerge(a, b);
}
orderedList::node* orderedList::sortedMerge(struct node* a, struct node *b)
{
struct node* result = nullptr;
if (a == nullptr) {
return (b);
}
if (b == nullptr) {
return (a);
}
if (a->value <= b->value) {
result = a;
result->next = sortedMerge(a->next, b);
}
else {
result = b;
result->next = sortedMerge(a, b->next);
}
return (result);
}
void orderedList::print() {
struct node* temp = head;
while (temp != nullptr) {
std::cout << temp->value << " ";
temp = temp->next;
}
delete(temp);
}
int orderedList::search(int key) {
int traversals = 1;
struct node* current = head;
struct node* previous = nullptr;
while (current != nullptr) {
if (current->value == key) {
if (previous != nullptr) {
previous->next = current->next;
current->next = head;
head = current;
return traversals;
}
}
previous = current;
current = current->next;
traversals ++;
}
return 1;
}
void orderedList::listSplit(struct node* source, struct node** frontRef, struct node** backRef) { // <--- Line 98
struct node* current = source;
int hopCount = ((listLength - 1) / 2);
for (int i = 0; i < hopCount; i++) {
current = current->next;
}
*frontRef = source;
*backRef = current->next;
current->next = nullptr;
}

You made *backRef point to current->next and then you let current->next = nullptr. This makes *backRef pointing to a nullptr. Did you later try to do something with the returned backRef, aka a node variable in your caller code?

Related

What could cause a Cyclical Linked List [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed yesterday.
Improve this question
I am trying to make a quicksort algorithm for singly-linked lists. I, however, must be somehow creating a cyclical list in the process. In the concatenate function, the while loop gets stuck printing out 2 and 22 continuously. So, I assume that I must somehow be creating a list where Node 2 points to Node 22 and vice versa. Unfortunately, I have no idea how, since I feel like I have added nullptr to the end of every list where it would matter. I have reviewed my partition function so many times I add more bugs than I fix. Is there something I am missing with how linked lists work?
I have been stuck on this for a while so any help would be greatly appreciated.
Here is my quicksort code.
// quick.cpp
#include "volsort.h"
#include <iostream>
#include <string>
using namespace std;
// Prototypes
Node *qsort(Node *head, bool numeric);
void partition(Node *head, Node *pivot, Node *&left, Node *&right, bool numeric);
Node *concatenate(Node *left, Node *right);
// Implementations
void quick_sort(List &l, bool numeric) {
l.head = qsort(l.head, numeric);
}
Node *qsort(Node *head, bool numeric) {
if (head == nullptr || head->next == nullptr) {
return head;
}
Node *l = nullptr;
Node *r = nullptr;
partition(head, head, l, r, numeric);
l = qsort(l, numeric);
r = qsort(r, numeric);
head = concatenate(l, head);
head = concatenate(head, r);
return head;
}
void partition(Node *head, Node *pivot, Node *&left, Node *&right, bool numeric) {
Node *cur = pivot->next;
bool c;
Node *tl=nullptr, *tr=nullptr;
while (cur != pivot && cur != nullptr) {
if (numeric) {
c = node_number_compare(cur, pivot);//compare numeric elements of the Nodes
}
else {
c = node_string_compare(cur, pivot);//compare string elements of the code
}
if (c) {
if (left == nullptr) {
left = cur;
cur = cur->next;
tl = left;
}
else {
tl->next = cur;
cur = cur->next;
tl = tl->next;
tl->next = nullptr;
}
}
else {
if (right == nullptr) {
right = cur;
cur = cur->next;
tr = right;
}
else {
tr->next = cur;
cur = cur->next;
tr = tr->next;
tr->next = nullptr;
}
}
}
}
Node *concatenate(Node *left, Node *right) {
if (right == nullptr && left == nullptr) {
return nullptr;
}
else if (left == nullptr) {
right->next = nullptr;
return right;
}
else if (right == nullptr) {
left->next = nullptr;
return left;
}
Node *t = left;
while (t->next != nullptr) {
cout << t->number << endl;
t = t->next;
}
t->next = right;
while (t->next != nullptr) {
cout << t->number << endl;
t = t->next;
}
t->next = nullptr;
return left;
}
Input:
45
4
9
22
2
Here's the list class functions if it helps.
#include "volsort.h"
#include <string>
#include <iostream>
List::List() {
head = NULL;
size = 0;
}
List::~List() {
if (head != NULL) { // follow the links, destroying as we go
Node *p = head;
while (p != NULL) {
Node *next = p->next; // retrieve this node's "next" before destroy it
delete p;
p = next;
}
}
}
bool node_number_compare(const Node *a, const Node *b) {
if (a->number <= b-> number) {
return true;
}
else {
return false;
}
}
bool node_string_compare(const Node *a, const Node *b) {
return a->string <= b->string;
}
void List::push_front(const std::string &s) {
Node *node = new Node();
node->next = NULL;
node->string = s;
node->number = std::stoi(s);
if (head == NULL) {
head = node;
size = 1;
}
else {
Node *p = head;
while (p->next != NULL) {p = p->next;} // go to end of list
p->next = node;
size++;
}
}
void List::dump_node(Node *n) {
while (n->next != NULL) {
std::cout << n->number << " " << n->string << std::endl;
}
}

Not showing any output

I am facing a problem while coding Linked List implementation in c++. Whenever I am trying to add an element he following code doesn't show any output. What's wrong with the code
#include<iostream>
using namespace std;
struct Node {
int data;
struct Node* ptr;
Node(int val) {
data = val;
ptr = NULL;
}
};
void addItem(struct Node* head, int val) {
struct Node* n = new Node(val);
if(head == NULL){
head = n;
return;
}
struct Node* cur = head;
while(cur->ptr != NULL){
cur = cur->ptr;
}
cur->ptr = n;
}
void printList(struct Node* head) {
struct Node* cur = head;
while(cur != NULL) {
cout << cur->data << " ";
cur = cur->ptr;
}
}
int main() {
struct Node* head = NULL;
addItem(head, 1);
addItem(head, 2);
addItem(head, 3);
addItem(head, 4);
printList(head);
return 0;
}
When I run the program it shows nothing on the terminal.
Output:
[Running] cd "c:\Users\Sonu\" && g++ LinkedList.cpp -o LinkedList && "c:\Users\Sonu\"LinkedList
[Done] exited with code=0 in 3.436 seconds
You should pass head by double pointer or by reference. Otherwise it will be just a copy on function argument which will get destroyed when coming out of the function.
void addItem(Node** head, int val) {
Node* n = new Node(val);
if(*head == NULL){
*head = n;
return;
}
Node* cur = *head;
while(cur->ptr != NULL){
cur = cur->ptr;
}
cur->ptr = n;
}
// ...
addItem(&head, 1); // take the address with &
or
void addItem(Node*& head, int val) {
Node* n = new Node(val);
if(head == NULL){
head = n;
return;
}
Node* cur = head;
while(cur->ptr != NULL){
cur = cur->ptr;
}
cur->ptr = n;
}
// ...
addItem(head, 1); // no change needed

Memory leak in linked list class

If I run this in visual studio it tells me there are memory leaks, but I don't see anything wrong with my destructor. What did I do wrong? Is it because the memory leak function is being called before the destructor? Am I not supposed to call the memory leak function at the end?
I already posted this on codereview and they said it work fine, but I hadn't included a destructor then. I added one now but I'm not sure if it's actually working.
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
struct node {
int key;
struct node *next;
};
class linked_list {
private:
struct node *head;
struct node *tail;
public:
linked_list() {
head = nullptr;
tail = nullptr;
}
void create(int key) {
struct node *temp;
temp = new struct node;
temp->key = key;
temp->next = nullptr;
head = temp;
tail = head;
}
void insert(int key) {
if (key < head->key) {
insert_beginning(key);
}
else if ((head->next == nullptr) || (key > tail->key)) {
insert_end(key);
}
else {
insert_middle(key);
}
}
void insert_beginning(int key) {
if (head->next == nullptr) {
tail = head;
}
struct node *temp;
temp = new struct node;
temp->key = key;
temp->next = head;
head = temp;
}
void insert_end(int key) {
struct node *temp;
temp = new struct node;
temp->key = key;
temp->next = nullptr;
if (head->next == nullptr) {
head->next = temp;
tail = temp;
}
else {
tail->next = temp;
}
tail = temp;
}
void insert_middle(int key) {
struct node *temp;
temp = new struct node;
temp->key = key;
struct node *current = head;
struct node *prev = current;
while (current->key < temp->key) {
prev = current;
current = current->next;
}
prev->next = temp;
temp->next = current;
}
void delete_node(int key) {
if (head == nullptr) {
cout << "List is empty\n";
return;
}
if (head->key == key) {
if (head->next == nullptr) {
delete(head);
head = tail = nullptr;
}
struct node *temp = head;
head = head->next;
delete(temp);
}
else {
struct node *current = head;
struct node *prev = current;
while ((current->key != key) && (current->next != nullptr)) {
prev = current;
current = current->next;
}
if ((current->key != key) && (current->next == nullptr)) {
cout << "Key not found\n";
}
else if ((current->key == key) && (current->next == nullptr)) {
tail = prev;
prev->next = nullptr;
delete(current);
}
else {
prev->next = current->next;
delete(current);
}
}
}
void search_node(int key) {
if (head->key == key || tail->key == key) {
cout << "Node found\n";
return;
}
struct node *current = head;
while ((current->key != key) && (current->next != nullptr)) {
current = current->next;
}
if (current->key == key) {
cout << "Node found\n";
}
else {
cout << "Node not found\n";
}
}
void print_nodes(void) {
struct node *current = head;
while (current != nullptr) {
cout << current->key << '\n';
current = current->next;
}
}
~linked_list() {
struct node *current = head;
struct node *prev = current;
while (current->next != nullptr) {
current = current->next;
delete(prev);
prev = current;
}
delete(prev);
}
};
int main(void) {
linked_list list;
list.create(0);
for (int i = 1; i < 20; ++i) {
list.insert(i);
}
list.search_node(5);
list.search_node(0);
list.search_node(-1);
list.delete_node(19);
list.delete_node(0);
list.print_nodes();
_CrtDumpMemoryLeaks();
}
When you call _CrtDumpMemoryLeaks();, you have not yet destructed your list object.
UPDATE
Adding a set of braces so as to destruct list before doing the memory leak diagnostic.
int main(void) {
{
linked_list list;
list.create(0);
for (int i = 1; i < 20; ++i) {
list.insert(i);
}
list.search_node(5);
list.search_node(0);
list.search_node(-1);
list.delete_node(19);
list.delete_node(0);
list.print_nodes();
}
_CrtDumpMemoryLeaks();
}
The usual way to do a leak check as late as possible with MSVC is to enable the automatic dump functionality, with the following code:
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_LEAK_CHECK_DF);
This will do a leak check after main/WinMain has returned and global object destructors have run. And if you've ever seen an MFC dump report that is how it is enabled.

Need help solving memory leak error

When I run valgrind, I get one error at method insert for operator new;
I know this probably means that I have to delete node n how I tried so many things to try to delete it but it just gives me even more errors. Please hel.
class key_value_sequences {
public:
struct node{
int key;
vector<int> values;
node* next;
node* prev;
};
key_value_sequences() {
}
~key_value_sequences() {
}
key_value_sequences(const key_value_sequences& A) {
n = A.n;
head = A.head;
tail = A.tail;
v = A.v;
}
key_value_sequences& operator=(const key_value_sequences& A) {
if (this == &A) return *this;
n = A.n;
head = A.head;
tail = A.tail;
v = A.v;
return *this;
}
// YOU SHOULD USE C++ CONTAINERS TO AVOID RAW POINTERS
// IF YOU DECIDE TO USE POINTERS, MAKE SURE THAT YOU MANAGE MEMORY PROPERLY
// IMPLEMENT ME: SHOULD RETURN SIZE OF A SEQUENCE FOR GIVEN KEY
// IF NO SEQUENCE EXISTS FOR A GIVEN KEY RETURN -1
int size(int key) const {
if (find(v.begin(), v.end(), key)!=v.end()) {
node* temp = head;
while(temp != NULL) {
if (temp->key == key) {
return temp->values.size();
}
else temp = temp->next;
}
}
else return -1;
}
// IMPLEMENT ME: SHOULD RETURN POINTER TO A SEQUENCE FOR GIVEN KEY
// IF NO SEQUENCE EXISTS FOR A GIVEN KEY RETURN nullptr
const int* data(int key) const {
if (find(v.begin(), v.end(), key)!=v.end()) {
node* temp = head;
while(temp != NULL) {
if (temp->key == key) {
return temp->values.data();
}
else temp = temp->next;
}
}
else return nullptr;
}
// IMPLEMENT ME: INSERT VALUE INTO A SEQUENCE IDENTIFIED BY GIVEN KEY
void insert(int key, int value) {
if(v.size() == 0) { //empty list
v.push_back(key);
n = new node;
n->prev = NULL;
n->key = key;
n->values.push_back(value);
head = n;
tail = n;
}
else if((find(v.begin(), v.end(), key)!=v.end())) { //if key exists already
node* temp = head;
while(temp != NULL) {
if (temp->key == key) {
temp->values.push_back(value);
break;
}
else temp = temp->next;
}
}
else { //if theres no existing key
v.push_back(key);
n = new node;
n->key = key;
n->values.push_back(value);
n->prev = tail;
tail->next = n;
tail = n;
tail->next = NULL;
}
}
private:
vector<int> v;
node* n;
node* head;
node* tail;
}; // class key_value_sequences
#endif // A3_HPP
In insert method:
if(v.size() == 0) { //empty list
v.push_back(key);
n = new node;
n->prev = NULL;
n->key = key;
n->values.push_back(value);
head = n;
tail = n;
}
You are not setting the head->next to NULL. I suspect that could be the problem while inserting second value.
while(temp != NULL) { // <<<<< Is temp uninitialized?
if (temp->key == key) {
temp->values.push_back(value);
break;
}
else temp = temp->next;
Its pretty dangerous to not initialize the pointer to NULL

Merge Sort Singly Linked List in C++ failing for large input

Update. its working for 65,519 in the FOR LOOP. If i increase it to 65,520, it fails. Completely strange.
This program is not working for large inputs. It is perfect for small inputs. I am getting an exception on Xcode.
Thread 1 : EXC_BAD_ACCESS (code=2, address = 0x7fff5f3fffb8).
Kindly let me know how I can bypass this strange error.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct Node * nodePtr;
struct Node{
int data;
nodePtr next;
};
nodePtr globalHead;
void partition(nodePtr head, nodePtr *front, nodePtr *back){
nodePtr fast;
nodePtr slow;
if (head == NULL || head->next == NULL){
*front = head; // &a
*back = NULL; // &b
}else{
slow = head;
fast = head->next;
while(fast != NULL){
fast = fast->next;
if(fast != NULL){
slow = slow->next;
fast = fast->next;
}
}
*front = head; // a
*back = slow->next; // b
slow->next = NULL;
//printList(*front);
//printList(*back);
}
}
nodePtr mergeLists(nodePtr a, nodePtr b){
nodePtr mergedList = NULL;
if (a == NULL){
return b;
}else if (b == NULL){
return a;
}
try {
if (a->data <= b->data){
mergedList = a;
mergedList->next = mergeLists(a->next, b);
}else{
mergedList = b;
mergedList->next = mergeLists(a, b->next);
}
}
catch (int e) {
cout << "Error is . . " << e << endl;
}
return mergedList;
}
void mergeSort(nodePtr *source){
nodePtr head = *source;
nodePtr a = NULL;
nodePtr b = NULL;
if(head == NULL || head->next == NULL){
return;
}
partition(head, &a, &b);
mergeSort(&a);
mergeSort(&b);
*source = mergeLists(a, b);
}
void push(nodePtr *head, int data){
nodePtr newNode = (nodePtr) malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if ((*head) == NULL){
*head = newNode;
globalHead = *head;
}else{
(*head)->next = newNode;
*head = newNode;
}
}
void printList(nodePtr head){
nodePtr current = head;
while(current != NULL){
printf("%d ",current->data);
current = current->next;
}
printf("\n");
}
// *head = head in the main function,
// it is only there to connect the two and
// not let make the function return anything
// passed by reference
// globalHead points to the start of the linked list
// if you are passing the address over here you have to
// make a double pointer over there in the function
int main(void)
{
nodePtr head = NULL;
// linked list is formed from top to bottom fashion
// push is done in constant time O(1)
long long int i;
//Pushing 200,000 Elements to the Linked List.
for(i=1 ; i<=200000 ; i++) {
push(&head, rand()%200000);
}
printList(globalHead);
mergeSort(&globalHead);
cout << "After Sorting . . \n";
printList(globalHead);
return 0;
}
Using recursion mergeLists() is the issue, it will call itself for every node on the list. Try changing the code so that the code loops and appends nodes to the initially empty mergeList, using a second pointer to node, or optionally a pointer to pointer to node which is initially set to &mergeList. For example, using the name pMerge instead of mergeList:
Node * mergeLists(Node *a, Node *b)
{
Node *pMerge = NULL; // ptr to merged list
Node **ppMerge = &pMerge; // ptr to pMerge or prev->next
if(a == NULL)
return b;
if(b == NULL)
return a;
while(1){
if(a->data <= b->data){ // if a <= b
*ppMerge = a;
a = *(ppMerge = &(a->next));
if(a == NULL){
*ppMerge = b;
break;
}
} else { // b <= a
*ppMerge = b;
b = *(ppMerge = &(b->next));
if(b == NULL){
*ppMerge = a;
break;
}
}
}
return pMerge;
}
Here is example code of a fast method to sort a linked list using an array of pointers to lists aList[], where aList[i] points to a list of size 2 to the power i, that makes use of mergeLists().
#define NUMLISTS 32 // size of aList
Node * mergeSort(NODE *pList)
{
Node * aList[NUMLISTS]; // array of pointers to lists
Node * pNode;
Node * pNext;
int i;
if(pList == NULL) // check for empty list
return NULL;
for(i = 0; i < NUMLISTS; i++) // zero array
aList[i] = NULL;
pNode = pList; // merge nodes into array
while(pNode != NULL){
pNext = pNode->next;
pNode->next = NULL;
for(i = 0; (i < NUMLISTS) && (aList[i] != NULL); i++){
pNode = mergeLists(aList[i], pNode);
aList[i] = NULL;
}
if(i == NUMLISTS)
i--;
aList[i] = pNode;
pNode = pNext;
}
pNode = NULL; // merge array into one list
for(i = 0; i < NUMLISTS; i++)
pNode = mergeLists(aList[i], pNode);
return pNode;
}