I am fairly new to programming and am having memory issues with my program. Somewhere I am overusing memory, but can't find the source. I don't understand why it is giving me issues with malloc allocation as i don't dynamically allocate any variables. Thanks
//returns the index of the character in the string
int find(string line, int begin, int end, char character) {
for (int i = begin; i <= end; i++) {
if (line[i] == character) {
return i;
}
}
//return -1 if not found
return -1;
}
//Get the characters from levelorder that align with inorder
char* getCharacters(char inOrder[], char levelOrder[], int a, int b) {
char *newLevelOrder = new char[a];
int j = 0;
for (int i = 0; i <= b; i++)
if (find(inOrder, 0, a-1, levelOrder[i]) != -1)
newLevelOrder[j] = levelOrder[i], j++;
return newLevelOrder;
}
//creates a new Node given a character
Node* newNode(char character) {
Node *node = new Node;
node->character = character;
node->left = NULL;
node->right = NULL;
return node;
}
//creates the huffman tree from inorder and levelorder
Node* createInLevelTree(char inOrder[], char levelOrder[], int beginning, int end, int size) {
//if start index is out of range
if (beginning > end) {
return NULL;
}
//the head of the tree is the 1st item in level order's traversal
Node *head = newNode(levelOrder[0]);
//if there are no children we can't go farther down
if (beginning == end) {
return head;
}
//get the index of the node
int index = find(inOrder, beginning, end, head->character);
//get the subtree on the left
char *leftTree = getCharacters(inOrder, levelOrder, index, size);
//get the subtree on the right
char *rightTree = getCharacters(inOrder + index + 1, levelOrder, size-index-1, size);
//branch off to the left and right
head->left = createInLevelTree(inOrder, leftTree, beginning, index-1, size);
head->right = createInLevelTree(inOrder, rightTree, index+1, end, size);
//delete
delete [] leftTree;
delete [] rightTree;
return head;
}
Fixed with this line. Thanks Sam.
Char* new level order = new char [b]
Somewhere I am overusing memory, but can't find the source.
I'd suggest you at least replace your character arrays with std::vector<char> or std::string and put some size assertions in, or use the at member to see no over-indexing happens. Furthermore, using operator new more than likely is implemented in terms of malloc, and operator delete in terms of free. Therefore you are allocated dynamically.
Also, wiki for RAII. Try and employ RAII for dynamically allocated memory ... always. std::vector and std::string gives you this for free.
Also, consider the code below:
char* getCharacters(char inOrder[], char levelOrder[], int a, int b) {
char *newLevelOrder = new char[a];
int j = 0;
for (int i = 0; i <= b; i++)
if (find(inOrder, 0, a-1, levelOrder[i]) != -1)
newLevelOrder[j] = levelOrder[i], j++;
return newLevelOrder;
}
Reading this, I'm not sure of the quantity of b. There is no restriction imposed at the call sight. How do I know that the for loop won't invoke indefined behavior (by overindexing). Typically a correct for loop would use "a" here, as "a" was used to create the array... If you want to code like this, use asserts liberally, as you are making assumptions about the calling code (but just use a vector....).
char *newLevelOrder = new char[a];
int j = 0;
for (int i = 0; (i < a) && (i <= b); i++)
{
or
assert (b < a);
char *newLevelOrder = new char[a];
int j = 0;
for (int i = 0; (i <= b); i++)
{
I leave the task of replacing your arrays with vectors and string as an exercise for you, as well as liberally spraying asserts in for loops mentioned... That will likely solve your problems
Related
Inside the ArrayList I'm trying to delete all possible 0's that are appended as input, but for now it only deletes just one 0, no matter where it is located. But seems like I can't delete more than one zero at the time. How can I fix this?
void AList::elimZeros(){
int i;
int curr = 0;
for(i=0; i < listSize; i++) {
if ( (listArray[i] != 0 ) && (curr<listSize) ){
listArray[curr] = listArray[i];
curr++;
}
else if (listArray[i] == 0 )
{
listArray[curr] = listArray[i+1];
listSize--;
curr++;
}
}
}
This is the class for the ADT
class AList : public List {
private:
ListItemType* listArray; // Array holding list elements
static const int DEFAULT_SIZE = 10; // Default size
int maxSize; // Maximum size of list
int listSize; // Current # of list items
int curr; // Position of current element
// Duplicates the size of the array pointed to by listArray
// and update the value of maxSize.
void resize();
public:
// Constructors
// Create a new list object with maximum size "size"
AList(int size = DEFAULT_SIZE) : listSize(0), curr(0) {
maxSize = size;
listArray = new ListItemType[size]; // Create listArray
}
~AList(); // destructor to remove array
This is the input I'm testing with:
int main() {
AList L(10);
AList L2(20);
L.append(10);
expect(L.to_string()=="<|10>");
L.append(20);
expect(L.to_string()=="<|10,20>");
L.append(30);
L.append(0);
L.append(40);
L.append(0);
L.append(0);
expect(L.to_string()=="<|10,20,30,0,40>");
L.elimZeros();
expect(L.to_string()=="<|10,20,30,40>");
assertionReport();
}
It'd be helpful if you posted the class code for AList. Think you confused Java's ArrayList type, but assuming you're using vectors you can always just do:
for (int i = 0; i < listSize; i++) {
if(listArray[i] == 0) listArray.erase(i);
}
EDIT: Assuming this is the template of for the AList class, then there is simply a remove() function. In terms of your code, there are two issues.
You reference listSize in the for loop, then decrement it inside of the loop. Each iteration evaluates the value separately so you're reducing the number of total loop iterations and stopping early.
The other thing is if the entry is zero you shouldn't increment curr and set listArray[curr] = listArray[i+1]. This is basically assuming the next entry will not be a zero. So if it is, then you're copying the element and moving to the next. Your if statement can be cleaned up with:
if (listArray[i] == 0) {
listSize--;
} else {
listArray[curr] = listArray[i];
curr++;
}
I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.
So I thought I understood how to implement an array of pointers but my compiler says otherwise =(. Any help would be appreciated, I feel like I'm close but am missing something crucial.
1.) I have a struct called node declared:.
struct node {
int num;
node *next;
}
2.) I've declared a pointer to an array of pointers like so:
node **arrayOfPointers;
3.) I've then dynamically created the array of pointers by doing this:
arrayOfPointers = new node*[arraySize];
My understanding is at this point, arrayOfPointers is now pointing to an array of x node type, with x being = to arraySize.
4.) But when I want to access the fifth element in arrayOfPointers to check if its next pointer is null, I'm getting a segmentation fault error. Using this:
if (arrayOfPointers[5]->next == NULL)
{
cout << "I'm null" << endl;
}
Does anyone know why this is happening? I was able to assign a value to num by doing: arrayOfPointers[5]->num = 77;
But I'm confused as to why checking the pointer in the struct is causing an error. Also, while we're at it, what would be the proper protoype for passing in arrayOfPointers into a function? Is it still (node **arrayOfPointers) or is it some other thing like (node * &arrayOfPointers)?
Thanks in advance for any tips or pointers (haha) you may have!
Full code (Updated):
/*
* Functions related to separate chain hashing
*/
struct chainNode
{
int value;
chainNode *next;
};
chainNode* CreateNewChainNode (int keyValue)
{
chainNode *newNode;
newNode = new (nothrow) chainNode;
newNode->value = keyValue;
newNode->next = NULL;
return newNode;
}
void InitDynamicArrayList (int tableSize, chainNode **chainListArray)
{
// create dynamic array of pointers
chainListArray = new (nothrow) chainNode*[tableSize];
// allocate each pointer in array
for (int i=0; i < tableSize; i++)
{
chainListArray[i]= CreateNewChainNode(0);
}
return;
}
bool SeparateChainInsert (int keyValue, int hashAddress, chainNode **chainListArray)
{
bool isInserted = false;
chainNode *newNode;
newNode = CreateNewChainNode(keyValue); // create new node
// if memory allocation did not fail, insert new node into hash table
if (newNode != NULL)
{
//if array cell at hash address is empty
if (chainListArray[hashAddress]->next == NULL)
{
// insert new node to front of list, keeping next pointer still set to NULL
chainListArray[hashAddress]->next = newNode;
}
else //else cell is pointing to a list of nodes already
{
// new node's next pointer will point to former front of linked list
newNode->next = chainListArray[hashAddress]->next;
// insert new node to front of list
chainListArray[hashAddress]->next = newNode;
}
isInserted = true;
cout << keyValue << " inserted into chainListArray at index " << hashAddress << endl;
}
return isInserted;
}
/*
* Functions to fill array with random numbers for hashing
*/
void FillNumArray (int randomArray[])
{
int i = 0; // counter for for loop
int randomNum = 0; // randomly generated number
for (i = 0; i < ARRAY_SIZE; i++) // do this for entire array
{
randomNum = GenerateRandomNum(); // get a random number
while(!IsUniqueNum(randomNum, randomArray)) // loops until random number is unique
{
randomNum = GenerateRandomNum();
}
randomArray[i] = randomNum; // insert random number into array
}
return;
}
int GenerateRandomNum ()
{
int num = 0; // randomly generated number
// generate random number between start and end ranges
num = (rand() % END_RANGE) + START_RANGE;
return num;
}
bool IsUniqueNum (int num, int randomArray[])
{
bool isUnique = true; // indicates if number is unique and NOT in array
int index = 0; // array index
//loop until end of array or a zero is found
//(since array elements were initialized to zero)
while ((index < ARRAY_SIZE) && (!randomArray[index] == 0))
{
// if a value in the array matches the num passed in, num is not unique
if (randomArray[index] == num)
{
isUnique = false;
}
index++; // increment index counter
} // end while
return isUnique;
}
/*
*main
*/
int main (int argc, char* argv[])
{
int randomNums[ARRAY_SIZE] = {0}; // initialize array elements to 0
int hashTableSize = 0; // size of hash table to use
chainNode **chainListArray;
bool chainEntry = true; //testing chain hashing
//initialize random seed
srand((unsigned)time(NULL));
FillNumArray(randomNums); // fill randomNums array with random numbers
//test print array
for(int i = 0; i < ARRAY_SIZE; i++)
{
cout << randomNums[i] << endl;
}
//test chain hashing insert
hashTableSize = 19;
int hashAddress = 0;
InitDynamicArrayList(hashTableSize, chainListArray);
//try to hash into hash table
for (int i = 0; i < ARRAY_SIZE; i++)
{
hashAddress = randomNums[i] % hashTableSize;
chainEntry = SeparateChainInsert(randomNums[i], hashAddress, chainListArray);
}
system("pause");
return 0;
}
arrayOfPointers = new node*[arraySize];
That returns a bunch of unallocated pointers. Your top level array is fine, but its elements are still uninitialized pointers, so when you do this:
->next
You invoke undefined behavior. You're dereferencing an uninitialized pointer.
You allocated the array properly, now you need to allocate each pointer, i.e.,
for(int i = 0; i < arraySize; ++i) {
arrayOfPointers[i] = new node;
}
As an aside, I realize that you're learning, but you should realize that you're essentially writing C here. In C++ you have a myriad of wonderful data structures that will handle memory allocation (and, more importantly, deallocation) for you.
Your code is good, but it's about how you declared your InitDynamicArrayList. One way is to use ***chainListArray, or the more C++-like syntax to use references like this:
void InitDynamicArrayList (int tableSize, chainNode **&chainListArray)
I'm trying to write a function that pushes an item onto the end of my dynamically allocated array (not allowed to use vectors). Once it goes to the area to double the size of the list if the list was too small to store the next number, it all goes to hell and starts feeding me back random numbers from the computer. Can anyone see why it's not doubling like it's suuposed to?
int *contents_;
int *temp;
int size_ = 0;
int capacity_ = 1;
void pushBack(int item) /**appends the specified value to DynArray; if the contents array is full,
double the size of the contents array and then append the value **/
{
if (size_ == capacity_)
{
capacity_ = (2*capacity_);
temp = new int[capacity_];
for (int i = 0; i < size_; ++i)
{
temp[i] = contents_[i];
}
delete [] contents_;
contents_ = temp;
}
contents_[size_++] = item;
}
EDIT ** I forgot to mention. This is a function out of a class. This is in the header and in main :
main()
{
DynArray myArray;
myArray.pushBack(2);
myArray.pushBack(3);
myArray.printArray();
return 0;
}
If this is your initial setup:
int *contents_; // Junk
int size_ = 0;
int capacity_ = 1;
Then your code is most likely performing a memory access violation upon the first time it does:
if (size_ == capacity_)
{
// Not entering here, contents_ remains junk
}
contents_[size_++] = item;
As barak implied, the contents_ pointer needs to be initialized. If not, c++ will point it to something you probably don't want it to.
I was trying to implement exponential tree from documentation, but here is one place in the code which is not clear for me how to implement it:
#include<iostream>
using namespace std;
struct node
{
int level;
int count;
node **child;
int data[];
};
int binary_search(node *ptr,int element)
{
if(element>ptr->data[ptr->count-1]) return ptr->count;
int start=0;
int end=ptr->count-1;
int mid=start+(end-start)/2;
while(start<end)
{
if(element>ptr->data[mid]) { start=mid+1;}
else
{
end=mid;
}
mid=start+(end-start)/2;
}
return mid;
}
void insert(node *root,int element)
{
node *ptr=root,*parent=NULL;
int i=0;
while(ptr!=NULL)
{
int level=ptr->level,count=ptr->count;
i=binary_search(ptr,element);
if(count<level){
for(int j=count;j<=i-1;j--)
ptr->data[j]=ptr->data[j-1];
}
ptr->data[i]=element;
ptr->count=count+1;
return ;
}
parent=ptr,ptr=ptr->child[i];
//Create a new Exponential Node at ith child of parent and
//insert element in that
return ;
}
int main()
{
return 0;
}
Here is a link for the paper I'm referring to:
http://www.ijcaonline.org/volume24/number3/pxc3873876.pdf
This place is in comment, how can I create a new exponential node at level i? Like this?
parent->child[i]=new node;
insert(parent,element);
The presence of the empty array at the end of the structure indicates this is C style code rather than C++ (it's a C Hack for flexible arrays). I'll continue with C style code as idiomatic C++ code would prefer use of standard containers for the child and data members.
Some notes and comments on the following code:
There were a number of issues with the pseudo-code in the linked paper to a point where it is better to ignore it and develop the code from scratch. The indentation levels are unclear where loops end, all the loop indexes are not correct, the check for finding an insertion point is incorrect, etc....
I didn't include any code for deleting the allocated memory so the code will leak as is.
Zero-sized arrays may not be supported by all compilers (I believe it is a C99 feature). For example VS2010 gives me warning C4200 saying it will not generate the default copy/assignment methods.
I added the createNode() function which gives the answer to your original question of how to allocate a node at a given level.
A very basic test was added and appears to work but more thorough tests are needed before I would be comfortable with the code.
Besides the incorrect pseudo-code the paper has a number of other errors or at least questionable content. For example, concerning Figure 2 it says "which clearly depicts that the slope of graph is linear" where as the graph is clearly not linear. Even if the author meant "approaching linear" it is at least stretching the truth. I would also be interested in the set of integers they used for testing which doesn't appear to be mentioned at all. I assumed they used a random set but I would like to see at least several sets of random numbers used as well as several predefined sets such as an already sorted or inversely sorted set.
.
int binary_search(node *ptr, int element)
{
if (ptr->count == 0) return 0;
if (element > ptr->data[ptr->count-1]) return ptr->count;
int start = 0;
int end = ptr->count - 1;
int mid = start + (end - start)/2;
while (start < end)
{
if (element > ptr->data[mid])
start = mid + 1;
else
end = mid;
mid = start + (end - start)/2;
}
return mid;
}
node* createNode (const int level)
{
if (level <= 0) return NULL;
/* Allocate node with 2**(level-1) integers */
node* pNewNode = (node *) malloc(sizeof(node) + sizeof(int)*(1 << (level - 1)));
memset(pNewNode->data, 0, sizeof(int) * (1 << (level - 1 )));
/* Allocate 2**level child node pointers */
pNewNode->child = (node **) malloc(sizeof(node *)* (1 << level));
memset(pNewNode->child, 0, sizeof(int) * (1 << level));
pNewNode->count = 0;
pNewNode->level = level;
return pNewNode;
}
void insert(node *root, int element)
{
node *ptr = root;
node *parent = NULL;
int i = 0;
while (ptr != NULL)
{
int level = ptr->level;
int count = ptr->count;
i = binary_search(ptr, element);
if (count < (1 << (level-1)))
{
for(int j = count; j >= i+1; --j)
ptr->data[j] = ptr->data[j-1];
ptr->data[i] = element;
++ptr->count;
return;
}
parent = ptr;
ptr = ptr->child[i];
}
parent->child[i] = createNode(parent->level + 1);
insert(parent->child[i], element);
}
void InOrderTrace(node *root)
{
if (root == NULL) return;
for (int i = 0; i < root->count; ++i)
{
if (root->child[i]) InOrderTrace(root->child[i]);
printf ("%d\n", root->data[i]);
}
if (root->child[root->count]) InOrderTrace(root->child[root->count]);
}
void testdata (void)
{
node* pRoot = createNode(1);
for (int i = 0; i < 10000; ++i)
{
insert(pRoot, rand());
}
InOrderTrace(pRoot);
}