So this is a problem I noticed with a small project I'm working on and I can't figure out what's going on, or what to search to fix it, so I wrote this small program to recreate the problem. I haven't worked with c++ in a few years so apologies if this is a really obvious problem.
#include <iostream>
#include <vector>
using namespace std;
class Cell{
int score;
Cell* next_l;
Cell* next_r;
public:
Cell(int s = 0, Cell *r = nullptr, Cell *l = nullptr){
this -> score = s;
this -> next_l = l;
this -> next_r = r;
}
int getScore(){
return this -> score;
}
void disp(){
cout << "Score: " << this -> score << endl; //Problem Line
if(this -> next_r != nullptr){
this -> next_r -> disp();
}
if(this -> next_l != nullptr){
this -> next_l -> disp();
}
}
};
// returns a cell that's the head of a binary tree
// formed by replacing last two cells in the vector
// with a Cell pointing to those two cells instead,
// and then calling this function on that new vector of cells.
Cell make_tree(vector<Cell> &cells){
if(cells.size() == 1){
return cells[0];
}else{
Cell c1 = *(cells.end() - 1);
cells.pop_back();
Cell c2 = *(cells.end() - 1);
cells.pop_back();
Cell cell = Cell(c1.getScore() + c2.getScore(), &c1, &c2);
cells.push_back(cell);
return make_tree(cells);
}
}
int main(){
vector<Cell> cells;
for(int i = 0; i < 3; i++){
Cell *ptr{new Cell(i)};
cells.push_back(*ptr);
}
Cell head = make_tree(cells);
head.disp();
return 0;
}
So the line that I marked as //Problem Line is where I faced confusion while debugging. After printing the score, for some reason, all the values in the tree after a certain depth get replaced by random junk. This eventually leads to a segmentation fault. I have no idea how to proceed with fixing this problem.
The problem is that you are taking pointers to local variables in this line:
Cell cell = Cell(c1.getScore() + c2.getScore(), &c1, &c2);
The members next_l and next_r are pointing to variables c1 and c2 that are on the stack which is not ok. These values are invalid the moment the function terminates and are overwritten when other function calls are made afterward.
Try to change the code so that the cells will be placed in vector<Cell*> cells. Then your code will look like:
Cell* make_tree(vector<Cell*> &cells) {
...
Cell* c1 = *(cells.end() - 1);
cells.pop_back();
Cell* c2 = *(cells.end() - 1);
cells.pop_back();
Cell* cell = new Cell(c1->getScore() + c2->getScore(), c1, c2);
cells.push_back( cell );
return make_tree( cells );
...
}
You will have to delete the resulting cell (delete head;) at the end of the program and you will also have to write a destructor for Cell that will delete its left and right children. You could avoid this by using shared pointers (std::shared_ptr) instead of raw pointers:
std::shared_ptr<Cell> next_l, next_r
vector<std::shared_ptr<Cell>> cells;
std::shared_ptr<Cell> make_tree(vector<std::shared_ptr<Cell>> &cells)
std::shared_ptr<Cell> c1, c2
auto cell = std::make_shared<Cell>(c1->getScore() + c2->getScore(), c1, c2)
Because of std::make_shared you will also need the default constructor:
class Cell{
...
Cell() = default;
...
};
Related
So for a school project, we are being asked to do a word frequency analysis of a text file using dictionaries and bucket hashing. The output should be something like this:
$ ./stats < jabberwocky.txt
READING text from STDIN. Hit ctrl-d when done entering text.
DONE.
HERE are the word statistics of that text:
There are 94 distinct words used in that text.
The top 10 ranked words (with their frequencies) are:
1. the:19, 2. and:14, 3. !:11, 4. he:7, 5. in:6, 6. .:5, 7.
through:3, 8. my:3, 9. jabberwock:3, 10. went:2
Among its 94 words, 57 of them appear exactly once.
Most of the code has been written for us, but there are four functions we need to complete to get this working:
increment(dict D, std::str w) which will increment the count of a word or add a new entry in the dictionary if it isn't there,
getCount(dict D, std::str w) which fetches the count of a word or returns 0,
dumpAndDestroy(dict D) which dumps the words and counts of those words into a new array by decreasing order of count and deletes D's buckets off the heap, and returns the pointer to that array,
rehash(dict D, std::str w) which rehashes the function when needed.
The structs used are here for reference:
// entry
//
// A linked list node for word/count entries in the dictionary.
//
struct entry {
std::string word; // The word that serves as the key for this entry.
int count; // The integer count associated with that word.
struct entry* next;
};
// bucket
//
// A bucket serving as the collection of entries that map to a
// certain location within a bucket hash table.
//
struct bucket {
entry* first; // It's just a pointer to the first entry in the
// bucket list.
};
// dict
//
// The unordered dictionary of word/count entries, organized as a
// bucket hash table.
//
struct dict {
bucket* buckets; // An array of buckets, indexed by the hash function.
int numIncrements; // Total count over all entries. Number of `increment` calls.
int numBuckets; // The array is indexed from 0 to numBuckets.
int numEntries; // The total number of entries in the whole
// dictionary, distributed amongst its buckets.
int loadFactor; // The threshold maximum average size of the
// buckets. When numEntries/numBuckets exceeds
// this loadFactor, the table gets rehashed.
};
I've written these functions, but when I try to run it with a text file, I get a Floating point exception error. I've emailed my professor for help, but he hasn't replied. This project is due very soon, so help would be much appreciated! My written functions for these are as below:
int getCount(dict* D, std::string w) {
int stringCount;
int countHash = hashValue(w, numKeys(D));
bucket correctList = D->buckets[countHash];
entry* current = correctList.first;
while (current != nullptr && current->word < w) {
if (current->word == w) {
stringCount = current->count;
}
current = current->next;
}
std::cout << "getCount working" << std::endl;
return stringCount;
}
void rehash(dict* D) {
// UNIMPLEMENTED
int newSize = (D->numBuckets * 2) + 1;
bucket** newArray = new bucket*[newSize];
for (int i = 0; i < D->numBuckets; i++) {
entry *n = D->buckets->first;
while (n != nullptr) {
entry *tmp = n;
n = n->next;
int newHashValue = hashValue(tmp->word, newSize);
newArray[newHashValue]->first = tmp;
}
}
delete [] D->buckets;
D->buckets = *newArray;
std::cout << "rehash working" << std::endl;
return;
void increment(dict* D, std::string w) {
// UNIMPLEMENTED
int incrementHash = hashValue(w, numKeys(D));
entry* current = D->buckets[incrementHash].first;
if (current == nullptr) {
int originalLF = D->loadFactor;
if ((D->numEntries + 1)/(D->numBuckets) > originalLF) {
rehash(D);
int incrementHash = hashValue(w, numKeys(D));
}
D->buckets[incrementHash].first->word = w;
D->buckets[incrementHash].first->count++;
}
while (current != nullptr && current->word < w) {
entry* follow = current;
current = current->next;
if (current->word == w) {
current->count++;
}
}
std::cout << "increment working" << std::endl;
D->numIncrements++;
}
entry* dumpAndDestroy(dict* D) {
// UNIMPLEMENTED
entry* es = new entry[D->numEntries];
for (int i = 0; i < D->numEntries; i++) {
es[i].word = "foo";
es[i].count = 0;
}
for (int j = 0; j < D->numBuckets; j++) {
entry* current = D->buckets[j].first;
while (current != nullptr) {
es[j].word = current->word;
es[j].count = current->count;
current = current->next;
}
}
delete [] D->buckets;
std::cout << "dumpAndDestroy working" << std::endl;
return es;
A floating-point exception is usually caused by the code attempting to divide-by-zero (or attempting to modulo-by-zero, which implicitly causes a divide-by-zero). With that in mind, I suspect this line is the locus of your problem:
if ((D->numEntries + 1)/(D->numBuckets) > originalLF) {
Note that if D->numBuckets is equal to zero, this line will do a divide-by-zero. I suggest temporarily inserting a line like like
std::cout << "about to divide by " << D->numBuckets << std::endl;
just before that line, and then re-running your program; that will make the problem apparent, assuming it is the problem. The solution, of course, is to make sure your code doesn't divide-by-zero (i.e. by setting D->numBuckets to the appropriate value, or alternatively by checking to see if it is zero before trying to use it is a divisor)
This is the output with the error.
And this is my homework text:
Think about a network that consists of nodes and one direction links.
Each node will be represented by a character and each link has an
integer cost value.
So when all nodes have only one link it works but when I include more than one links to one node it does not work.
#include <iostream>
#include <vector>
using namespace std;
class Node {
public:
char nodeChar;
int cost;
Node(char nodeChar) {
this->nodeChar = nodeChar;
}
vector<Node> nextNodes;
void connect(Node &next, int cost) {
next.cost = cost;
this->nextNodes.push_back(next);
}
};
int main() {
Node A('A'), B('B'), C('C'), D('D');
A.connect(C, 3); // A[0] = C
C.connect(B, 4); // C[0] = B
B.connect(A, 2); // B[0] = A
C.connect(D, 5); // C[1] = D
D.connect(B, 6); // D[0] = B
int sum = 0;
Node currentNode = A;
while (sum < 15) {
cout << currentNode.nodeChar;
Node next = currentNode.nextNodes[0];
currentNode = next;
sum += next.cost;
}
cout << endl;
system("pause");
}
In
A.connect(C, 3);
connect takes the next node as a reference, but when it puts it into nextNodes, nextNodes makes a copy. That means that after A.connect(C, 3); and C.connect(B, 4);. The C in A is different from C and knows nothing of B. This copy of C has no nodes in nextNodes, so
Node next = currentNode.nextNodes[0];
ventures into undefined behaviour. In your case that behaviour is it does not work. Whatever that means.
Solution: A must contain a reference to C, not a copy of it. You are going to have to familiarize yourself with the use of pointers or reference wrappers because you cannot place references into a vector.
I think I am close to finishing this implementation of A* but my mind is becoming fried and am looking for pointers on what I should be doing to complete it.
My current problem is that my function that runs through A* remains stuck on the same node, as in the current node never moves into any other of the open nodes.
Here is my main function, note that the heuristic(Node &n1, Node &n2) function is currently set to always to return 0, so it should currently be working more like a Dijkstra algorithm rather than A*. Also, movement is restricted to the NESW plane, no diagonal movement, so distance_between(Node &n1, Node &n2) always returns 1.
void astar(Node start_, Node end_) {
Node start = start_;
Node end = end_;
// compute f,g,h for the start node
start.g = 0;
start.h = heuristic(start, end);
start.f = start.g + start.h;
// insert start node into the open set
openNodes.insert(&start);
// while the set of open nodes is not empty
while (openNodes.size() > 0) {
// pick the most promising node to look at next
Node currentNode;
cout << "currentNode before: ";
currentNode.displaylocation();
// go through all the open nodes and find the one with the smallest 'f' value
Node* minf = (*openNodes.begin()); // set initial value for minimum f to be the first node in the set of open nodes
for (auto n : openNodes) {
if (n->f <= minf->f) {
minf = n;
}
}
currentNode = *minf; // set the current node to the node that holds the smallest 'f' value
cout << "currentNode after: ";
currentNode.displaylocation();
// if the current node is the end node, then we have found a path
if (currentNode.type == -3) {
break;
}
// remove the current node from the set of open nodes, and add it to the set of closed nodes
openNodes.erase(¤tNode);
closedNodes.insert(¤tNode);
// go through the currents node's neighbours
for (auto n : neighbours(currentNode)) {
cout << "neighbour local: " << n.location.x << "," << n.location.y << "\n";
if (closedNodes.count(&n) == 0 && n.type != -2) { // if this node is neither closed or a blocker
int new_g = currentNode.g + distance_between(currentNode, n);
if (openNodes.count(&n) != 0) { // if we have not seen this node before, add to the open set
openNodes.insert(&n);
}
else if (new_g >= n.g) { // else if we have seen this node before, and already found a shorter path to it from the starting node
}
n.g = new_g;
n.f = n.g + heuristic(n, end);
n.parent_ = ¤tNode;
}
}
cout << "\n A* run success! \n";
//break;
}
}
Here is the deceleration of things like the Node struct and the global variables:
// The size of the grid
#define WIDTH 6
#define HEIGHT 6
// Holds values for x and y locations on the grid
struct Coord {
int x, y;
};
// holds data for each node required for A*
struct Node {
int type; // used for defining if this node is a blocker, empty, start or end
Coord location;
int g = 0;
int h = 0;
int f = g + h;
Node *parent_; // pointer to this node's parent
std::string debugmessage;
void displaylocation() {
std::cout << "I am the node at: " << location.x << "," << location.y << "\n";
}
};
// The 2D grid array for A*, requiring a Node struct to store the data of each cell
Node astarArray[WIDTH][HEIGHT];
// Sets for A*
std::set<Node *> openNodes; // contains the nodes that are yet to be considered (if this is empty, then there are no more paths to consider or there is no path)
std::set<Node *> closedNodes; // contains the nodes that have already been considered (if the end node is placed in here, a path has been found)
// stores the start and end values for A*
Node start_A, end_A;
void astar(Node start_, Node end_);
int distance_between(Node& n1, Node& n2);
int heuristic(Node& n1, Node& n2);
std::list<Node> neighbours(Node& n_);
// returns the distance between two nodes for A*
int distance_between(Node& n1, Node& n2) {
return 1; // always return 1 as we are working in a grid restricted to NSEW movement
}
int heuristic(Node& n1, Node& n2) {
return 0; // return 0 to work as a Dijkstra algorithm rather than A*
}
// finds a node's neighbours for A*
std::list<Node> neighbours(Node& n_) {
std::list<Node> neighbours_;
int x = n_.location.x;
int y = n_.location.y;
// start at the location belonging to 'n_'
//for (int y = n_.location.y; y < HEIGHT; y++) {
//for (int x = n_.location.x; x < WIDTH; x++) {
// east
if (x < WIDTH - 1) {
neighbours_.push_back(astarArray[x + 1][y]);
}
// west
if (x > 0) {
neighbours_.push_back(astarArray[x - 1][y]);
}
// south
if (y < HEIGHT - 1) {
neighbours_.push_back(astarArray[x][y + 1]);
}
// north
if (y > 0) {
neighbours_.push_back(astarArray[x][y -1]);
}
//}
//}
return neighbours_;
}
Thank you very much for reading and for any help you can give. I will provide more code if required.
The main problem you have is that you are using the pointers (mem address) to find out if a node is in your set or not.
currentNode = *minf; // set the current node to the node that holds the smallest 'f' value
Then you copy to currentNode the contents of minf.
currentNode will have a different address from the pointer to minf
openNodes.erase(¤tNode); will not remove minf because currentNode does not have the same address.
I would suggest you investigate more on how to implement A* as you are missing some steps. Look for priority queues.
Instead of the mem address of the node, use the position index for that node in the grid (pos.x * numCols) + pos.y
My problem is that when trying to add to linked lists within an array it would seem to not work and I'm almost totally ignorant as to why this is. First I declare the object move as seen below:
struct move {
move(int startX, int startY, int endX, int endY)
{
this->startX = startX;
this->startY = startY;
this->endX = endX;
this->endY = endY;
this->next = nullptr;
}
move()
{
next = nullptr;
this->startX = -1;
}
int startX;
int startY;
int endX;
int endY;
move* next;
};
I then declare 2 arrays, one which contains 100 linked lists of the moveobject and another which contains pointers to elements in each of the linked lists in the first array. As seen below:
move possibleMoves[100];
move * endOfLists[100];
I then initialise these arrays as seen below:
for (int i = 0; i < 100; i++) {
possibleMoves[i] = move();
endOfLists[i] = &possibleMoves[i];
}
Moving onto the function itself which adds to one of the linked lists within the possibleMoves array I prototype it as such:
void listAdd(move * list, move * object, int width);
I call it as such:
if (possibleMoves[0].startX == -1) {
possibleMoves[0] = *(new move(x, y, x + xOffset, y + yOffset));
}else {
listAdd(endOfLists[width], new move(x, y, x + xOffset, y + yOffset), width);
}
And the function is declared as such:
void listAdd(move * list, move * object, int width) {
int count = 0;
while (list->next != nullptr){
count++;
list = (*list).next;
}
std::cout << "\nCount: " << count << std::endl;
list->next = object;
endOfLists[width] = list->next;
}
Count always outputs as '0'.
Here is a link to all the code (https://pastebin.com/E5g58N6L) it's not pretty. The listAdd procedure is called on lines 188, 197 and 444. Here is the MCVE:
#include<stdio.h>
#include <stdlib.h>
#include<math.h>
#include<iostream>
struct move {
move(int startX, int startY, int endX, int endY)
{
this->startX = startX;
this->startY = startY;
this->endX = endX;
this->endY = endY;
this->next = nullptr;
}
move()
{
next = nullptr;
this->startX = -1;
}
int startX;
int startY;
int endX;
int endY;
move* next;
};
void listAdd(move * list, move * object, int width);
move possibleMoves[100];
move * endOfLists[100];
int main() {
int x = 0;
int y = 0;
int xOffset = 1;
int yOffset = 1;
int width = 0;
for (int i = 0; i < 100; i++) {
possibleMoves[i] = move();
endOfLists[i] = &possibleMoves[i];
}
if (possibleMoves[0].startX == -1) {
possibleMoves[0] = *(new move(x, y, x + xOffset, y + yOffset));
}else {
listAdd(endOfLists[width], new move(x, y, x + xOffset, y + yOffset), width);
}
void listAdd(move * list, move * object, int width) {
int count = 0;
while (list->next != nullptr)
{
count++;
list = (*list).next; //Go down the list until it reaches an item with nothing next.
}
std::cout << "\nCount: " << count << std::endl;
list->next = object;
endOfLists[width] = list->next;
}
NM the full code. You don't tell us what the initial width is, but assuming it's valid (that is -1<width<100), it doesn't matter. Look at what happens here (end of add function):
list->next = object;
At this point list is endOfLists[width]. Now, you properly set the next to the new object, so far so good.
But what now?
endOfLists[width] = list->next;
So the "head" pointer, saved in the global (why?) is bypassing what it originally pointed to (who has a proper next!) and points directly to a descendant, the new object with NULL next. I'm guessing this wasn't what you want:
Leaking memory 0 - at first static allocation, but this can quickly be dynamic if you call this function the way you did a lot.
The head pointer is still, at the end of the function, an object with NULL next. A new one indeed, but the next is still NULL - so the next call will perform the same actions.
Basically you're swapping the head pointers, while leaking memories. You want to either:
Set the object next first: object->next=endOfLists[width], and set the second line to let endOfLists[width]=object, kind of reversing the list.
Delete the second line, and leave the original head.
Also:
I can't see a good reason for globals
Why is the add function not a move method?
You need to make sure you delete all those new objects.
EDIT
I saw your addition - the first call will always return 0, since all initial objects have NULL nexts, even if you fix your code. You need two calls to the same index (width) at least twice to start testing this.
Graphical addendum
At the beginning we have 100 objects, stored in an array, all looking like this:
head->list->NULL
list here is the object pointed to by endOfLists at some index, and we call that pointer head. Now, we want to add the new object. We enter the addition function, with the first argument endOfLists[width], so this will be our list argument in the function itself.
We immediately skip the while (since our next is already NULL). Getting to the first line above, we now connect our head to the new object:
list->object->NULL
So in the array we have:
head->list->object->NULL
Again, head is the pointer stored in endOfLists[width]. Now we tell endOfLists[width] to swap the head to a different one, setting it equal to list->next, which is object. So how does our memory look like?
head->object->NULL
list->^
Both head (the array cell) and list point to object, and nothing points to list. There we go leaking. Next time we call the function with the updated cell, we will repeat the process, leaking object:
head-> object2->NULL
list->object->^
and so forth.
I've a problem that I could not resolve. I've thought many solutions but no one seems to work.
So that's my problem:
You're given n1, n2, .... nk LEGOs, each one with a even number of faces.
Every LEGO can be stacked up another one only if :
the upper LEGO has the same face of the LEGO under it;
the upper LEGO must have a number of faces that is less or equal to the number of faces of the LEGO under it.
In addition to this every face has an opposite face which is inserted by input after the first one;
example: LEGO1 - face1, face2, face3, face4 (face1 and face2 are opposites such as face3 and face4).
The problem asks to make the highest tower with these LEGOs using each LEGO only once.
The tower must have only 1 direction so it can go only from left to right or from bottom to the top.
Thanks a lot and sorry for my bad English :/
INPUT EXAMPLE:
Lego1 - f1, f2, f3, f4, f5, f6
Lego2- f33, f47, f98, f123
Lego3 - f4,f127
OUTPUT EXAMPLE:
2
Resembles a task I had long ago. Idea of the algorithm was:
put items (legos) in circular list (closed single-linked list);
make function which
in loop
takes next element from the list (deletes it)
recursively cals itself
inserts previously deleted element
advances to the next element
When list gets empty You have got one of possible lego sequences. Algorithm builds all possible seaquences using each list element only once.
Working code:
#include <stdio.h>
#define MAX 4
struct CList{
int d;
struct CList *next;
};
void search(struct CList *pstart);
void result(struct CList *v[MAX], const int nv);
int main(){
static struct CList lst[MAX];
struct CList *p = lst;
int i;
for( i = 0; i < MAX - 1; i++){
lst[i].d = i;
lst[i].next = lst + i + 1;
}
lst[MAX-1].d = MAX - 1;
lst[MAX-1].next = lst;
search( p );
return 0;
}
void search(struct CList *pstart){
struct CList *p, *pp;
static struct CList *v[MAX];
static int nv = 0;
if( pstart->next == pstart ){
v[nv++] = pstart;
result( v, nv );
nv--;
return;
}
nv++;
p = pstart;
do{
pp = p;
p = p->next;
v[nv-1] = p;
pp->next = p->next;
search( pp );
p->next = pp->next;
pp->next = p;
} while( p != pstart );
nv--;
}
void result(struct CList *v[MAX], const int nv){
int i;
for( i = 0; i < nv; i++ ){
printf(" %d ", v[i]->d);
}
puts( "" );
}
In Your case further optimization may be possible (for example breaking the recurson when current element dosn't stack).