c++ making an array null using foreach - c++

Node* nodes[3];
for (Node* eachNode:nodes) {
eachNode = 0; //if i try to dereference it gives seg fault
} // eg. *eachNode = 0;
if (nodes[0] == 0) {
cout << "Null";
} else
cout << "Not null";
cout << '\n';
Node* nodes2[3];
for (int i = 0; i < 3; ++i) { //this way works fine
nodes2[i] = 0;
}
if (nodes2[0] == 0) {
cout << "Null";
} else
cout << "Not null";
Hi guys I am trying to make all my objects in an array equal to null. When using a for loop it works fine but when I use a foreach loop it breaks.
The output i get is
Not null
Null
I think i have to dereference the nodes in the foreach loop but it gives a seg fault.
Does anyone know whats wrong? thanks.

The loop you wrote loops over the values of the array:
for (Node* eachNode:nodes) {
eachNode = 0;
}
The above loop could as well have been written using auto:
for (auto eachNode:nodes) {
eachNode = 0;
}
The problem with the above loops is that eachNode is not the pointer stored in the array, but a copy of that pointer stored in a local variable of the loop.
If you wish to set the node to null, you need a reference to the memory location where you want to set it. You get that reference by referring to the array element using auto&:
for (auto& eachNode:nodes) {
eachNode = 0;
}
This last segment will likely do what you want.

I believe instead you should try:
for(Node *&eachNode : nodes) {
eachNode = nullptr;
}
This way you get a reference as opposed to the value, and you can appropriately set it to nullptr.
I'm not super experienced in C++ 11, but I did have a read here for more information about this new range construct.

Pointers are passed by value. So setting the eachNode = 0; will change the value, otherwise you are trying to dereference sonething that isn’t a pointer.

Related

Why does this function give me a segmentation fault?

I am currently trying to create a linked list which has two elements, usernames and seconds. It is supposed to read from a file and save it into two vectors.
I'm not sure why, but when I attempt to collect the data and store it into a linked list, I get a segmentation fault.
I'm kind of in a rutt, I feel like this should work.
Here is my code for main.cpp:
// main.cpp
int main() {
//Collect initial leaderboard data into two parallel vectors
cout << "here";
vector<string> playerNames;
vector<unsigned> playerTimes;
collect_data(playerNames, playerTimes);
cout << "here";
//Create a LeaderBoard object based on the data in the parallel vectors
LeaderBoard players(playerNames, playerTimes);
cout << "Initial leaderboard from https://www.speedrun.com/ac#All_Debts\n";
players.display();
cout << endl;
return 0;
}
//Leaderboard.cpp
LeaderBoard :: LeaderBoard(const vector<string>& usernames, const vector<unsigned>& second) //Combines both vectors to linked list;
{
for (int i = 0; i < usernames.size(); i++)
{
nPlayers_ ++;
Player *ptr = new Player;
ptr = nullptr;
ptr->username = usernames[i];
ptr->seconds = second[i];
if (head_ == nullptr)
{
head_ = ptr;
tail_ = ptr;
}
else
{
while (tail_-> next != nullptr)
{
tail_ = tail_ -> next;
}
tail_->next = ptr;
tail_ = ptr;
}
}
}
Can someone help me, or lead me towards the right direction?
In this part
Player *ptr = new Player;
ptr = nullptr;
ptr->username = usernames[i];
ptr->seconds = second[i];
You are overwriting the pointer to newly created object by nullptr, then dereferencing the nullptr. This will lead to memory leak and Segmentation Fault.
The line
ptr = nullptr;
should be removed from here.
Also it seems you forgot to initialize ptr->next.
ptr->next = nullptr;
should be added after that part.
This code presents some issues.
First of all, you might ditch heap allocation on each iteration of the for loop, using only once the allocation, before entering the loop. This prevents errors such as:
Player *ptr = new Player;
ptr = nullptr;
which causes segmentation fault in your code.
Another problem might be that head_ and tail_ might also be nullptr, so you have to check carefully about both.
You are allocating something on the heap, without caring about deleting the data later.
Why don't you use a std::vectorstd::unique_ptr<Player> to collect all the player scores, so at the end of the program, everything will be deleted?
//Assuming there's a vector like this in Leaderboard.h:
#include <memory>
std::vector<std::unique_ptr<Player>> players_{};
//Leaderboard.cpp
LeaderBoard::LeaderBoard(const vector<string>& usernames, const vector<unsigned>& second) //Combines both vectors to a final list;
{
for (int i = 0; i < usernames.size(); i++)
{
Player p{};
p.username = usernames[i];
p.seconds = second[i];
players_.emplace_back(std::move(Player));
}
}
In this way, you ditch tricky pointer handling problems, allocation problems, segmentation fault all together. As nice result, you have a vector that can be used with a broad range of algorithms

