I am using a library, RapidXML, but my problem is more general. The library parses xml like item->first_node("CRAP")->first_node("CRAP") Now, if I put this in an if statement it will crash. If I put this: item->first_node("CRAP") it won't.
I am a beginner in C++ and I don't know much about exceptions but:
try
{
if(item->first_node("CRAP")->first_node("CRAP"))
{
}
cout << "OK";
} catch (...)
{
cout << "CRASH";
}
The above crashes. How to check if my node exists without crashes (and without looping all the items one by one)?
You simply need to take it one step at a time:
if (item != 0) // check if item is null
{
rapidxml::xml_node<char>* node = item->first_node("CRAP"); // Try to grab first child node
if (node != 0)
{
// okay got a valid node, grab next one
rapidxml::xml_node<char>* next = node->first_node("CRAP");
if (next != 0)
{
// Okay
}
}
}
When you try it in one step, i.e. item->first_node("CRAP")->first_node("CRAP"), you never check that the first call to first_node returned a null pointer (assuming item is a valid pointer also).
Sounds like either item is NULL or item->first_node("CRAP") is returning NULL. Try this, see what output you get:
try
{
node *n; // <-- use whatever type first_node() actually returns
if (!item)
cout << "item is NULL";
else
{
n = item->first_node("CRAP");
if (!n)
cout << "first node is NULL";
else
{
n = n->first_node("CRAP");
if (!n)
cout << "second node is NULL";
else
cout << "OK";
}
}
}
catch (...)
{
cout << "CRASH";
}
Always test whether an expression is NULL before using it as part of a longer expression. Never write things like
if(item->first_node("CRAP")->first_node("CRAP"))
if first_node("CRAP") can return NULL. Instead, write something like
if(item->first_node("CRAP") && item->first_node("CRAP")->first_node("CRAP"))
This works because the '&&' (logical and) operator uses lazy evaluation: it won't bother to evaluate its second operand if the first one evaluates to false.
Related
I am facing a problem where I have a void function which prints out AVL tree node values using inorder traversal. However, I also need to print out "EMPTY" if the void function does not have any cout. And since the void function is recursive so I assume the cout << "EMPTY" << endl; can not be inside the function (Actually I tried but a lot of unncessary EMPTY were produced).My question is that is there any way I can check the program/function cout, something like: if(cout is empty){ print "EMPTY" }
void inorder(node* n){
if(n != NULL){
inorder(n->left);
cout << n->value << ' ';
inorder(n->right);
}
}
You can't query cout to find out whether it printed something or not. There actually is a method (tellp()) that returns the position of a std::basic_ostream stream (which is what cout is), but when called on cout is always returns -1, presumably because cout is not keeping track of the number of characters it has printed (aka its "position" within the output stream).
Therefore the only practical way to know if something was printed is to instrument your inorder() function to provide that information to the caller, via a return-value (as Retired Ninja suggests in the comments) or via some other mechanism (e.g. writing to a by-reference argument, or setting a global variable, or etc)
When you call inorder, it is guaranteed to produce some ouput if, and only if, its parameter is not NULL. So you can do this:
void inorderTraverse(node* n)
{
if (n == NULL)
std::cout << "EMPTY" << std::endl;
else
inorder(n);
}
Then, wherever you first call inorder, call inorderTraverse instead.
The way to do this is to have two functions:
one that the user calls, and which will print “EMPTY” if the tree is empty
one that does everything else
The common way to do this is with a “detail” namespace, but any other method for having a helper function would work as well:
namespace detail{
void inorder(node* n){
if(n != NULL){
inorder(n->left);
std::cout << n->value << ' ';
inorder(n->right);
}
}
}
void inorder(node* n){
if(n) detail::inorder(n);
else std::cout << "EMPTY";
}
Another common way of doing this is having an additional, defaulted-argument (boolean, in this case) to indicate whether or not it is a toplevel invocation:
void inorder(node* n, bool is_top=true){
if (n != NULL){
inorder(n->left, false);
std::cout << n->value << ' ';
inorder(n->right, false);
}else if(is_top){
std::cout << "EMPTY";
}
}
I personally do not like flaggy code, though — the helper function is an old, recognizable idiom and avoids the overhead of the boolean tests at every leaf node.
I've been trying to write my own implementation of linked list, but the code segfaults when I try to access an the third element or anything after it. Adding elements doesn't segfault, but accessing does. I can't find the pointer error in my get() function.
Each node in the list stores data (of Template t) and a pointer leading to the next node. I have two functions for everything- one for the first element, and one for any subsequent elements. The get() function for the subsequent elements always segfaults. I have some debug messages in the function that spit out results I can't explain. For example, if I run a get() request for the second element, an then the third, the code doesn't segfault, but it does return clearly incorrect results. Debug messages I placed indicate the segfault occurs when the second element calls the function to check the third element, if it occurs at all. Try the code with and without the line cout << newList.get(2) << endl; and you'll get very different results.
One possible cause is the pointer storage- I have the get() function output the pointer of each element (except the first) as it cycles through, and compare them to the pointers outputted by the add() function, and and pointers for element 0 and 1 match, but 2 and beyond do not match, and I can't seem to figure out why that would be.
#include <iostream>
using namespace std;
template <class T> class myLinkedList{
T data;
myLinkedList<T> *next = NULL;
public:
myLinkedList(T input){
data = input;
}
void add(T input){
if(next == NULL){
myLinkedList<T> newItem(input);
next = &newItem;
cout << "adding to list, data is " << input << ", pointer is " << next << endl;
}else{
myLinkedList<T> nextEntry = *next;
nextEntry.add(input);
}
}
T getData(){
return data;
}
//the start of the get function, only used by the first entry in the list
T get(int entry){
int currentPosition = 0;
if(entry == currentPosition){
return getData();
}else{
//defrefrence the pointer anc check the next entry
myLinkedList<T> nextEntry = *next;
return nextEntry.get(entry, ++currentPosition);
}
}
private:
//this vesion is the hidden, private vesion only used by nodes other than the first one
//used to keep track of position in the list
T get(int entry, int currentPosition){
//cout << currentPosition << endl;
if(entry == currentPosition){
return data;
}else{
//derefrence the pointer and check the next entry
cout << next << endl;
myLinkedList<T> nextEntry = *next;
currentPosition++;
T output = nextEntry.get(entry, currentPosition);
return output;
}
}
};
int main(){
myLinkedList<int> newList(3);
newList.add(4);
newList.add(5);
newList.add(7);
newList.add(9);
cout << newList.get(2) << endl;
cout << newList.get(3) << endl;
return 0;
}
Results are clearly erroneous- program should spit oout two macthing sets of pointers, as well as the numbers 5 and 7 ( the list elements)
One of your main problems is here:
if(next == NULL){
myLinkedList<T> newItem(input); // <<<<<<<<<<<<<
next = &newItem;
cout << "adding to list, data is " << input << ", pointer is " << next << endl;
}
you allocate an item on stack inside the if scope. Then you make next to point to this item. But... lifetime of the item is bounded by this scope. As son as you exit the scope, this item does not exist any longer. You need to allocate it dynamically by 'new' or other methods.
I had a breakthrough! Following Serge's solution was helpful, but one more change was needed- rather than create a function reference in the else block of my add function,
eg
myLinkedList<T> nextEntry = *next;
nextEntry.add(input)
i needed to use the pointer directly, as in
next->add(input)
I didn't know my pointer/object syntax
I having a problem getting my code to throw runtime errors as well getting these loops to work properly, and I'm not sure why.
If the user were to enter a name and balance, for example: josh 100, the program should add 100 to the account named josh in listAccounts vector, and then print the new balance.
something about the line: for ( ; iter != listAccounts.end(); iter++) {
For some reason it's causing the if statements to not work, if I comment out that line the function works but only with the last element in listAccounts. Is something wrong with the for loop that is causing it to not step through each element?
void Account::change_balance(string name, int balance, int i) {
try {
auto iter = listAccounts.begin();
for ( ; iter != listAccounts.end(); iter++) {
if ((*iter).account_name == name) {
if (((*iter).account_type == 0) && (((*iter).account_balance +
balance) < 0)) {
throw runtime_error("account cannot hold negative
balance");
(*iter).account_balance = (((*iter).account_balance) -
(balance));
cout << (*iter).account_balance;
} else {
(*iter).account_balance = balance +
(*iter).account_balance;
cout << (*iter).account_balance;
}
}
}
}
catch (runtime_error& e) {
cout << "error on line " << i << ": " << e.what() << "\n";
}
}
I can't figure out where I have gone wrong, any indication would be much appreciated. Thanks.
Check your inner for-loop. You never increase the iterator, all you do is comparing listAccounts.size() times the same element of the vector with the function argument. As the loops ends when k == listAccounts.size(), the condition n == listAccounts.size() can only be fulfilled when the outer loop goes for at least another run, because you did not clear n (or defined it locally). But now, it may fire and say "Account not found" even though it is there, because n == listAccounts.size(). This is not the behaviour your intended.
You should rethink your algorithm. Why do you traverse all the accounts each time you traverse the list of accounts? It would be totally sufficient to do it once. Consider doing something like this:
for(auto& account : listAccounts) {
if(account.account_name == name) {
// do your logic stuff and eventually:
return;
}
}
// if your program gets here, no account with such a name was found
below is a searchVal function for searching a value in a binary tree. nodes of binary tree are stored in a vector nodeVec with first object in vector as root.
structure of nodes
class bst{
public:
//other functions..//
int searchVal(int)
private:
bst *lLink;
int info;
bst *rLink;
}
calling part in main
cout << "Enter Value to search ";
int val;
cin >> val;
int ret = nodeVec[0].searchVal(val);
if (ret == 2)
cout << "Value Not Found" << endl << endl;
else
cout << "Value Found" << endl << endl;
Function
int bst::searchVal(int val)
{
if (info != val)
{
if (info > val)
{
if (lLink != NULL)
lLink->searchVal(val);
else
return 2;
}
if (info < val)
{
if (rLink != NULL)
rLink->searchVal(val);
else
return 2;
}
}
if (info == val)
return 1;
}
while debugging (using codeBlocks) i observed that after any condition is met for example if the condition info==val is met the execution pointer (arrow in the IDE pointing to line being processed) goes to end of searchVal and after that it go to nearest if(from the end) however it does not go into the block of that condition. It always returns the info stored in root node in ret not 1 or 2
Should be
if(lLink!=NULL)
return lLink->searchVal(val);
^^^^^^
I think the major problem in your code is that you're not returning the result of the sub-tree searches; i.e. you should be doing this:
if(lLink!=NULL)
return lLink->searchVal(val);
You're missing the return keyword. That means that some execution paths go all the way through to the end of the function, and never hit a return, which is potentially very bad. The compiler should be issuing an error or warning about that though.
The searchVal function needs a return value on every code path - everything else has undefined behaviour (which means that anything could happen).
Add a return to your calls to lLink->searchVal and rLink->searchVal.
(And if your compiler didn't warn you about this, you need to enable that warning.)
I cannot seem to get my try/catch to work correctly. When you implement a try/catch, it's suppose to "throw" whatever string you told it to, right? And if you want, let the program continue on. Well mine does not say what I want it to say, nor does it continue, instead it tells me this then aborts:
Debug Error!! Blah blah blah.exe
R6010 -abort() has been called (Press Retry to debug the app)
I want it to say: "You are trying to add more Items than are allowed. Don't. ", then continue on with the program. It's a LinkedList, it's not suppose to allow it to have more than 30 nodes. It does stop when it tries to add more than 30, just not how I want it to. I'm not sure what I'm doing wrong, help much appreciated!
Main:
Collection<int> list;
for(int count=0; count < 31; count++)
{
try
{
list.addItem(count);
cout << count << endl;
}
catch(string *exceptionString)
{
cout << exceptionString;
cout << "Error";
}
}
cout << "End of Program.\n";
Collection.h:
template<class T>
void Collection<T>::addItem(T num)
{
ListNode<T> *newNode;
ListNode<T> *nodePtr;
ListNode<T> *previousNode = NULL;
const std::string throwStr = "You are trying to add more Items than are allowed. Don't. ";
// If Collection has 30 Items, add no more.
if(size == 30)
{
throw(throwStr);
}
else
{}// Do nothing.
// Allocate a new node and store num there.
newNode = new ListNode<T>;
newNode->item = num;
++size;
// Rest of code for making new nodes/inserting in proper order
// Placing position, etc etc.
}
You're throwing a string, but trying to catch a pointer to a string.
Change your try/catch block to this:
try
{
...
}
catch( const string& exceptionString )
{
cout << exceptionString;
}
The reason you're getting that abort message is because you're not "catching" a type that is compatible with what you're throwing, so the exception is just bypassing your catch and is therefore an "uncaught exception", subject to the default underlying exception handler, which calls abort.
FYI a more standard way is to throw/catch a std::exception object. i.e.
try
{
...
}
catch( std::exception& e )
{
std::cout << e.what();
}
...
throw( std::logic_error("You are trying to add more Items than are allowed. Don't.") );