As part of a homework assignment I need to be able to take an input string and manipulate it several ways using a list of string functions. The first function takes a string and reverses it using a for loop. This is what I have:
#include <iostream>
#include <string>
namespace hw06
{
typedef std::string::size_type size_type;
//reverse function
std::string reverse( const std::string str );
}
// Program execution begins here.
int main()
{
std::string inputStr;
std::cout << "Enter a string: ";
std::getline( std::cin, inputStr );
std::cout << "Reversed: " << hw06::reverse( inputStr )
<< std::endl;
return 0;
}
//reverse function definition
std::string hw06::reverse( const std::string str )
{
std::string reverseStr = "";
//i starts as the last digit in the input. It outputs its current
//character to the return value "tempStr", then goes down the line
//adding whatever character it finds until it reaches position 0
for( size_type i = (str.size() - 1); (i >= 0); --i ){
reverseStr += str.at( i );
}
return reverseStr;
}
The program asks for input, then returns this error:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::tat
I'm really at a loss as to what I'm doing wrong here. The loop seems correct to me, so am I misunderstanding how to reference the function?
Unless you really want to write a loop, it's probably easier to just do something like:
std::string reverse(std::string const &input) {
return std::string(input.rbegin(), input.rend());
}
The problem is that your loop never terminates. You have as your condition i >= 0, but size_type is unsigned, so 0 - 1 == 2^(sizeof(size_t) * 8) - 1, which is certainly out of the range of your string. Therefore, you need to pick something else as your termination condition. One option is you can use i != std::string::npos, but that feels wrong. You're probably better off with something like:
for (size_type i = str.size(); i != 0; ) {
reverseStr += str.at(--i);
}
EDIT: I did some checking on i != std::string::npos. It should be well-defined and OK. However, it still seems like the Wrong Way To Do It.
As Andreas Grapentin said, the problem is that std::string::size() returns a size_t which is required by the standard to be an unsigned type. So it will always be >= 0 and when you hit 0 and decrement it, you will go to some really large, positive number.
Consider something like this:
std::string hw06::reverse(const std::string &str)
{
std::string reverseStr;
for(size_t i = str.size(); i != 0; i--)
reverseStr += str.at(i - 1);
return reverseStr;
}
I'm not keen on answering homework questions, but seeing some of the answers, I couldn't resist this:
std::string hw06::reverse(const std::string &str)
{ return std::string(str.rbegin(), str.rend()); }
Simple, clean and least wasteful if you can't do it in-place.
As other answers say, the problem is in the loop. I'll suggest using the following "goes to" operator :)
for(size_t i = str.size(); i --> 0;)
{
}
use i-- and not --i. Or u will decrease i value before getting the char and get loop problems.
Related
I'd like to know the fastest way for reading the last line in a std::string object.
Technically, the string after the last occurrence of \n in the fastest possible way?
This can be done using just string::find_last_of and string::substr like so
std::string get_last_line(const std::string &str)
{
auto position = str.find_last_of('\n');
if (position == std::string::npos)
return str;
else
return str.substr(position + 1);
}
see: example
I would probably use std::string::rfind and std::string::substr combined with guaranteed std::string::npos wrap around to be succinct:
inline std::string last_line_of(std::string const& s)
{
return s.substr(s.rfind('\n') + 1);
}
If s.rfind('\n') doesn't find anything it returns std::string::npos. The C++ standard says std::string::npos + 1 == 0. And returning s.substr(0) is always safe.
If s.rfind('\n') does find something then you want the substring starting from the next character. Again returning s.substr(s.size()) is safe according to the standard.
NOTE: In C++17 this method will benefit from guaranteed return value optimization so it should be super efficient.
I thought of a way that reads the string inversely (backwards) while storing what it reads
std::string get_last_line(const std::string &str)
{
size_t l = str.length();
std::string last_line_reversed, last_line;
for (--l; l > 0; --l)
{
char c = str.at(l);
if (c == '\n')
break;
last_line_reversed += c;
}
l = last_line_reversed.length();
size_t i = 0, y = l;
for (; i < l; ++i)
last_line += last_line_reversed[--y];
return last_line;
}
until it counters a '\n' character then reverse the stored string back and return it. If the target string is big and has a lot of new lines, this function would be very efficient.
I am really having a hard time getting recursions but i tried recursion to match a pattern inside a string.
Suppose i have a string geeks for geeks and i have a pattern eks to match.I could use many methods out there like regex, find method of string class but i really want to do this thing by recursions.
To achieve this i tried this code:
void recursion(int i,string str)
{
if(!str.compare("eks"))
cout<<"pattern at :"<<i<<'\n';
if(i<str.length() && str.length()-1!=0)
recursion(i,str.substr(i,str.length()-1));
}
int main()
{
string str("geeks for geeks");
for(int i=0;i<str.length();i++)
recursion(i,str.substr(i,str.length()));
}
Output :
Desired Ouput :
pattern at 2
pattern at 12
What could i be doing wrong here and what would be a good way to do this with recursions?
I understood a lot of topics in cpp but with recursions , i know how they work and even with that whenever i try to code something with recursions , it never works.Could there be any place that could help me with recursions as well?
You will never get pattern at 2, since compare doesn't work like that. Ask yourself, what will
std::string("eks for geeks").compare("eks")
return? Well, according to the documentation, you will get something positive, since "eks for geeks" is longer than "eks". So your first step is to fix this:
void recursion(int i, std::string str){
if(!str.substr(0,3).compare("eks")) {
std::cout << "pattern at: " << i << '\n';
}
Next, we have to recurse. But there's something off. i should be the current position of your "cursor". Therefore, you should advance it:
i = i + 1;
And if we reduce the length of the string in every iteration, we must not test i < str.length, otherwise we won't check the later half of the string:
if(str.length() - 1 > 0) {
recursion(i, str.substr(1));
}
}
Before we actually compile this code, let's reason about it:
we have a substring of the correct length for comparison with "eks"
we never use i except for the current position
we advance the position before we recurse
we "advance" the string by removing the first character
we will end up with an empty string at some point
Seems reasonable:
#include <iostream>
#include <string>
void recursion(int i, std::string str){
if(!str.substr(0,3).compare("eks")) {
std::cout << "pattern at: " << i << '\n';
}
i = i + 1;
if(str.length() - 1 > 0) {
recursion(i, str.substr(1));
}
}
int main () {
recursion(0, "geeks for geeks");
return 0;
}
Output:
pattern at: 2
pattern at: 12
However, that's not optimal. There are several optimizations that are possible. But that's left as an exercise.
Exercises
compare needs to use substr due to it's algorithm. Write your own comparison function that doesn't need substr.
There's a lot of copying going on. Can you get rid of that?
The for loop was wrong. Why?
Recursive function must not run into loop. And you have some mistakes.Try this code.
void recursion(string str, string subStr, int i){
if(str.find(subStr) != string::npos ) {
int pos = str.find(subStr);
str = str.substr(pos + subStr.length(), str.length()-1);
cout << "pattern at " << (pos + i) << endl;
recursion(str, subStr, pos+subStr.length() );
}
}
int main(int argc, char** argv) {
string str("geeks for geeks");
string subStr("eks");
recursion(str, subStr, 0);
return 0;
}
I am required to use recursion to determine the number of occurrences of a certain character in a given string. Now the non-recursive function is very simple. But, when trying to use recursion, I am getting an error when my program runs
short f_r(string, char);
int main()
{
string str;
char c;
cout << "Enter a string: ";
getline(cin,str);
cout << "Enter a character: ";
cin >> c;
cout << "\nString: " << str << endl;
cout << f_r(str,c) << endl;
return 0;
}
short f_r(string str, char c)
{
int pos = 0;
pos = str.find(c, pos);
if (pos > str.length()) return 0;
else
{
int count = 0;
count++;
pos++;
return count + f_r(str,c);
}
}
Problem Analysis
Your fundamental problems in your implementation are:
Failure to use the proper data type for the discovered position
Incorrect conditional to terminate the recursion
Incorrect recursion parameters (you're passing the same parameters).
Solution
That said, this function is simpler than you may think:
std::size_t f_r(const std::string& s, char c)
{
std::string::size_type pos = s.find(c);
return (pos == std::string::npos) ? 0 : (1 + f_r(s.substr(pos+1), c));
}
Note the following:
Uses std::string::size_type for the position calculation
Terminates the recursion if no value is returned by comparing against std::string::npos, returning 0 as the result of that final recursion invocation.
Passes a substring of the original as a parameter to the recursed call. This substring includes all remaining characters passed the discovered location in pos.
Non Recursive Solution
I realize you're tasked with doing this recursively, but I wanted to make sure you knew the way to do it iteratively without having to write the loop yourself. The C++ standard library includes an algorithm called std::count that does exactly what this does, but with a single pass, no sub-allocations like those delivered from substr(), and no recursion at all:
std::size_t f_r(const std::string& s, char c)
{
return std::count(s.begin(), s.end(), c);
}
and yes, it does make the very reason for f_r() somewhat pointless.
This "program" has too many problems to offer a quick fix. For starters, consider the following:
Your "recursion" keeps calling the function with the same state over and over again, so ultimately you'll blow the stack.
string.find() returns an npos in case of not found character.
Your else branch keeps passes the entire string into the recursive call. This will continue until the stack overflows. You need to only pass the part of the string after the first instance of c. You can do this by changing
return count + f_r(str,c);
to
str = str.substr(pos, str.size()-pos);
return count + f_r(str,c);
Note also that since count is always 1, this block would be simpler as
pos++;
str = str.substr(pos, str.size()-pos);
return 1 + f_r(str,c);
I would write the function using a static variable.
std::string::size_type f_r( const std::string &s, char c )
{
static std::string::size_type pos;
pos = s.find( c, pos );
return ( pos == std::string::npos ? pos = 0 : ( ++pos, 1 + f_r( s, c ) ) );
}
I'm new to C++. I'm working on a project where I need to read mostly integers from the user through the console. In order to avoid someone entering non-digit characters I thought about reading the input as a string, checking there are only digits in it, and then converting it to an integer. I created a function since I need to check for integers several times:
bool isanInt(int *y){
string z;
int x;
getline(cin,z);
for (int n=0; n < z.length(); n++) {
if(!((z[n] >= '0' && z[n] <= '9') || z[n] == ' ') ){
cout << "That is not a valid input!" << endl;
return false;
}
}
istringstream convert(z); //converting the string to integer
convert >> x;
*y = x;
return true;
}
When I need the user to input an integer I'll call this function. But for some reason when I make a call tho this function the program doesn't wait for an input, it jumps immediately to the for-loop processing an empty string. Any thoughts? Thanks for your help.
There are many ways to test a string for only numeric characters. One is
bool is_digits(const std::string &str) {
return str.find_first_not_of("0123456789") == std::string::npos;
}
This would work:
#include <algorithm> // for std::all_of
#include <cctype> // for std::isdigit
bool all_digits(const std::string& s)
{
return std::all_of(s.begin(),
s.end(),
[](char c) { return std::isdigit(c); });
}
You can cast the string in a try/catch block so that if the cast fails you it would raise an exception and you can write whatever you want in the console.
For example:
try
{
int myNum = strtoint(myString);
}
catch (std::bad_cast& bc)
{
std::cerr << "Please insert only numbers "<< '\n';
}
Character-classification is a job typically delegated to the ctype facets of a locale. You're going to need a function that takes into account all 9 digits including the thousands separator and the radix point:
bool is_numeric_string(const std::string& str, std::locale loc = std::locale())
{
using ctype = std::ctype<char>;
using numpunct = std::numpunct<char>;
using traits_type = std::string::traits_type;
auto& ct_f = std::use_facet<ctype>(loc);
auto& np_f = std::use_facet<numpunct>(loc);
return std::all_of(str.begin(), str.end(), [&str, &ct_f, &np_f] (char c)
{
return ct_f.is(std::ctype_base::digit, c) || traits_type::eq(c, np_f.thousands_sep())
|| traits_type::eq(c, np_f.decimal_point());
});
}
Note that extra effort can go into making sure the thousands separator is not the first character.
try another way like cin.getline(str,sizeof(str)), and str here is char*. I think ur problem may be cause by other functions before calling this function. Maybe u can examine other parts of ur codes carefully. Breakpoints setting is recommended too.
Always use off-the-shelf functions. Never write alone.
I recommend
std::regex
Enjoy.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
Im trying to create a function that mimics the behavior of the getline() function, with the option to use a delimiter to split the string into tokens.
The function accepts 2 strings (the second is being passed by reference) and a char type for the delimiter. It loops through each character of the first string, copying it to the second string and stops looping when it reaches the delimiter. It returns true if the first string have more characters after the delimiter and false otherwise. The position of the last character is being saved in a static variable.
for some reason the the program is going into an infinite loop and is not executing anything:
const int LINE_SIZE = 160;
bool strSplit(string sFirst, string & sLast, char cDelim) {
static int iCount = 0;
for(int i = iCount; i < LINE_SIZE; i++) {
if(sFirst[i] != cDelim)
sLast[i-iCount] = sFirst[i];
else {
iCount = i+1;
return true;
}
}
return false;
}
The function is used in the following way:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
}
Why is it going into an infinite loop, and why is it not working?
I should add that i'm interested in a solution without using istringstream, if that's possible.
It is not exactly what you asked for, but have you considered std::istringstream and std::getline?
// UNTESTED
std::istringstream iss(sLine);
while(std::getline(iss, sToken, '|')) {
std::cout << sToken << "\n";
}
EDIT:
Why is it going into an infinite loop, and why is it not working?
We can't know, you didn't provide enough information. Try to create an SSCCE and post that.
I can tell you that the following line is very suspicious:
sLast[i-iCount] = sFirst[i];
This line will result in undefined behavior (including, perhaps, what you have seen) in any of the following conditions:
i >= sFirst.size()
i-iCount >= sLast.size()
i-iCount < 0
It appears to me likely that all of those conditions are true. If the passed-in string is, for example, shorter than 160 lines, or if iCount ever grows to be bigger than the offset of the first delimiter, then you'll get undefined behavior.
LINE_SIZE is probably larger than the number of characters in the string object, so the code runs off the end of the string's storage, and pretty much anything can happen.
Instead of rolling your own, string::find does what you need.
std::string::size_type pos = 0;
std::string::size_type new_pos = sFirst.find('|', pos);
The call to find finds the first occurrence of '|' that's at or after the position 'pos'. If it succeeds, it returns the index of the '|' that it found. If it fails, it returns std::string::npos. Use it in a loop, and after each match, copy the text from [pos, new_pos) into the target string, and update pos to new_pos + 1.
are you sure it's the strSplit() function that doesn't return or is it your caller while loop that's infinite?
Shouldn't your caller loop be something like:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
cin >> sLine >> endl;
}
-- edit --
if value of sLine is such that it makes strSplit() to return true then the while loop becomes infinite.. so do something to change the value of sLine for each iteration of the loop.. e.g. put in a cin..
Check this out
std::vector<std::string> spliString(const std::string &str,
const std::string &separator)
{
vector<string> ret;
string::size_type strLen = str.length();
char *buff;
char *pch;
buff = new char[strLen + 1];
buff[strLen] = '\0';
std::copy(str.begin(), str.end(), buff);
pch = strtok(buff, separator.c_str());
while(pch != NULL)
{
ret.push_back(string(pch));
pch = strtok(NULL, separator.c_str());
}
delete[] buff;
return ret;
}