Why is my while loop not terminating when i < 0? - c++

sorry for the noob question.
I have the following code for an assignment in my class (includes the assignment description):
Write a program which asks the user to enter a string and then passes it to a void recursive function which displays the string in reverse. The prototype of the function would be:
void reverse(string s, int i);
The function call would be:
reverse(strIn, strIn.length());
A typical run will be:
Enter a string:
Four score and seven years ago ..
.. oga sraey neves dna erocs ruoF
// Actual code
#include <iostream>
#include <string>
void reverse(std::string, int);
int main() {
std::string input;
std::cout << "Enter a string." << std::endl;
getline(std::cin, input);
int i = input.length() - 1;
reverse(input, i);
return 0;
}
void reverse(std::string input, int i) {
while (i >= 0) {
std::cout << input.at(i);
i--;
reverse(input, i);
}
}
I assumed that by subtracting 1 each time would display the last character in the string, and setting the loop condition to i >= 0 would make the loop terminate when there's no more characters left in the string. But I'm getting the following output:
sleepy#mooncell ~/CMPSC121/Activities $ ./a.out
Enter a string.
help
plehhehhlehhehh
I can't figure out what I'm doing wrong here. Help is much appreciated!

This is because you are trying to perform recursion and a while loop at the same time, just get rid of the while loop and it will work, the code should look something like this:
// Actual code
#include <iostream>
#include <string>
void reverse(std::string, int);
int main() {
std::string input;
std::cout << "Enter a string." << std::endl;
getline(std::cin, input);
int i = input.length() - 1;
reverse(input, i);
return 0;
}
void reverse(std::string input, int i) {
if(i <0)
return;
std::cout << input.at(i);
i--;
reverse(input, i);
}

This function
void reverse(std::string input, int i) {
while (i >= 0) {
std::cout << input.at(i);
i--;
reverse(input, i);
}
}
is not pure recursive because it uses a while loop.
Also it is a bad idea to pass the string by value. And the position in the string should have the type std::string::size_type.
The second parameter can have a default argument. in this case a function call will look much simpler
reverse( input );
Pay attention to that these statements can invoke undefined behavior when an empty string is passed to the function
int i = input.length() - 1;
reverse(input, i);
Because in this case the variable i will have maximum value. That is this declaration
int i = input.length() - 1;
in fact will be equivalent to
int i = std::string::size_type( -1 );
What you need is the following
void reverse( const std::string &s, std::string::size_type i = 0 )
{
if ( i < s.size() )
{
char c = s[i];
reverse( s, i + 1 );
std::cout << c;
}
}
Here is a demonstrative program.
#include <iostream>
#include <string>
void reverse( const std::string &s, std::string::size_type i = 0 )
{
if ( i < s.size() )
{
char c = s[i];
reverse( s, i + 1 );
std::cout << c;
}
}
int main()
{
const char *s = "Hello bbchan";
std::cout << s << '\n';
reverse( s );
std::cout << '\n';
return 0;
}
Its output is
Hello bbchan
nahcbb olleH
And even better to define the function the following way as it is shown in the demonstrative program below. In this case you can for example write a string in the reverse order in a file.
#include <iostream>
#include <string>
std::ostream & reverse( const std::string &s,
std::string::size_type i = 0,
std::ostream &os = std::cout )
{
if ( i < s.size() )
{
char c = s[i];
reverse( s, i + 1, os );
os << c;
}
return os;
}
int main()
{
const char *s = "Hello bbchan";
std::cout << s << '\n';
reverse( s ) << '\n';
return 0;
}

Related

This is a program to recursively calculate the reverse of a string but it's not printing anything

What I have done is created a global array to store the reversed string.
#include <bits/stdc++.h>
using namespace std;
char arr[10];
int c = 1;
string Reverser(string z)
{
arr[c] = z[(z.size() - c)];
c++;
if (c == (z.size() + 1))
{
return 0;
}
else
{
Reverser(z);
}
return 0;
}
int main()
{
string z;
cin >> z;
string Reverser(z);
for (int i = 1; i <= z.size(); i++)
{
cout << arr[i];
}
return 0;
}
I have also tried to dry run it but I can't really find any error.
You can use a std::stringstream and pass it by reference in your recursive function. Also, you can pass the string by reference.
#include <iostream>
#include <string>
#include <sstream>
void reverse(const std::string& a, std::stringstream& ss, unsigned int pos)
{
ss << a[pos];
if (pos == 0) return;
reverse(a, ss, pos - 1);
}
void reverse(const std::string& a, std::stringstream& ss)
{
reverse(a, ss, a.length() - 1);
}
int main()
{
std::stringstream ss;
std::string input = "Hello";
reverse(input, ss);
std::cout << ss.str() << std::endl;
}

