I'm trying to find a TreeNode with a certain Name inside my Treeview.
For that, I want to use the Find function.
The problem is every time I try to access the Array I get the IndexOutOfRange exception.
When debugging, I can see that the index im accessing has a value in it.
if (!form->treeView1->Nodes->Find(gcnew String(primary.c_str()), false))
{
std::cout << "NoValue" << std::endl;
}
else
{
System::Windows::Forms::TreeNode^ prima = form->treeView1->Nodes->Find(gcnew String(primary.c_str()), true)[0];
prima->Nodes->Add(second);
}
Here you can see the Debug I did. I put the Breakpoint at the prima variable where the array that the Find function is returning is accessed.
Related
I was given an exercise to debug a short linked list program, and while I've fixed it to have it behave correctly both with and without the debugger, there is a scenario which I can't wrap my head around from when I was debugging.
The following code fragment traverses and displays the contents of the linked list.
while ( p_itr != NULL )
{
cout << p_itr->val << endl;
p_itr = p_itr->p_next;
delete p_itr;
}
Now, here's the strange thing: when I delete p_itr (pointer to the head of the list), shouldn't I lose the linkage to the rest of my list or dereference invalid memory during the subsequent iteration?
When I run the program normally, it displays all the linked list elements perfectly fine and returns normally (doesn't hang) -- when I use the debugger it gets stuck in an infinite loop, printing a pattern of irrelevant values.
For example, when I add the elements 2, 2, and 2 to the list:
Normal Execution Output:
Output:
2
2
2
Debugger Output (after holding down the "next line" key):
2
14166872
14166808
14161464
14155968
14167352
14166872
14166808...
Why does the normal program execute successfully? But I my main question is, why does the debugger fall into an infinite loop with these values and the normal program doesn't?
I am using Code::Blocks 16.01.
This code snippet
while ( p_itr != NULL )
{
cout << p_itr->val << endl;
p_itr = p_itr->p_next;
delete p_itr;
}
has undefined behaviour because except the first iteration of the loop there is access to the already deleted object.
It is not clear why the nodes are deleted when the list is outputed. Nevertheless the loop should look at least like
while ( p_itr != NULL )
{
cout << p_itr->val << endl;
auto tmp = p_itr;
p_itr = p_itr->p_next;
delete tmp;
}
Giving as simple of a background context as I possibly can, which I don't think is necessary for what I'm trying to figure out at the moment, I'm trying to implement a graph representation via adjacency list, in my case being an unordered map that has a string key to a struct value that contains Vertex object pointers (the object that is identified by the key), and a vector of its dependencies. The goal is to output a critical path via a sort of DAG resolution algorithm.
So when I need to output a critical path, I'm trying to use a recursive solution I implemented. Basically it looks for a base case (if a job has no dependencies), return a print out of its id, start time and length. Otherwise, find the longest running (in terms of time length) job in its dependency list and call the function on that until you find a job with no dependencies. There can be more than one critical path, and I don't have to print out all of them.
MY QUESTION: I'm debugging this at the moment, and it has no problem printing out a job's properties when its a base case. If it has to recurse through though, the string always comes back as empty (""). Is the recursive call making my string go out of scope by the time it comes back to the caller? Here is the code structure for it. All of the functions below are public members of the same Graph class.
string recurseDeps(unordered_map<string, Dependencies>& umcopy, string key) {
if (umcopy[key].deps.empty()) {
string depPath = " ";
string idarg, starg, larg, deparg;
idarg = key;
starg = " " + to_string(umcopy[key].jobatKey->getStart());
larg = " " + to_string(umcopy[key].jobatKey->getStart() + umcopy[key].jobatKey->getLength());
umcopy.erase(key);
return depPath + idarg + starg + larg;
}
else {
string lengthiestDep = umcopy[key].deps[0];
for (auto i = begin(umcopy[key].deps); i != end(umcopy[key].deps); i++) {
if (umcopy[*i].jobatKey->getLength() >
umcopy[lengthiestDep].jobatKey->getLength()) {
lengthiestDep = *i;
}
}
recurseDeps(umcopy, lengthiestDep);
}
}
string criticalPath(unordered_map<string, Dependencies>& um, vector<Vertex*> aj) {
unordered_map<string, Dependencies> alCopy = um;
string path = aj[0]->getId();
for (auto i = begin(aj); i != end(aj); i++) {
if (um[(*i)->getId()].jobatKey->getLength() >
um[path].jobatKey->getLength()) {
path = (*i)->getId();
}
}
return recurseDeps(alCopy, path);
}
Later on down in the class members, a function called readStream() calls the functions like so:
cout << time << criticalPath(adjList, activeJobs) << endl;
You're not returning the value when you recurse. You're making the recursive call, but discarding the value and just falling off the end of the function. You need to do:
return recurseDeps(umcopy, lengthiestDep);
First of all, to answer your question, since you return by value the string is copied so no need to worry about variables going out of scope.
Secondly, and a much bigger problem, is that not all paths of your recursive function actually returns a value, which will lead to undefined behavior. If your compiler doesn't already warn you about this, you should enable more warnings.
I've been having an issue with a game I've been making in my C++ game programming class for school. For some reason, after calling a function which I'm using to manage the inventory based stuff, the function seems to complete and work (I think this because I put in cout commands at the end of it and they printed correctly, also the function runs twice in a row, and they both run), my entire game crashes and doesn't reach the next line. I tried commenting out all the code in the function and it still crashed. I commented out the function calls and it worked, but I still can't tell what is wrong with it. I'll put the code for the function and the section were I make the calls:
string inventoryFunction(int h, string ab)
{
if(h == 1)
inventory.push_back(ab);
else
if(h == 2)
{
for(int i=0; i < inventory.size(); i++)
{
if(inventory[i] == ab)
inventory[i].erase();
}
}
else
if(h == 3)
{
cout << inventory[0];
for(int i=1; i < inventory.size(); i++)
cout << ", " << inventory[i];
}
}
The function call:
if(answer.find("village") != string::npos)
{
cout << endl;
cout << "While looking around your village,\nyou found a stone sword and a cracked wooden shield!" << endl;
inventoryFunction(1, "stone sword");
inventoryFunction(1, "cracked wooden shield");
cout << "Would you like to set off on your adventure now?" << endl;
cin >> answer2;
capitalizeLower(answer2);
Not sure there's anything there likely to cause a crash, my advice would be to single-step your code in the debugger to see where it's falling over. It's quite possible the bug is somewhere totally different and it's just being exacerbated by the function calls modifying the vector.
That's the nature of bugs unfortunately, you can never really tell where they're actually coming from without looking closely :-)
However, there are a couple of issues with the code that I'd like to point out.
First, with regard to:
inventory[i].erase();
That doesn't do what you think it does. inventory[i] is the string inside your vector so it's simply erasing the string contents.
If you want to remove the string from the vector, you need something like:
inventory.erase (inventory.begin() + i);
Second, I'd tend to have three separate functions for addToInventory, removeFromInventory and listInventory.
It seems a little ... unintuitive ... to have to remember the magic values for h to achieve what you want to do, and there's no real commonality in the three use cases other than access to the inventory vector (and that's not really reason enough to combine them into the same member function).
On top of that, your function appears to be returning a string but you have no actual return statements and, in fact, none of the three use cases of your function require anything to be passed back.
The signature is better off as:
void inventoryFunction(int h, string ab)
In terms of the second and third points above, I'd probably start with something like:
void addToInventory (string item) {
inventory.push_back(ab);
}
void removeFromInventory (string item) {
for (int i = 0; i < inventory.size(); i++) {
if (inventory[i] == ab) {
inventory.erase (inventory.begin() + i);
break;
}
}
void listInventory () {
cout << inventory[0];
for (int i = 1; i < inventory.size(); i++)
cout << ", " << inventory[i];
}
You may also want to look into using iterators exclusively for the second and third functions rather than manually iterating over the collection with i.
It'll save you some code and be more "C++ic", a C++ version of the "Pythonic" concept, a meme that I hope will catch on and make me famous :-)
So by changing the inventoryFunction to a void function like #Retired Ninja said, the crash has stopped occurring and now the program is working great.
Also, #paxdiablo pointed out that I was using the inventory[i].erase() thing incorrectly, so thanks a bunch to him, because now I won't have to come back on here later to try to fix that :D
string inventoryFunction(int h, string ab)
should return a string but does not have any return statements. Of course it works, after you change it to a void function, which correctly does not return anything. Interesting is, that you are able co compile this code without an error - normally a compiler would show you this problem.
I am creating a program that finds the shortest path from one vertex to another that is based upon a set and tables that keep track vertex information as well as the shortest paths from one vertex to another. This is created using an array, NOT a linked list.
//--------------------------------------------------------------------------
// 'updatepaths' uses the newest vertex which was added to the Set to modify
// the distances of the remaining vertices (if smaller)
// in addition to the newly added vertex, it uses the Set, the Vertexinfo
// and the Shortpath tables
//--------------------------------------------------------------------------
void Paths::updatepaths(int addnode)
{
if (done.in(addnode)) //done is a set instance, checks if the value is in the set
{
for (int i = 0; i<VERTICES; i++)
{
if (shortpath[edgedata[addnode].path[i].vertexto].distance > edgedata[addnode].path[i].weight) //HERE IS THE ISSUE
{
shortpath[edgedata[addnode].path[i].vertexto].distance = edgedata[addnode].path[i].weight;
shortpath[edgedata[addnode].path[i].vertexto].via = addnode;
}
}
}
}
I realize that the code is quite difficult to read, but it's the only way to compare vertex distances to one another that I can think of -- the issue is that in the if statement, sometimes it will try to compare values that don't exist in the array.
For example, edgedata[addnode].path[0].weight may contain NO VALUE - thus my program throws an access violation (segmentation fault). I tried setting edgedata[addnode].path[i].weight != NULL in the if statement as well as 0, but you cannot use NULL during arithmetic and it won't ever be 0 if it doesn't exist.
How should I make it so that it won't try to compare values that don't exist? Thanks for the help.
If your logic is regularly hitting NULL objects, there may likely be larger design or implementation issues in your code, but the easiest thing to do here to patch over your immediate problem is to use std::array<>::at(), instead of std::array<>::operator[], and catch the out_of_range exceptions it can generate:
try {
if (shortpath.at(edgedata.at(addnode).path.at(i).vertexto).distance >
edgedata.at(addnode).path.at(i).weight)
{
shortpath.at(edgedata.at(addnode).path.at(i).vertexto).distance =
edgedata.at(addnode).path.at(i).weight;
shortpath.at(edgedata.at(addnode).path.at(i).vertexto).via = addnode;
}
}
catch (std::out_of_range const &oor) {
std::cerr << "Out of Range error: " << oor.what() << std::endl;
}
Alternately, you can short-circuit checks in your if statement along these lines (I probably missed a check or two here, so watch out):
if ((edgedata.size() >= addnode)
&& (edgedata[addnode].path.size() >= i)
&& (shortpath.size() >= edgedata[addnode].path[i].vertexto)
&& (shortpath[edgedata[addnode].path[i].vertexto].distance >
edgedata[addnode].path[i].weight))
{
shortpath[edgedata[addnode].path[i].vertexto].distance =
edgedata[addnode].path[i].weight;
shortpath[edgedata[addnode].path[i].vertexto].via = addnode;
}
When you write c++ code, you shoud use the c++ coding style firstly. For example, you can use the std::vector instead of array, then you shoud use the iterator to access the element of vector or use vec.at(i) because this two methods can check the boundary exceeded, In c,it has no way to do so
I have to code a method of a class in C++ that shows me all the attributes of a class when they give me only the name. For example, I have a class 'Team' with a_name, a_goals and a_points. So when they give me a string with the name, I have to compare it to my dynamic structure and find the team with the same name to show it. I have this code:
void Classificacio::mostrar(string nom) const {
Equip eq;
Node* i=a_inici;
bool trobat=false;
while(!trobat && i!=NULL) {
if(nom.compare(i->a_equip.NomEquip())==0) trobat=true;
else i=i->seg;
}
if(trobat==true) eq=i->a_equip;
cout << eq << endl;
}
NomEquip() is a method that returns the team name.
But it doesn't work. Every time I try to execute it with the debugger, it stops in the line with the if. Any ideas what I'm doing wrong?
EDIT: Wanted to translate it to english but I forgot some things, just copy/pasted it this time.
There is a possibility of crashing in the line:
if (trobat == true) eq=i->a_equip;
Because you check for 'i!=NULLin thewhileloop. One of the terminating conditions of thewhileloop is thati == NULL`.
Assuming the while loop was terminated because i == NULL, your if statement will dereference a NULL pointer which is undefined behavior.
Edit 1:
If it crashes at if (nom.compare(i->a_equip.NomEquip()) == 0), and we know i is valid, it leads that the NomEquip function is a leading culprint.
Change your while loop to:
while (...)
{
std::string nom_equip = i->a_equip.NomEquip();
if (nom == nom_equip)
//...
}
Now place breakpoint at the std::string line and step into the function to trace it.