Welcome to SO.
If you say that your program "crashes", you should also say how it crashes
and if possible quote the exact output that shows how it is crashing. Many
people who might be able to help will not bother if they have to work
out what the problem really is as well as solve it.
If your question is about a coding problem, like yours, it is also important
to tag your question with the name of the programming language you are
coding in - in your case C++. If you don't, then most C++ programmers who
could help will simply never notice your question. (I have now tagged your
question C++.)
And if you are programming in a compiled language, like C++, it is also
helpful to say what compiler you are using, and what version of that compiler,
- e.g. "GCC 4.7.2", "MS VC++ 2012" - because then programmers can try to
reproduce the problem using the same one. It is quite common for coding
problems to be in some way dependent on the compiler or compiler version being
used.
I have built your program with GCC 4.7.2 and clang 3.2 on Linux and it executes the test
case that you have given with no problems when I enter the input lines from
the console.
This leaves me to speculate what you mean when you say it "crashes", and this
is what I speculate:
I think you may mean that after you enter "6", the program terminates with
an error diagnostic something like:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Aborted
If I am wrong about that, feel free to stop reading now.
If I am right about that, then the diagnostic is telling you that in your
call a.substr(j,a.size()-1)
, the index j
is out of range.
If j
is out of range at that point, then it must have got out of range as
a result of the preceding line j=a.find(" on ")
. And that can only mean
that a.find(" on ")
failed to find " on "
at any place in a
.
Look up the documentation of std::string::find
, e.g.
here
and read about the returned value:
If no matches were found, the function returns string::npos.
which is (size_t)-1
, and is assuredly out of range.
Next, if a.find(" on ")
is failing, that can only mean that the
preceding line getline(cin,a)
is failing at that point to read a line from cin
that
contains " on "
. And we know that is true! Because you say that the program
crashes right after it has read "6" and printed the required newline.
So that getline(cin,a)
must be reading a line from the console after the
"6" but before "Begin on Old Madras Road". An empty line. And that is what
it would do if you happened to press [Enter]
just a bit too long when
entering the "6", so that the keyboard buffer contains "6\n\n", or maybe
"6\n\n\n", instead of just "6\n". Your call to cin.ignore()
, after reading
the integer, will consume only one following character, because you are
accepting the default arguments of:
std::istream& std::istream::ignore(std::streamsize n = 1, int delim = EOF)
As I say, your program works fine for me. But I can make it crash in the
way I described by pressing [Enter]
either too long when I enter the test
case line-count - either the first time or the second time - or by pressing
[Enter]
again after I have done so. Either way, I am inputting an empty line
to getline(cin,a)
.
If I am right so far, then a serious error in your code is that you are not
checking that std::string::find()
is successful on an input string and just
assuming that it is. Even if I am not right, that is serious error.
You can stop your program from crashing when the user's finger stays too
long on [Enter]
by ensuring that cin
ignores all the newlines it can
read after cin>>n
. You must look at the next character, if any,
without extracting it; check if it is a newline, and if it is then extract it
and repeat. Replace cin.ignore()
with:
for ( ;cin.peek() == '\n'; cin.ignore()){}
However this will not prevent your program from crashing in the same way if the
user happens to mistakenly enter a route-line that does not contain " on "
:
try it with "Left On Domlur Flyover".
To fix this bug you must check that j=a.find(" on ")
is successful and
handle the situation when it is not. Here is complete fix for what I think is the problem, built with GCC 4.7.2
and clang 3.2:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
vector <string> dr,rd;
string a,b;
size_t i,j,n;
cin>>n;
for ( ;cin.peek() == '\n'; cin.ignore()){}
for(i=0;i<n;i++)
{
a.clear(),b.clear();
getline(cin,a);
j=a.find(" on ");
if (j == string::npos) {
cout << "Invalid direction. Try again" << endl;
--i;
continue;
}
b=a.substr(j,a.size()-1);
a.resize(j);
dr.push_back(a);
rd.push_back(b);
}
for(i=0,j=rd.size()-1;i<rd.size();i++,j--)
{
cout<<dr[i]<<rd[j]<<endl;
}
cout<<endl;
}
return 0;
}
Notice I have also corrected a couple of minor defects:-
No need for any global variables. It is good practice to avoid globals
if possible and to declare variables in the smallest possible scope.
I have changed the type of i,j,n
from int
to size_t
. Variables
that used to hold the return value of some_class::some_method()
or the
return value of some_function()
, or are compared with that return value,
are best declared with the same type as that return value to avoid bugs and
compiler warnings: string::find()
and vector::size()
return size_t
,
which is not the same as int
.
P.S. Investigate what goes wrong, either with your original program or
mine, if the user mistakenly enters one of the integer inputs as, say,
"y" or "6y" instead of "6". How could you fix that?