Can anyone please tell me why is it showing "runtime error"? - c++

I'm trying to implement hash table, but I'm getting a runtime error in the for loop of createHashTable() function. Can anyone please tell me why is it showing this "runtime error"? Is it StackOverflow error?
#include <iostream>
using namespace std;
#define LOAD_FACTOR 20
struct ListNode{
int data;
struct ListNode *next;
};
struct HashTableNode{
int bCount; // number of elements in the block
struct ListNode *next;
};
struct HashTable{
int tSize; // table size
int count; // total number of elements in the table
struct HashTableNode **hashTableNodeArray;
};
int hashFunction(struct HashTable *h, int data){
return data % h->tSize;
}
struct HashTable * createHashTable(int numberOfElements){
struct HashTable *h = new HashTable;
h->count = 0;
h->tSize = numberOfElements / LOAD_FACTOR;
h->hashTableNodeArray = new HashTableNode *[h->tSize];
for(int i = 0; i < h->tSize; ++i){
// this is where it is showing runtime error
h->hashTableNodeArray[i]->bCount = 0;
h->hashTableNodeArray[i]->next = nullptr;
}
return h;
}
void deleteHashTable(struct HashTable *h){
struct ListNode *node, *tmp;
for(int i = 0; i < h->tSize; ++i){
node = h->hashTableNodeArray[i]->next;
while(node != nullptr){
tmp = node;
node = node->next;
delete tmp;
}
}
delete[] h->hashTableNodeArray;
delete h;
}
int main(int argc, char **argv){
struct HashTable *h = createHashTable(220);
deleteHashTable(h);
return 0;
}

h->hashTableNodeArray = new HashTableNode *[h->tSize];
This allocates an array of pointers, but not the actual hashtablenodes. In the following loop you try to write to them which is undefined behaviour.
You are missing in your loop:
h->hashTableNodeArray[i] = new HashTableNode;

The problem is here:
h->hashTableNodeArray = new HashTableNode *[h->tSize];
for(int i = 0; i < h->tSize; ++i){
// this is where it is showing runtime error
h->hashTableNodeArray[i]->bCount = 0;
h->hashTableNodeArray[i]->next = nullptr;
}
You allocate an array of pointers, but don't actually make the pointers point anywhere valid which means their values are indeterminate (and in reality seemingly random). You then proceed to dereference these uninitialized pointers, and write to memory using the pointers, without knowing where in memory you will write.
This leads to undefined behavior, and most likely your crash.
The solution? Either don't use pointers, or explicitly allocate the memory for the pointers. My recommendation is to stop using pointers altogether, create proper copy- and move-constructors, and use std::vector instead.

Related

C++ Binary Tree Implementation - Deleting Pointer Causes

I am working on a pretty basic binary tree implementation in C++, but I am currently having a problem that deleting a pointer to the root node crashes the program. In Dev-C++ debug mode the error returned is: "Program received signal SIGTRAP, Trace/breakpoint trap", but when I check with "info breakpoints", it says there are no breakpoints or watchpoints. I'm pretty confused about this and have been spending a lot of time checking if I have used and declared all the pointers correctly, any help would greatly be appreciated!
#include <iostream>
#include <vector>
using namespace std;
class Node {
public:
int key;
Node * left_child = NULL;
Node * right_child = NULL;
};
class Tree {
public:
int num_nodes;
vector<Node> nodes;
int read() {
cin >> num_nodes;
nodes.resize(num_nodes);
int input_key, input_left, input_right, root_node = 0;
for (int i = 0; i < num_nodes; i++) {
cin >> input_key >> input_left >> input_right;
if(input_key >= nodes.size()) {
nodes.resize(input_key+1);
}
if(i==0) {
root_node = input_key;
}
nodes[input_key].key = input_key;
if(input_left >= 0) {
nodes[input_key].left_child = &nodes[input_left];
}
if(input_right >= 0) {
nodes[input_key].right_child = &nodes[input_right];
}
}
return root_node;
}
};
int main() {
Tree t;
int root_index = 0;
root_index = t.read();
Node * root_ptr = new Node;
root_ptr = &(t.nodes[root_index]);
delete root_ptr; //when I take this line out, it works
}
Sample Input (no output expected):
3
4 2 5
2 -1 -1
2 -1 -1
Firstly, this line is useless:
Node * root_ptr = new Node;
You immediately reassign root_ptr to something else. So the line does nothing but allocate memory. You then assign root_ptr as follows:
&(t.nodes[root_index]);
The variable t you declared on the stack. You end up getting a pointer to a vector element, an element you never allocated yourself. If you did not allocate it yourself, you cannot delete it. Any allocation by the vector will be handled by the vector, and the vector itself is a stack-allocated, so you cannot delete it.
That is why the delete line crashes.
Additionally, you say it is a simple binary tree implementation, but it is not. You have a vector in there, and you have a strange way of assigning the tree elements, so you've created some kind of hybrid data structure.