Skip List C++ segmentation fault

I'm trying to implement the Skip List using this article Skip List.
Code:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<limits>
using namespace std;
template<class T>
class SkipList{
private:
class SkipNode{
public:
T* key; //Pointer to the key
SkipNode** forward; //Forward nodes array
int level; //Node level
//SkipNode constructor
SkipNode(T* key, int maxlvl, int lvl){
forward = new SkipNode*[maxlvl];
this->key=key;
level=lvl;
}
//Method that print key and level node
print(){
cout << "(" << *key << "," << level << ") ";
}
};
SkipNode *header,*NIL; //Root and End pointers
float probability; //Level rate
int level; //Current list level
int MaxLevel; //Maximum list levels number
//Function that returns a random level between 0 and MaxLevel-1
int randomLevel(){
int lvl = 0;
while( (float(rand())/RAND_MAX < probability) && (lvl < MaxLevel-1) )
lvl++;
return lvl;
}
public:
//SkipList constructor
SkipList(float probability, int maxlvl){
this->probability = probability;
MaxLevel = maxlvl;
srand(time(0));
header=new SkipNode(NULL,MaxLevel,0); //Header initialization
T* maxValue = new T;
*maxValue = numeric_limits<T>::max(); //Assign max value that T can reach
NIL = new SkipNode(maxValue,0,0); //NIL initialization
level=0; //First level
for(int i=0; i<MaxLevel; i++){ //Every header forward node points to NIL
header->forward[i]=NIL;
}
}
//SkipList destructor
~SkipList(){
delete header;
delete NIL;
}
//Method that search for a key in the list
SkipNode* search(T* key){
SkipNode* cursor = header;
//Scan the list
for(int i=level; i>=0; i--)
while(*(cursor->forward[i]->key) < (*key))
cursor=cursor->forward[i];
cursor=cursor->forward[0];
if(*(cursor->key) == *key)
return cursor;
return NULL;
}
//Method that insert a key in the list
SkipList* insert(T* key){
SkipNode* cursor = header;
SkipNode* update[MaxLevel]; //Support array used for fixing pointers
//Scan the list
for(int i=level; i>=0; i--){
while(*(cursor->forward[i]->key) < *(key))
cursor=cursor->forward[i];
update[i]=cursor;
}
cursor=cursor->forward[0];
if(*(cursor->key) == *(key)){ //Node already inserted
return this;
}
int lvl = randomLevel(); //New node random level
if(lvl > level){ //Adding missing levels
for(int i=level+1; i<=lvl; i++)
update[i]=header;
level=lvl;
}
SkipNode* x = new SkipNode(key,MaxLevel,lvl); //New node creation
for(int i=0; i<=lvl; i++){ //Fixing pointers
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
return this;
}
//Method that delete a key in the list
SkipList* erase(T* key){
SkipNode* cursor = header;
SkipNode* update[MaxLevel]; //Support array used for fixing pointers
//Scan the list
for(int i=level; i>=0; i--){
while(*(cursor->forward[i]->key) < *(key))
cursor=cursor->forward[i];
update[i]=cursor;
}
cursor=cursor->forward[0];
if(*(cursor->key) == *(key)){ //Deletetion of the founded key
for(int i=0; i<=level && update[i]->forward[i] == cursor; i++){
update[i]->forward[i] = cursor->forward[i];
}
delete cursor;
while(level>0 && header->forward[level]==NIL){
level=level-1;
}
}
return this;
}
//Method that print every key with his level
SkipList* print(){
SkipNode* cursor = header->forward[0];
int i=1;
while (cursor != NIL) {
cursor->print();
cursor = cursor->forward[0];
if(i%15==0) cout << endl; i++;
}
cout << endl;
return this;
}
};
main(){
SkipList<int>* list = new SkipList<int>(0.80, 8);
int v[100];
for(int i=0; i<100; i++){
v[i]=rand()%100;
list->insert(&v[i]);
}
list->print();
cout << endl << "Deleting ";
for(int i=0; i<10; i++){
int h = rand()%100;
cout << v[h] << " ";
list->erase(&v[h]);
}
cout << endl;
list->print();
cout << endl;
for(int i=0; i<10; i++){
int h = rand()%100;
cout << v[h] << " ";
if(list->search(&v[h]))
cout << " is in the list" << endl;
else
cout << " isn't in the list" << endl;
}
delete list;
}
It gives me Segmentation Fault on line 59 (the for-cycle on the insert), but I can't understand why. May you help me please? I will accept any other improvement that you suggest. My deadline is on two days, that's why I'm asking for help.
EDIT:
I've corrected the code with bebidek suggestions (Thanks). Now first level is 0. It seems to be working, but sometimes some nodes is not inserted correctly and the search give a bad result.
LAST EDIT:
It works, thanks to all
ONE MORE EDIT:
Added comments to code, if you have any suggestion you're welcome
The biggest problem in your code is probably NIL=new SkipNode(numeric_limits<T*>::max());
First of all i suspect you want the key pointer to point to a memory address that contains the biggest possible int value.
But that's not what's actually happening here. Instead the key pointer points to the biggest possible memory-address which is most likely not available for your process.
Also the forward property probably contains an array of junk pointers.
Then when the first loop in the insert method is executed this leads to 2 problems:
while(*(cursor->forward[i]->key) < *(key)) will compare the key value to an invalid pointer
cursor=cursor->forward[i]; will re-assign cursor to an invalid pointer
I would first suggest you'd change the design to let SkipNode keep a value to T instead of a pointer:
class SkipNode{
public:
T key;
SkipNode* forward[100];
This will make a lot of pointer related code unnecessary and make the code simpler so less likely to run into access violation.
Also it might be cleaner to use an actual NULL (or event better nullptr) value instead of a dummy NIL value to indicate the end of the list.
So, first problem is when you create NIL node:
NIL=new SkipNode(numeric_limits<T*>::max());
As argument you should use pointer to existing variable, for example:
T* some_name = new T;
*some_name = numeric_limits<T>::max();
NIL = new SkipNode(some_name);
Notice, I used T instead of T* in numeric_limits. Of course you have to remember about deleting this variable in destructor.
Second problem is that level variable in your code sometimes is inclusive (I mean level number level exists) as in line 61, and sometimes exclusive (level number level doesn't exist) as in line 71. You have to be consistent.
Third problem is in line 52. You probably mean cursor=cursor->forward[1];, but after loop i = 0, and forward[0] doesn't have any sense in your code.
EDIT:
Fourth and fifth problem is in erase function.
cursor->~SkipNode();
It won't delete your node, but only run empty destructor. Use delete cursor; instead.
And in loop you probably wanted to write update[i]->forward[i] == cursor instead of !=.
ONE MORE EDIT:
You haven't implemented any destructor of SkipList and also you forgot about delete list; at the end of main(). These two will give you a memory leak.
ANOTHER EDIT:
srand(time(0));
This line should be executed once at the beginning of main and that's all. If you execute it before each random generation, you will get the same result every time (as time(0) counts only seconds and your program can run function randomLevel() more than once a second).
You also forgot about rewriting precision variable in constructor of SkipList.
NEXT EDIT:
In your insert function you don't have level randomization. I mean, you do not have ability of inserting node of level less than level of whole skip list. It's not error which will crash your program or give wrong results, but time complexity of queries in your structure is O(n) instead of O(log n).
You should use lvl instead of level in this loop in insert function:
for(int i=1; i<level; i++){
x->forward[i] = update[i]->forward[i];
update[i]->forward[i] = x;
}
And also minimum result of your random function randomLevel should be 1 instead of 0, as you don't want node witch level=0.

Return statement breaking my function c++

So I call a function in main:
B.remove()
Which goes here
m_arrays[m_oldest]->remove()
Then finally here:
int MyClass::remove() {
cout << "this is the remove function"<< endl; //debugging line
int lastVal = 0;
for (int i = start; i < capacity; i++) { //actual remove function
if (m_array[i] != NULL) {
int lastVal = m_array[i];
m_array[i] = NULL; // sets to null
m_size--; //increment
break;
}
}
m_start++; //increment
return lastVal;
}
If I remove the code containing lastVal, the function works properly. Why is this? Is there an easy way to fix this?
As you can see I'm attempting to return a value before removing it from the array. I am aware I should be using vector or some other standard method, but I cannot. I looked in my textbook but I couldn't find what I was looking for. Any help is greatly appreciated.
You have two int lastVal statements in your code - one before the for loop and one in it. Try removing the declaration inside the for loop (and set it to the assignment lastVal = m_array[i];) and see if it works.

Segmentation Error C++

I am fairly new to the C++ language and I am trying to write a recursive method to traverse a tree. I have a traverse method but there is one line of code that causes a segmentation fault. I have tested this by commenting and uncommenting the line, compiling and executing. I have researched why segmentation errors are caused and do not see why any of what I am doing is causing a problem with the memory. Can someone give me advice about what I am doing wrong?
map<int, Node> theNodes;
void initialize()
{
// first we read the data
while (inStream.hasNext())
{
string nextLine = inStream.nextLine();
Node newNode = Node(nextLine);
this->theNodes[newNode.getSequence()] = newNode;
}
}
Code for getDownLinks() and getSequence
vector<int> downLinks;
int sequence;
vector<int> Node::getDownLinks() const
{
return this->downLinks; //
}
int Node::getSequence() const
{
return this->sequence;
}
Traversal Class Code
int totalPayoff;
Node headNode;
int Traversal::traverse()
{
Node headNode = theNodes[0];
std::vector<int> downLinks = headNode.getDownLinks();
for(int i = 0; i < downLinks.size(); i++)
{
int a = 0;
Node currentNode = theNodes[downLinks[i]];
traverseInner(a, currentNode);
}
return this->totalPayoff;
}
Here is the traverseInner function
int Traversal::traverseInner(int& level, Node& node)
{
std::vector<int> nodeDownLinks = node.getDownLinks();
if(nodeDownLinks.size() == 0)
{
totalPayoff = totalPayoff + node.getPayoff();
return 0;
}
for(int i = 0; i < nodeDownLinks.size(); i++)
{
int a = 0;
Node currentNode = theNodes[nodeDownLinks[i]]; <-- This causes segmentation error.
traverseInner(a, currentNode);
}
return totalPayoff;
}
Any variables that are not declared here are declared in the header file. The code compiles fine.
I'd also like to mention that I have written this code in many different ways and through my observations have come to the conclusion that any variable that is trying to be accessed in the braces of a nested statement cannot be accessed by the memory. Even the int a variable that is declared right above the problem statement and even hard coded data which is supposed to be there such as nodeDownLinks. If I try to print out through standard output the size of the vector inside one of the nested statements, I also get a segmentation error.
Probably the value inside "nodeDownLinks[i]" it is not initialized, having a memory random value, then you are trying to access this position in the
"theNodes" array and gives to you the segmentation fault.
Please, be sure the values inside "nodeDownLinks" are initialized.
99% it crashes because theNodes has less size, then nodeDownLinks[i] contains index. So nodeDownLinks[i] contains wrong index, u'd better check it and print what goes wrong this way:
int a = 0;
int link = nodeDownLinks[i];
if (theNodes.size() <= link)
std::err << "Wrong link " << link << " in Node" << std::endl;
else
traverseInner(a, theNodes[link]);
It shouldnt crash and you can find wrong index in nodeDownLink easily!

Changing vector value causing seg fault

I am working on a school project for graphs and here I am doing a depth first search down the tree.
void wdigraph::depth_first(int v) const {
static int firstv = -1;
static bool *visited = NULL;
if (firstv == -1) {
firstv = v;
vector<bool> visited(size);
for (int i = 0; i < size; i++) {
visited[i] = false;
cout << visited[i] << endl;
}
}
cout << label[v];
visited[v] = true;
// visited[0] = true;
The first input value to the function is 0 (v = 0) and it crashes with that. size = 5. As you can see at the end of the code, I have tried to set visited to true manually with the same seg fault. When I remove all attempts to change visited, the program runs how it should normally without a seg fault.
Any ideas why this can't be modified? Also, there is more code but I have decided not to provide it unless necessary.
There are two different variables named visited in your code. Inside the if condition, visited is a vector, but outside this block, on the last line:
visited[v] = true;
visited refers to the bool *visited = NULL defined at the beginning of your code. The segfault occurs because you're trying to dereference a null pointer.