How to write c++ code to reverse a string without using inbuilt function?

I have write this code. It does not show any error but string is not reversed.please let me know where i have made the mistake?
I'm using codeblock to write code and GCC compiler. I have created two functions reverseString and printString, the printString function is working but reverseString is not working. what can i do?
#include <iostream>
#include<string>
using namespace std;
void reverseString(string s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
void printString(string s, int n){
for(int i=0; i<n; i++){
cout << s[i];
cout << endl;
}
}
int main() {
string s;
cout << "Type String To Reverse: \n";
cin >> s;
cout << "String In Actual Order: \n";
printString(s,s.length());
reverseString(s, 0, s.length()-1);
cout << "String In Reverse Order: \n";
printString(s,s.length());
return 0;
}
This function accepts an object of the type std::string by value
void reverseString(string s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
It means that it deals with a copy of the string used as an argument and changes the copy instead of the original string.
You have to declare the parameter as having reference type
void reverseString(string &s, int iNode, int lNode){
while(iNode < lNode){
char temp = s[iNode];
s[iNode] = s[lNode];
s[lNode] = temp;
iNode++;
lNode--;
}
}
The function could be defined simpler (without using standard features as for example std::swap) the following way
std::string & reverseString( std::string &s )
{
for ( std::string::size_type i = 0, n = s.size(); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
And the function can be called like
cout << "String In Reverse Order: \n";
std::cout << reverseString( s ) << '\n';
Without using the loop you could define the function just the following way
std::string & reverseString( std::string &s )
{
return s.assign( s.rbegin(), s.rend() );
}
As for your own function printString then it could be defined at least like
std::ostream & printString( const std::string &s, std::ostream &os = std::cout )
{
for ( char c : s )
{
os << c;
}
return os;
}
and can be called like
printString( s ) << '\n';

How to insert an integer with leading zeros into a std::string?

In a C++14 program, I am given a string like
std::string s = "MyFile####.mp4";
and an integer 0 to a few hundred. (It'll never be a thousand or more, but four digits just in case.) I want to replace the "####" with the integer value, with leading zeros as needed to match the number of '#' characters. What is the slick C++11/14 way to modify s or produce a new string like that?
Normally I would use char* strings and snprintf(), strchr() to find the "#", but figure I should get with modern times and use std::string more often, but know only the simplest uses of it.
What is the slick C++11/14 way to modify s or produce a new string like that?
I don't know if it's slick enough but I propose the use of std::transform(), a lambda function and reverse iterators.
Something like
#include <string>
#include <iostream>
#include <algorithm>
int main ()
{
std::string str { "MyFile####.mp4" };
int num { 742 };
std::transform(str.rbegin(), str.rend(), str.rbegin(),
[&](auto ch)
{
if ( '#' == ch )
{
ch = "0123456789"[num % 10]; // or '0' + num % 10;
num /= 10;
}
return ch;
} // end of lambda function passed in as a parameter
); // end of std::transform()
std::cout << str << std::endl; // print MyFile0742.mp4
}
I would use regex since you're using C++14:
#include <iostream>
#include <regex>
#include <string>
#include <iterator>
int main()
{
std::string text = "Myfile####.mp4";
std::regex re("####");
int num = 252;
//convert int to string and add appropriate number of 0's
std::string nu = std::to_string(num);
while(nu.length() < 4) {
nu = "0" + nu;
}
//let regex_replace do it's work
std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
text.begin(), text.end(), re, nu);
std::cout << std::endl;
return 0;
}
WHy not use std::stringstream and than convert it to string.
std::string inputNumber (std::string s, int n) {
std::stringstream sstream;
bool numberIsSet = false;
for (int i = 0; i < s; ++i) {
if (s[i] == '#' && numberIsSet == true)
continue;
else if (s[i] == '#' && numberIsSet == false) {
sstream << setfill('0') << setw(5) << n;
numberIsSet = true;
} else
sstream << s[i];
}
return sstream.str();
}
I would probably use something like this
#include <iostream>
using namespace std;
int main()
{
int SomeNumber = 42;
std:string num = std::to_string(SomeNumber);
string padding = "";
while(padding.length()+num.length()<4){
padding += "0";
}
string result = "MyFile"+padding+num+".mp4";
cout << result << endl;
return 0;
}
Mine got out of control while I was playing with it, heh.
Pass it patterns on its command line, like:
./cpp-string-fill file########.jpg '####' test###this### and#this
#include <string>
#include <iostream>
#include <sstream>
std::string fill_pattern(std::string p, int num) {
size_t start_i, end_i;
for(
start_i = p.find_first_of('#'), end_i = start_i;
end_i < p.length() && p[end_i] == '#';
++end_i
) {
// Nothing special here.
}
if(end_i <= p.length()) {
std::ostringstream os;
os << num;
const std::string &ns = os.str();
size_t n_i = ns.length();
while(end_i > start_i && n_i > 0) {
end_i--;
n_i--;
p[end_i] = ns[n_i];
}
while(end_i > start_i) {
end_i--;
p[end_i] = '0';
}
}
return p;
}
int main(int argc, char *argv[]) {
if(argc<2) {
exit(1);
}
for(int i = 1; i < argc; i++) {
std::cout << fill_pattern(argv[i], 1283) << std::endl;
}
return 0;
}
I would probably do something like this:
using namespace std;
#include <iostream>
#include <string>
int main()
{
int SomeNumber = 42;
string num = std::to_string(SomeNumber);
string guide = "myfile####.mp3";
int start = static_cast<int>(guide.find_first_of("#"));
int end = static_cast<int>(guide.find_last_of("#"));
int used = 1;
int place = end;
char padding = '0';
while(place >= start){
if(used>num.length()){
guide.begin()[place]=padding;
}else{
guide.begin()[place]=num[num.length()-used];
}
place--;
used++;
}
cout << guide << endl;
return 0;
}

Palindrome class help in C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hi i am trying to write a palindrome class but am getting the wrong results.
I need to create a Palindrome class and return whether the phrase is a Palindrome.
Here is my code.
Palindrome.h:
#ifndef PALINDROME_H
#define PALINDROME_H
#include <iostream>
#include<cstring>
using namespace std;
class Palindrome{
private:
char str[1024];
char s1[1024];
char s2[1024];
int a;
int b;
public:
Palindrome(char s2[1024], int a, int b)
{
s2[1024] = { 0 };
a = 0;
b = 0;
}
void removeNonLetters(char str[]);
void lowerCase(char s1[]);
bool isPalindrome(char s2[], int a, int b);
}; // End of class definition
#endif
Palindrome.cpp:
#include "Palindrome.h"
void Palindrome::removeNonLetters(char str[])
{
char s1[1024] = { 0 };
int j = 0;
int l1 = strlen(str);
for (int i = 0; i < l1; i++)
{
if (str[i] <= '9' && str[i] >= '0')
{
s1[j++] = str[i];
}
else if ((str[i] >= 'A' && str[i] <= 'Z')
|| (str[i]) >= 'a' && str[i] <= 'z')
{
s1[j++] = str[i];
}
}
cout << s1 << endl;
}
void Palindrome::lowerCase(char s1[])
{
char s2[1024] = { 0 };
int l2 = strlen(s1);
int g = 0;
for (int i = 0; i < l2; i++)
{
if (s1[i] >= 'a' && s1[i] <= 'z')
{
s2[g++] = s1[i];
}
else if (s1[i] >= 'A' && s1[i] <= 'Z')
{
s2[g++] = s1[i] + 32;
}
}
cout << s2 << endl;
}
bool Palindrome::isPalindrome(char s2[], int a, int b)
{
if (a >= b)
return true;
cout << "Yes" << endl;
if (s2[a] != s2[b])
return false;
else
return isPalindrome(s2, a + 1, b - 1);
cout << "No" << endl;
}
Main.cpp:
#include "Palindrome.h"
int main()
{
char str[1024] = { 0 };
char s1[1024] = { 0 };
char s2[1024] = { 0 };
cout << "input a string:" << endl;
cin.getline(str, sizeof(str));
Palindrome removeNonLetters(char str[]);
Palindrome lowerCase(char s1[]);
int length = strlen(s2);
Palindrome isPalindrome(s2, 0, length - 1);
return 0;
}
You teacher may not like this, but this is how we do it in the real world.
First things first, reach for the standard library:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
A function to strip non-alpha characters from a string:
std::string strip(std::string s)
{
s.erase(std::remove_if(std::begin(s),
std::end(s),
[](auto c) { return !std::isalpha(c); }),
std::end(s));
return s;
}
A function to transform a string to lower case:
std::string to_lower(std::string s)
{
std::transform(std::begin(s),
std::end(s),
std::begin(s),
[](auto c) { return std::tolower(c); });
return s;
}
A function to check that a string is the same in reverse as it is forwards:
bool is_palindrome(const std::string& s)
{
return std::equal(std::begin(s), std::end(s),
std::rbegin(s), std::rend(s));
}
Putting it all together in a test:
int main()
{
auto word = std::string("a!b B <>A");
if (is_palindrome(to_lower(strip(word)))) {
std::cout << "palindrome" << std::endl;
}
else {
std::cout << "not palindrome" << std::endl;
}
return 0;
}
Complete listing:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
std::string strip(std::string s)
{
s.erase(std::remove_if(std::begin(s),
std::end(s),
[](auto c) { return !std::isalpha(c); }),
std::end(s));
return s;
}
std::string to_lower(std::string s)
{
std::transform(std::begin(s),
std::end(s),
std::begin(s),
[](auto c) { return std::tolower(c); });
return s;
}
bool is_palindrome(const std::string& s)
{
return std::equal(std::begin(s), std::end(s),
std::rbegin(s), std::rend(s));
}
int main()
{
auto word = std::string("a!b B <>A");
if (is_palindrome(to_lower(strip(word)))) {
std::cout << "palindrome" << std::endl;
}
else {
std::cout << "not palindrome" << std::endl;
}
return 0;
}
There are many things wrong with your code. I hope these pointers help:
You should be using std library.
Why does the constructor for the class take any parameters? Nothign uses them
Why are there any member variables? Nothing uses them.
Why are the functions in a class at all? They're just functions - they should be in a functions library or similar.
The functions just write to cout so are useless.
Your main function doesn't even seem to call the functions correctly.
I tried this:
char str[1024] = { 0 };
cout << "input a string:" << endl;
cin.getline(str, sizeof(str));
int length = strlen(str);
Palindrome a(str,0, length);
a.removeNonLetters(str);
a.lowerCase(str);
a.isPalindrome(str, 0, length - 1);
cin.getline(str, sizeof(str));
return 0;
I don't get the exception but get the following output:
input a string:
EVIL rats on no star **** live
EVILratsonnostarlive
evilratsonnostarlive
Yes
However this works too:
input a string
hello
hello
hello
Yes
So the first two functions seem to work (if removing spaces was also intentional) but the third does not.

How to insert spaces in a big number to make it more readable?

I came up with this, since other examples provided on stackoverflow were in C#
string number_fmt(ulong n)
{
// cout << "(" << n << ")" << endl;
char s[128];
sprintf(s, "%lu", n);
string r(s);
reverse(r.begin(), r.end());
int space_inserted = 0;
size_t how_many_spaces = r.length() / 3;
if(r.length() % 3 != 0)
how_many_spaces += 1;
for(int i = 1; i < how_many_spaces; ++i)
{
r.insert(3 * i + space_inserted, " ");
space_inserted += 1;
}
reverse(r.begin(), r.end());
return r;
}
Do you know any better solution ?
I don't know about "better", but this version uses std::locale, etc.
#include <iostream>
#include <locale>
#include <sstream>
template<class Char>
class MyFacet : public std::numpunct<Char> {
public:
std::string do_grouping() const { return "\3"; }
Char do_thousands_sep() const { return ' '; }
};
std::string number_fmt(unsigned long n)
{
std::ostringstream oss;
oss.imbue(std::locale(oss.getloc(), new MyFacet<char>));
oss << n;
return oss.str();
}
int main() {
std::cout << number_fmt(123456789) << "\n";
}
EDIT: Of course, if your final goal is to print the values on an ostream, you can skip storing them in a string altogether.
#include <iostream>
#include <locale>
#include <sstream>
#include <cwchar>
template <class Char>
class MyFacet : public std::numpunct<Char> {
public:
std::string do_grouping() const { return "\3"; }
Char do_thousands_sep() const { return ' '; }
};
int main(int ac, char **av) {
using std::locale;
using std::cout;
// Show how it works to start with
cout << 123456789 << "\n";
// Switch it to spacey mode
locale oldLoc =
cout.imbue(locale(cout.getloc(), new MyFacet<char>));
// How does it work now?
cout << 456789123 << "\n";
// You probably want to clean up after yourself
cout.imbue(oldLoc);
// Does it still work?
cout << 789123456 << "\n";
}
This is already done by the locale.
The default local is "C" which does no formatting. But you can set it to your current language-specific local (as defined by your computer's setting by setting the current local as the first line of main).
int main()
{
std::locale::global(std::locale("")); // Set the default local of the machine
// Will be used by all streams.
// The "" will find the machine specific local
// and use that instead of the "C" locale
// Note: The C local should only be used for programmers.
// Alternatively you can imbue particular stream with the local
// To achieve a localized effect
// std::cout.imbue(std::locale(""));
// Now all you do is print the number.
std::cout << "123456789\n"; // This will print the number according to your local
} // For me US-en this is 123,456,789
// Your may very.
If you want to do something explicitly then you can set a facet in the local for printing numbers.
#include <iostream>
#include <locale>
#include <string>
template<typename CharT>
struct Sep : public std::numpunct<CharT>
{
virtual std::string do_grouping() const {return "\003";}
virtual CharT do_thousands_sep() const {return ':';}
};
int main()
{
std::cout.imbue(std::locale(std::cout.getloc(), new Sep <char>()));
std::cout << 123456789 << "\n"; // this prints 123:456:789
}
This one is different, but better is subjective. I think it's very succinct and clear what it's doing though:
string number_fmt(unsigned long long n, char sep = ',') {
stringstream fmt;
fmt << n;
string s = fmt.str();
s.reserve(s.length() + s.length() / 3);
// loop until the end of the string and use j to keep track of every
// third loop starting taking into account the leading x digits (this probably
// can be rewritten in terms of just i, but it seems more clear when you use
// a seperate variable)
for (int i = 0, j = 3 - s.length() % 3; i < s.length(); ++i, ++j)
if (i != 0 && j % 3 == 0)
s.insert(i++, 1, sep);
return s;
}
Using it like
cout << number_fmt(43615091387465) << endl;
prints
43,615,091,387,465
Admittedly, if one wanted to have the most possible efficient version and didn't mind specializing it for the case at hand, using a local char buffer can help a lot.
#include <iostream>
#include <string>
std::string format(unsigned long long i) {
char buffer[128]; // can be adapted more tightly with std::numeric_limits
char* p = buffer + 128;
*(--p) = '\0';
unsigned char count = 0;
while (i != 0) {
*(--p) = '0' + (i % 10);
i /= 10;
if (++count == 3) { count = 0; *(--p) = ' '; }
}
return p;
}
int main() {
std::cout << format(1234567890) << '\n';
}
In action at ideone:
1 234 567 890
(Key point: for number printing, go backward)
Not very optimal but small
QString str = QString::number(d);
for (int i = 3; str.size() > i; i += 4)
str.insert(str.size() - i, ' ');
If "better" means more efficient, you should:
use reserve on the output string (you know its size...)
avoid the insert in the middle of the string, because you have to copy a big part of the string each time you do that.
I would say something like this (untested):
std::string number_fmt (ulong n)
{
std::ostringstream buff;
buff << n;
std::string without_spaces = buff.str ();
std::string with_spaces;
with_spaces.reserve ((without_spaces.size () * 4) / 3);
std::size_t nb_inserted = 0;
for (auto it = without_spaces.rbegin (); it != without_spaces.rend (); ++it)
{
if (nb_inserted % 3 == 0 && nb_inserted != 0)
{
with_spaces.push_back (' ');
}
++ nb_inserted;
with_spaces.push_back (*it);
}
std::reverse (with_spaces.begin (), with_spaces.end ());
return with_spaces;
}