Using shared_ptr to access addresses in vector to creat a linked list

Here, I am trying to make an array of nodes, which will also be linked as a linked list. I am purposely making the vector and linked list together, so as to make them contiguous, and when I pop from the vector, I can still refer to the memory.
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
struct node {
int data;
std::shared_ptr<node> next;
};
int main(){
vector<node> myArray;
for (int i = 0; i < 10; ++i) {
myArray.push_back(node());
}
for (int i = 0; i < 10; ++i) {
myArray[i].data = i;
myArray[i].next.reset(&myArray[i+1]);
}
std::shared_ptr<node> nodeList(make_shared<node>());
auto here = nodeList;
for (int i = 0; i < 10; ++i) {
here->next.reset(&myArray[i]); // the error occurs in this line
here = here->next;
}
here = nodeList;
here = here->next;
while (here != nullptr) {
cout << here->data << " with address of : " << &(*here) << endl;
}
return 0;
}
When I run this code, I get an error stating error for object 0x7fb8cbc033d0: pointer being freed was not allocated. Why is this happening? Thank you for your help in advance.
1) The pointer you assigned to myArray[i].next is not allocated by anyone, so it will barf when shared_ptr try to delete it.
2) myArray[i].next.reset(&myArray[i+1]); is dangerous, because the vector could reallocate the memory it uses, and this pointer will be invalid.
3) A linked list node doesn't have to store a pointer, you could store a next_index filed and do myArray[i].next_index = i + 1 or something like that.
4) You could also store shared_ptr in the vector if that's what you want.

A pointer to an array of pointers

I know I should know this, but it's late and my brain just won't put the pieces together.
This is as straight forward as a question can get:
I have a struct item. I want to create a pointer to an array of pointers to that item type.
Eg.
struct item {
int data;
string moreData;
};
I want to have an ArrayPointer that point's to an array. I want that array to contain in each element a pointer to an item.
How do I do this in C++, or more sepcifically where do I need to put how many dereferencing operators? I know how to declare basic (single indirection) pointers and am pretty fluent in their use.
I need information for the following steps if at all possible:
Declaring the ArrayPointer.
Initializing the ArrayPointer with a size s.
Initializing each element of ArrayPointer with new item.
eg:
for(int i = 0; i < s; i++)
ArrayPointer[i] = // a new item
I feel like as soon as someone posts an answer I'm going to facepalm so hard I break my nose.
If I have understood correctly then you need something like this
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item; { i, "More Data" };
}
Or
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item;
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
To free the allocated memory you can in reverse order
for ( int i = 0; i < s; i++ )
{
delete ArrayPointer[i];
}
delete [] ArrayPointer;
Otherewise if s is a constant then you may simply declare an array of pointers. For example
item * ArrayPointer[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
file.h
struct item {
int data;
string moreData;
};
item ** array;
file.cpp
array = new item*[s];
for(int i = 0; i < s; i++)
{
array[i] = new item;
array[i]->data = 10;
array[i]->moreData = "data";
}
What you want is an array of struct item *, which are pointers to item structs.
An array of such pointers is a struct item **.
#include <string>
#include <cstdlib>
using namespace std;
struct item {
int data;
string moreData;
};
struct item * newItem(int data, string moreData) {
struct item *result = (struct item *) malloc(sizeof(struct item));
result->data = data;
result->moreData = moreData;
return result;
}
struct item ** array; // We don't know the size of the array in advance.
int main() {
int arraySize = 3; // We get this value from somewhere (user input?).
array = (struct item **) malloc(3*sizeof(struct item *));
// Now the array has been allocated. There is space for
// arraySize pointers.
array[0] = newItem(5, "ant"); // Let's make some items. Note that
array[1] = newItem(90, "bear"); // newItem() returns a pointer to
array[2] = newItem(25, "cat"); // an item.
return 0;
}

I got a glibc detected error

I am trying to create an array that, when filled, will cause a new bigger array to be created, will copy the values of the old array into the previous array, and will continue adding values to the new array from where the old one left off. My code works fine while I'm adding to the first array, but once I try to call append after I've filled up the original array, I end up getting a weird error:
*** glibc detected *** demo: double free or corruption (fasttop): 0x0000000000602010 ***
No clue what's going on! I'm not really sure why.
#include <iostream>
using namespace std;
class ArrayList {
public:
int* array;
public:
int capacity = 0;
int size = 16;
ArrayList() {
array = new int(size);
}
void append(int data) {
if (size == capacity) {
int* tmp = new int(size+16);
for (int i = 0; i != size; i++) {
tmp[i] = array[i];
delete [] array;
}
array = tmp;
} else {
array[capacity] = data;
capacity++;
// std::cout << *(array+15) << std::endl;
}
Your syntax for allocating an array is wrong - instead of
int* tmp = new int(size+16);
(which creates a new int and initializes it with the value size+16), you need
int* tmp = new int[size+16];
which creates a new int array with size+16 elements.

How can I prevent segmentation faults in my program?

I have a C assignment. It is a lot longer than the code shown below, and we are given the function prototypes and instructions only. I have done my best at writing code, but I am stuck with segmentation faults. When I compile and run the program below on Linux, at "735 NaN" it will terminate, indicating a segfault occurred. Why? What am I doing wrong? Basically, the program does not let me access table->list_array[735]->value and table->list_array[735]->key. This is of course the first segfault. There might be more following index 735.
#include <stdio.h>
#include <stdlib.h>
typedef struct list_node list_node_t;
struct list_node
{
char *key;
int value;
list_node_t *next;
};
typedef struct count_table count_table_t;
struct count_table {
int size;
list_node_t **list_array;
};
count_table_t* table_allocate(int size)
{
count_table_t *ptr = malloc(sizeof(count_table_t));
ptr->size = size;
list_node_t *nodes[size];
int k;
for(k=0; k<size; k++){
nodes[k] = NULL;
}
ptr->list_array = nodes;
return ptr;
}
void table_addvalue(count_table_t *table)
{
int i;
for(i=0; i<table->size; i++)
{
table->list_array[i] = malloc(sizeof(list_node_t));
table->list_array[i]->value = i;
table->list_array[i]->key = "NaN";
table->list_array[i]->next = NULL;
}
}
int main()
{
count_table_t *table = table_allocate(1000);
table_addvalue(table);
int i;
for(i=0; i<table->size; i++)
printf("%d %s\n", table->list_array[i]->value, table->list_array[i]->key);
return 0;
}
You're point ptr->list_array at a local variable (nodes) in table_allocate, which goes away when that function returns, leaving a dangling pointer. You probably want
list_node_t **nodes = malloc(size * sizeof(list_node_t *));
I recommend the routine use of valgrind(1) to prevent such problems from occurring.