Remove extra white spaces in C++ - c++
I tried to write a script that removes extra white spaces but I didn't manage to finish it.
Basically I want to transform abc sssd g g sdg gg gf into abc sssd g g sdg gg gf.
In languages like PHP or C#, it would be very easy, but not in C++, I see. This is my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <string.h>
char* trim3(char* s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
char *str_replace(char * t1, char * t2, char * t6)
{
char*t4;
char*t5=(char *)malloc(10);
memset(t5, 0, 10);
while(strstr(t6,t1))
{
t4=strstr(t6,t1);
strncpy(t5+strlen(t5),t6,t4-t6);
strcat(t5,t2);
t4+=strlen(t1);
t6=t4;
}
return strcat(t5,t4);
}
void remove_extra_whitespaces(char* input,char* output)
{
char* inputPtr = input; // init inputPtr always at the last moment.
int spacecount = 0;
while(*inputPtr != '\0')
{
char* substr;
strncpy(substr, inputPtr+0, 1);
if(substr == " ")
{
spacecount++;
}
else
{
spacecount = 0;
}
printf("[%p] -> %d\n",*substr,spacecount);
// Assume the string last with \0
// some code
inputPtr++; // After "some code" (instead of what you wrote).
}
}
int main(int argc, char **argv)
{
printf("testing 2 ..\n");
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
return 1;
}
It doesn't work. I tried several methods. What I am trying to do is to iterate the string letter by letter and dump it in another string as long as there is only one space in a row; if there are two spaces, don't write the second character to the new string.
How can I solve this?
There are already plenty of nice solutions. I propose you an alternative based on a dedicated <algorithm> meant to avoid consecutive duplicates: unique_copy():
void remove_extra_whitespaces(const string &input, string &output)
{
output.clear(); // unless you want to add at the end of existing sring...
unique_copy (input.begin(), input.end(), back_insert_iterator<string>(output),
[](char a,char b){ return isspace(a) && isspace(b);});
cout << output<<endl;
}
Here is a live demo. Note that I changed from c style strings to the safer and more powerful C++ strings.
Edit: if keeping c-style strings is required in your code, you could use almost the same code but with pointers instead of iterators. That's the magic of C++. Here is another live demo.
Here's a simple, non-C++11 solution, using the same remove_extra_whitespace() signature as in the question:
#include <cstdio>
void remove_extra_whitespaces(char* input, char* output)
{
int inputIndex = 0;
int outputIndex = 0;
while(input[inputIndex] != '\0')
{
output[outputIndex] = input[inputIndex];
if(input[inputIndex] == ' ')
{
while(input[inputIndex + 1] == ' ')
{
// skip over any extra spaces
inputIndex++;
}
}
outputIndex++;
inputIndex++;
}
// null-terminate output
output[outputIndex] = '\0';
}
int main(int argc, char **argv)
{
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
printf("input: %s\noutput: %s\n", input, output);
return 1;
}
Output:
input: asfa sas f f dgdgd dg ggg
output: asfa sas f f dgdgd dg ggg
Since you use C++, you can take advantage of standard-library features designed for that sort of work. You could use std::string (instead of char[0x255]) and std::istringstream, which will replace most of the pointer arithmetic.
First, make a string stream:
std::istringstream stream(input);
Then, read strings from it. It will remove the whitespace delimiters automatically:
std::string word;
while (stream >> word)
{
...
}
Inside the loop, build your output string:
if (!output.empty()) // special case: no space before first word
output += ' ';
output += word;
A disadvantage of this method is that it allocates memory dynamically (including several reallocations, performed when the output string grows).
There are plenty of ways of doing this (e.g., using regular expressions), but one way you could do this is using std::copy_if with a stateful functor remembering whether the last character was a space:
#include <algorithm>
#include <string>
#include <iostream>
struct if_not_prev_space
{
// Is last encountered character space.
bool m_is = false;
bool operator()(const char c)
{
// Copy if last was not space, or current is not space.
const bool ret = !m_is || c != ' ';
m_is = c == ' ';
return ret;
}
};
int main()
{
const std::string s("abc sssd g g sdg gg gf into abc sssd g g sdg gg gf");
std::string o;
std::copy_if(std::begin(s), std::end(s), std::back_inserter(o), if_not_prev_space());
std::cout << o << std::endl;
}
You can use std::unique which reduces adjacent duplicates to a single instance according to how you define what makes two elements equal is.
Here I have defined elements as equal if they are both whitespace characters:
inline std::string& remove_extra_ws_mute(std::string& s)
{
s.erase(std::unique(std::begin(s), std::end(s), [](unsigned char a, unsigned char b){
return std::isspace(a) && std::isspace(b);
}), std::end(s));
return s;
}
inline std::string remove_extra_ws_copy(std::string s)
{
return remove_extra_ws_mute(s);
}
std::unique moves the duplicates to the end of the string and returns an iterator to the beginning of them so they can be erased.
Additionally, if you must work with low level strings then you can still use std::unique on the pointers:
char* remove_extra_ws(char const* s)
{
std::size_t len = std::strlen(s);
char* buf = new char[len + 1];
std::strcpy(buf, s);
// Note that std::unique will also retain the null terminator
// in its correct position at the end of the valid portion
// of the string
std::unique(buf, buf + len + 1, [](unsigned char a, unsigned char b){
return (a && std::isspace(a)) && (b && std::isspace(b));
});
return buf;
}
for in-place modification you can apply erase-remove technic:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
int main()
{
std::string input {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
input.erase(std::remove_if(input.begin(), input.end(), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}), input.end());
std::cout << input << "\n";
}
So you first move all extra spaces to the end of the string and then truncate it.
The great advantage of C++ is that is universal enough to port your code to plain-c-static strings with only few modifications:
void erase(char * p) {
// note that this ony works good when initial array is allocated in the static array
// so we do not need to rearrange memory
*p = 0;
}
int main()
{
char input [] {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
erase(std::remove_if(std::begin(input), std::end(input), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}));
std::cout << input << "\n";
}
Interesting enough remove step here is string-representation independent. It will work with std::string without modifications at all.
I have the sinking feeling that good ol' scanf will do (in fact, this is the C school equivalent to Anatoly's C++ solution):
void remove_extra_whitespaces(char* input, char* output)
{
int srcOffs = 0, destOffs = 0, numRead = 0;
while(sscanf(input + srcOffs, "%s%n", output + destOffs, &numRead) > 0)
{
srcOffs += numRead;
destOffs += strlen(output + destOffs);
output[destOffs++] = ' '; // overwrite 0, advance past that
}
output[destOffs > 0 ? destOffs-1 : 0] = '\0';
}
We exploit the fact that scanf has magical built-in space skipping capabilities. We then use the perhaps less known %n "conversion" specification which gives us the amount of chars consumed by scanf. This feature frequently comes in handy when reading from strings, like here. The bitter drop which makes this solution less-than-perfect is the strlen call on the output (there is no "how many bytes have I actually just written" conversion specifier, unfortunately).
Last not least use of scanf is easy here because sufficient memory is guaranteed to exist at output; if that were not the case, the code would become more complex due to buffering and overflow handling.
Since you are writing c-style, here's a way to do what you want.
Note that you can remove '\r' and '\n' which are line breaks (but of course that's up to you if you consider those whitespaces or not).
This function should be as fast or faster than any other alternative and no memory allocation takes place even when it's called with std::strings (I've overloaded it).
char temp[] = " alsdasdl gasdasd ee";
remove_whitesaces(temp);
printf("%s\n", temp);
int remove_whitesaces(char *p)
{
int len = strlen(p);
int new_len = 0;
bool space = false;
for (int i = 0; i < len; i++)
{
switch (p[i])
{
case ' ': space = true; break;
case '\t': space = true; break;
case '\n': break; // you could set space true for \r and \n
case '\r': break; // if you consider them spaces, I just ignore them.
default:
if (space && new_len > 0)
p[new_len++] = ' ';
p[new_len++] = p[i];
space = false;
}
}
p[new_len] = '\0';
return new_len;
}
// and you can use it with strings too,
inline int remove_whitesaces(std::string &str)
{
int len = remove_whitesaces(&str[0]);
str.resize(len);
return len; // returning len for consistency with the primary function
// but u can return std::string instead.
}
// again no memory allocation is gonna take place,
// since resize does not not free memory because the length is either equal or lower
If you take a brief look at the C++ Standard library, you will notice that a lot C++ functions that return std::string, or other std::objects are basically a wrapper to a well written extern "C" function. So don't be afraid to use C functions in C++ applications, if they are well written and you can overload them to support std::strings and such.
For example, in Visual Studio 2015, std::to_string is written exactly like this:
inline string to_string(int _Val)
{ // convert int to string
return (_Integral_to_string("%d", _Val));
}
inline string to_string(unsigned int _Val)
{ // convert unsigned int to string
return (_Integral_to_string("%u", _Val));
}
and _Integral_to_string is a wrapper to a C function sprintf_s
template<class _Ty> inline
string _Integral_to_string(const char *_Fmt, _Ty _Val)
{ // convert _Ty to string
static_assert(is_integral<_Ty>::value,
"_Ty must be integral");
char _Buf[_TO_STRING_BUF_SIZE];
int _Len = _CSTD sprintf_s(_Buf, _TO_STRING_BUF_SIZE, _Fmt, _Val);
return (string(_Buf, _Len));
}
Well here is a longish(but easy) solution that does not use pointers.
It can be optimized further but hey it works.
#include <iostream>
#include <string>
using namespace std;
void removeExtraSpace(string str);
int main(){
string s;
cout << "Enter a string with extra spaces: ";
getline(cin, s);
removeExtraSpace(s);
return 0;
}
void removeExtraSpace(string str){
int len = str.size();
if(len==0){
cout << "Simplified String: " << endl;
cout << "I would appreciate it if you could enter more than 0 characters. " << endl;
return;
}
char ch1[len];
char ch2[len];
//Placing characters of str in ch1[]
for(int i=0; i<len; i++){
ch1[i]=str[i];
}
//Computing index of 1st non-space character
int pos=0;
for(int i=0; i<len; i++){
if(ch1[i] != ' '){
pos = i;
break;
}
}
int cons_arr = 1;
ch2[0] = ch1[pos];
for(int i=(pos+1); i<len; i++){
char x = ch1[i];
if(x==char(32)){
//Checking whether character at ch2[i]==' '
if(ch2[cons_arr-1] == ' '){
continue;
}
else{
ch2[cons_arr] = ' ';
cons_arr++;
continue;
}
}
ch2[cons_arr] = x;
cons_arr++;
}
//Printing the char array
cout << "Simplified string: " << endl;
for(int i=0; i<cons_arr; i++){
cout << ch2[i];
}
cout << endl;
}
I don't know if this helps but this is how I did it on my homework. The only case where it might break a bit is when there is spaces at the beginning of the string EX " wor ds " In that case, it will change it to " wor ds"
void ShortenSpace(string &usrStr){
char cha1;
char cha2;
for (int i = 0; i < usrStr.size() - 1; ++i) {
cha1 = usrStr.at(i);
cha2 = usrStr.at(i + 1);
if ((cha1 == ' ') && (cha2 == ' ')) {
usrStr.erase(usrStr.begin() + 1 + i);
--i;//edit: was ++i instead of --i, made code not work properly
}
}
}
I ended up here for a slighly different problem. Since I don't know where else to put it, and I found out what was wrong, I share it here. Don't be cross with me, please.
I had some strings that would print additional spaces at their ends, while showing up without spaces in debugging. The strings where formed in windows calls like VerQueryValue(), which besides other stuff outputs a string length, as e.g. iProductNameLen in the following line converting the result to a string named strProductName:
strProductName = string((LPCSTR)pvProductName, iProductNameLen)
then produced a string with a \0 byte at the end, which did not show easily in de debugger, but printed on screen as a space. I'll leave the solution of this as an excercise, since it is not hard at all, once you are aware of this.
Related
How to replace "pi" by "3.14"?
How to replace all "pi" from a string by "3.14"? Example: INPUT = "xpix" ___ OUTPUT = "x3.14x" for a string, not character array. This doesn't work: #include<iostream> using namespace std; void replacePi(string str) { if(str.size() <=1) return ; replacePi(str.substr(1)); int l = str.length(); if(str[0]=='p' && str[1]=='i') { for(int i=l;i>1;i--) str[i+2] = str[i]; str[0] = '3'; str[1] = '.'; str[2] = '1'; str[3] = '4'; } } int main() { string s; cin>>s; replacePi(s); cout << s << endl; }
There is a ready to use function in the C++ lib. It is called: std::regex_replace. You can read the documentation in the CPP Reference here. Since it uses regexes it is very powerful. The disadvantage is that it may be a little bit too slow during runtime for some uses case. But for your example, this does not matter. So, a common C++ solution would be: #include <iostream> #include <string> #include <regex> int main() { // The test string std::string input{ "Pi is a magical number. Pi is used in many places. Go for Pi" }; // Use simply the replace function std::string output = std::regex_replace(input, std::regex("Pi"), "3.14"); // Show the output std::cout << output << "\n"; } But my guess is that you are learning C++ and the teacher gave you a task and expects a solution without using elements from the std C++ library. So, a hands on solution. This can be implemented best with a temporary string. You check character by character from the original string. If the characters do not belong to Pi, then copy them as is to new new string. Else, copy 3.14 to the new string. At the end, overwrite the original string with the temp string. Example: #include <iostream> #include <string> using namespace std; void replacePi(string& str) { // Our temporay string temp = ""; // Sanity check if (str.length() > 1) { // Iterate over all chararcters in the source string for (size_t i = 0; i < str.length() - 1; ++i) { // Check for Pi in source string if (str[i] == 'P' and str[i + 1] == 'i') { // Add replacement string to temp temp += "3.14"; // We consumed two characters, P and i, so increase index one more time ++i; } else { // Take over normal character temp += str[i]; } } str = temp; } } // Test code int main() { // The test string std::string str{ "Pi is a magical number. Pi is used in many places. Go for Pi" }; // Do the replacement replacePi(str); // Show result std::cout << str << '\n'; }
What you need is string::find and string::replace. Here is an example size_t replace_all(std::string& str, std::string from, std::string to) { size_t count = 0; std::string::size_type pos; while((pos=str.find(from)) != str.npos) { str.replace(pos, from.length(), to); count++; } return count; } void replacePi(std::string& str) { replace_all(str, "pi", "3.14"); }
C++ reverse a string but printing numbers first
I was given a project in class and almost have it finished, I am required to take a string of numbers and letters and return that string with the numbers printed first followed by the letters in reverse order (ex. abc123 should return 123cba). As of now my code returns a string with the numbers first and the original order of the letters (ex. abc123 returns 123abc). I would be able to do this with two loops however the assignment asks that my code only iterates though the initial string one time. Here is the code I have so far... #include <iostream> #include <string> #include "QueType.h" #include "StackType.h" using namespace std; int main () { QueType<char> myQueue; StackType<char> myStack; string myString="hello there123"; char curchar; string numbers, letters; for (int i = 0; i < myString.length(); i++) { if (isdigit(myString.at(i))) { myQueue.Enqueue(myString.at(i)); myQueue.Dequeue(curchar); numbers += curchar; //cout<<numbers<<endl; } else if (islower(myString.at(i))) { myStack.Push(myString.at(i)); curchar = myStack.Peek(); myStack.Pop(); letters += curchar; //cout<<curchar<<endl; } } cout<<(myString = numbers + letters)<<endl; } In my code, I have two .h files that set up a stack and a queue. With the given string, the code loops through the string looking to see if it sees a letter or number. With a number the spot in the string is then saved to a queue, and with a letter it is saved to the stack. The only other way i can think of reversing the order of the letters is in the if else statement instead of having char = myStack.Peek() every loop, change it to char += myStack.Peek() however I get weird lettering when that happens.
since you already got the string with letters you can basically reverse it and that's it. //emplace version: void reverse_str(std::string& in) { std::reverse(in.begin(), in.end()); } //copy version std::string reverse_str(std::string in) { std::reverse(in.begin(), in.end()); return in; } in your case the emplace version would be the best match. in other cases (e.g. when you want to preserve the original string) the copy version is preferred. adding an example to make it as clean as possible. int main() { std::string inputstr = "123abc"; std::string numbers{}; std::string letters{}; for(auto c : inputstr) { if(isdigit(c)) numbers += c; else letters += c; } reverse_str(letters); //using the emplace version std::cout << numbers + letters; }
Here's my take. It only loops through the string once. I don't have your types, so I'm just using the std versions. std::string output; output.reserve( myString.size() ); std::stack<char> stack; for ( char c : myString ) { if ( std::isdigit( c ) ) // if it's a number, just add it to the output output.push_back( c ); else // otherwise, add the character to the stack stack.push( c ); } // string is done being processed, so use the stack to get the // other characters in reverse order while ( !stack.empty() ) { output.push_back( stack.top() ); stack.pop(); } std::cout << output; working example: https://godbolt.org/z/eMazcGsMf Note: wasn't sure from your description how to handle characters other than letters and numbers, so treated them the same as letters.
One way to do this is as follows: Version 1 #include <iostream> #include <string> int main() { std::string s = "abc123"; std::string output; output.resize(s.size()); int i = output.length() - 1; int j = 0; for(char &c: s) { if(!std::isdigit(c)) { output.at(i) = c; --i; } else { output.at(j) = c; ++j; } } std::cout<<output<<std::endl; } You can also use iterators in the above program to obtain the desired result as shown in version 2. Version 2 #include <iostream> #include <string> int main() { std::string s = "abfsc13423"; std::string output; output.resize(s.size()); std::string::reverse_iterator iter = output.rbegin(); std::string::iterator begin = output.begin(); for(char &c: s) { if(!std::isdigit(c)) { *iter = c; ++iter; } else { *begin = c; ++begin; } } std::cout<<output<<std::endl; }
Adding the next character on a string C++
I did get the next character on a string (hello-->ifmmp) but in the case of hello* i want to be able to still display the * as the exception, it can be also a number but i guess it does not matter because is not in the alphabet. this is my code, Where should be the else if? There is another option but i dont find it optimized, it is to add inside the first for loop this: string other="123456789!##$%^&*()"; for(int z=0;z<other.length();z++) { if(str[i]==other[z]) str2+=other[z]; } Then this is the main code; int main() { string str = "hello*"; string str2=""; string alphabet = "abcdefghijklmnopqrstuvwxyz"; for(int i=0;i<str.length();i++) { for(int j=0;j<alphabet.length();j++) { if(str[i]==alphabet[j]) { str2+=alphabet[j+1]; } } } cout<<str2<<endl; return 0; }
I like functions. They solve a lot of problems. For example, if you take the code you already have, paste it into a function, and give it a little tweak char findreplacement(char ch, const std::string & alphabet) { for (int j = 0; j < alphabet.length(); j++) { if (ch == alphabet[j]) { return alphabet[(j+1) % alphabet.length()]; // return the replacement character // using modulo, %, to handle wrap around z->a } } return ch; // found no replacement. Return original character. } you can call the function for (int i = 0; i < str.length(); i++) { str2 += findreplacement(str[i], alphabet); } to build str2. Consider using a range-based for here: for (char ch: str) { str2 += findreplacement(ch, alphabet); } It's cleaner and a lot harder to screw up.
There is a function isalpha in the standard library which is very useful for classification. You could do something like this. (This kind of exercise usually assumes the ASCII encoding of the English alphabet, and this is a very ASCII-specific solution. If you want a different alphabet or a different character encoding, you need to handle that yourself.) #include <cctype> #include <string> #include <iostream> int main() { std::string str = "Hello*Zzz?"; std::string str2; for (char c: str) { if (std::isalpha(c)) { c += 1; if (!std::isalpha(c)) { // Went too far; wrap around to 'a' or 'A'. c -= 26; } } str2 += c; } std::cout << str2 << std::endl; } Output: Ifmmp*Aaa?
Write a recursive function that reverses the input string
I've been reading the book C++ For Everyone and one of the exercises said to write a function string reverse(string str) where the return value is the reverse of str. Can somebody write some basic code and explain it to me? I've been staring at this question since yesterday and can't figure it out. The furthest I've gotten is having the function return the first letter of str (Which I still don't know how it happened) This is as far as I got (An hour after posting this question): string reverse(string str) { string word = ""; if (str.length() <= 1) { return str; } else { string str_copy = str; int n = str_copy.length() - 1; string last_letter = str_copy.substr(n, 1); str_copy = str_copy.substr(0, n); word += reverse(str_copy); return str_copy; } return word; } If I enter "Wolf", it returns Wol. Somebody help me out here If I return word instead of return str_copy then I get a w If I return last_letter then I get an l
I'll instead explain the recursive algorithm itself. Take the example "input" which should produce "tupni". You can reverse the string recursively by If the string is empty or a single character, return it unchanged. Otherwise, Remove the first character. Reverse the remaining string. Add the first character above to the reversed string. Return the new string.
Try this one string reverse(string &s) { if( s.length() == 0 ) // end condtion to stop recursion return ""; string last(1,s[s.length()-1]); // create string with last character string reversed = reverse(s.substr(0,s.length()-1)); return last+reversed; // Make he last character first } A recursive function must have the following properties It must call itself again It must have a condition when the recursion ends. Otherwise you have a function which will cause a stack overflow. This recursive function does basically create a string of the last character and then call itself again with the rest of the string excluding the last character. The real switching happens at the last line where last+reversed is returned. If it would be the other way around nothing would happen. It is very inefficient but it works to show the concept.
Just to suggest a better way of handling recursion: String reversal using recursion in C++: #include <iostream> #include <string> using namespace std; string reverseStringRecursively(string str){ if (str.length() == 1) { return str; }else{ return reverseStringRecursively(str.substr(1,str.length())) + str.at(0); } } int main() { string str; cout<<"Enter the string to reverse : "; cin>>str; cout<<"The reversed string is : "<<reverseStringRecursively(str); return 0; }
I won't write a full-blown algorithm for you, but here's a hint: How about swapping the two outermost characters, and then apply the same to the characters in the middle? Oh, and if that book really proposed string reverse(string str) as an appropriate function signature for this, throw it away and buy a good book instead.
Here is my version of a recursive function that reverses the input string: void reverse(char *s, size_t len) { if ( len <= 1 || !s ) { return; } std::swap(s[0], s[len-1]);// swap first and last simbols s++; // move pointer to the following char reverse(s, len-2); // shorten len of string }
Shortest and easiest class Solution { public: string reverseString(string s) { string str; if(s != "\0"){ str = reverseString(s.substr(1, s.length())); str += s.substr(0,1); } return str; } };
1-line recursive solution: string RecursiveReverse(string str, string prev = "") { return (str.length() == 0 ? prev : RecursiveReverse(str.substr(0, str.length()-1), prev += str[str.length()-1])); } You call it like this: cout << RecursiveReverse("String to Reverse");
I know I shouldn't give a solution, but since no one mentioned this easy solution I though I should share it. I think the code literally is the algorithm so there is no need for a pseudo-code. void c_plusplus_recursive_swap_reverse(std::string::iterator start, std::string::iterator end) { if(start >= end) { return; } std::iter_swap(start, end); c_plusplus_recursive_swap_reverse(++start, --end); } To call it use: c_plusplus_recursive_swap_reverse(temp.begin(), temp.end());
All existing solutions had way too much code that didn't really do anything, so, here's my take at it: #include <iostream> #include <string> std::string r(std::string s) { if (s.empty()) return s; return r(s.substr(1)) + s[0]; } int main() { std::cout << r("testing") << std::endl; } P.S. I stumbled upon this question trying to find a C++ way for std::string of what s+1 for a char * in C is; without going the whole route of s.substr(1, s.length()-1), which looks too ugly. Turns out, there's std::string::npos, which means until the end of the string, and it's already the default value for the second argument, so, s.substr(1) is enough (plus, it also looks more efficient and on par with the simple s + 1 in C). Note, however, that recursion in general doesn't scale as the input grows larger, unless the compiler is able to do what is known as tail-recursion optimisation. (Recursion is rarely relied upon in imperative languages.) However, in order for the tail recursion optimisation to get activated, it is generally required that, (0), the recursion only happens within the return statement, and that, (1), no further operations are performed with the result of the recursive call back in the parent function. E.g., in the case above, the + s[0] is logically done by the parent after the child call completes (and it probably would be so even if you go the more uglier s[s.length()-1] + route), so, it might as well prevent most compilers from doing a tail-recursion-optimisation, thus making the function very inefficient on large inputs (if not outright broken due to heap exhaustion). (For what it's worth, I've tried writing a more tail-recursion-friendly solution (making sure to grow the return result through an argument to the function itself), but disassembly of the resulting binary seems to suggest that it's more involved than that in the imperative languages like C++, see gcc: is there no tail recursion if I return std::string in C++?.)
you can implement your own reverse similar to std::reverse. template <typename BidirIt> void reverse(BidirIt first, BidirIt last) { if((first == last) || (first == --last)) return; std::iter_swap(first, last); reverse(++first, last); }
I did something like this, it did the reversal in place. I took two variables that traverse the string from two extreme end to the centre of the string and when they overlap or equal to each other then reversal terminates. Take an example: input string str = "abcd" and call the function as ReverseString(str,0,str.length()-1); and increment/decrement the variable pointers recursively. First the pointers points to 'a' and 'd' and swap them, then they point to 'b' and 'c' and swap them. Eventually i >= j which calls for the base case to be true and hence the recursion terminates. The main take away for this question is to pass input string as reference. string ReverseString(string& str,int i,int j){ if(str.length() < 1 || str == "" || i >= j){ return ""; } else{ char temp = str[i]; str[i] = str[j]; str[j] = temp; ReverseString(str,i+1,j-1); } return str; }
String can be reversed in-place. If we start from smallest possible string i.e. one character string, we don't need to do anything. This is where we stop or return from our recursive call and it becomes our base case. Next, we have to think of a generic way to swap the smallest string i.e. two characters or more. Simplest logic is to swap the current character str[current_index] with character on the opposite side str[str_length-1 - current_index]. In the end, call the reverse function again for next index. #include <iostream> using namespace std; void reverse_string(std::string& str, int index, int length) { // Base case: if its a single element, no need to swap // stop swapping as soon as we reach the mid, hence index*2 // otherwise we will reverse the already reversed string if( (length - index*2) <= 1 ) { return; } // Reverse logic and recursion: // swap current and opposite index std::swap(str[index], str[length-1 - index]); // do the same for next character (index+1) reverse_string(str, index+1, length); } int main() { std::string s = "World"; reverse_string(s, 0, s.length()); std::cout << s << endl; }
There are already some good answer but I want to add my approach with full working Recursive reversing string. #include <iostream> #include <string> using namespace std; char * reverse_s(char *, char*, int,int); int main(int argc, char** argv) { if(argc != 2) { cout << "\n ERROR! Input String"; cout << "\n\t " << argv[0] << "STRING" << endl; return 1; } char* str = new char[strlen(argv[1])+1]; strcpy(str,argv[1]); char* rev_str = new char[strlen(str)+1]; cout<<"\n\nFinal Reverse of '" << str << "' is --> "<< reverse_s(str, rev_str, 0, strlen(str)) << endl; cin.ignore(); delete rev_str, str; return 0; } char* reverse_s(char* str, char* rev_str, int str_index, int rev_index ) { if(strlen(str) == 1) return str; if(str[str_index] == '\0' ) { rev_str[str_index] = '\0'; return rev_str; } str_index += 1; rev_index -=1; rev_str = reverse_s(str, rev_str, str_index, rev_index); if(rev_index >= 0) { cout << "\n Now the str value is " << str[str_index-1] << " -- Index " << str_in dex << " Rev Index: " << rev_index; rev_str[rev_index] = str[str_index-1]; cout << "\nReversed Value: " << rev_str << endl; } return rev_str; }
void reverse(string &s, int &m) { if (m == s.size()-1) return; int going_to = s.size() - 1 - m; string leader = s.substr(1,going_to); string rest = s.substr(going_to+1,s.size()); s = leader + s.substr(0,1) + rest; reverse(s,++m); } int main () { string y = "oprah"; int sz = 0; reverse(y,sz); cout << y << endl; return 0; }
void ClassName::strgRevese(char *str) { if (*str=='\0') return; else strgRevese(str+1); cout <<*str; }
here is my 3 line string revers std::string stringRevers(std::string s) { if(s.length()<=1)return s; string word=s.at(s.length()-1)+stringRevers(s.substr(0,s.length()-1));//copy the last one at the beginning and do the same with the rest return word; }
The question is to write a recursive function. Here is one approach. Not a neat code, but does what is required. /* string reversal through recursion */ #include <stdio.h> #include <string.h> #define size 1000 char rev(char []); char new_line[size]; int j = 0; int i =0; int main () { char string[]="Game On"; rev(string); printf("Reversed rev string is %s\n",new_line); return 0; } char rev(char line[]) { while(line[i]!='\0') { i++; rev(line); i--; new_line[j] = line[i]; j++; return line[i]; } return line[i]; }
It will reverse Original string recursively void swap(string &str1, string &str2) { string temp = str1; str1 = str2; str2 = str1; } void ReverseOriginalString(string &str, int p, int sizeOfStr) { static int i = 0; if (p == sizeOfStr) return; ReverseOriginalString(str, s + 1, sizeOfStr); if (i <= p) swap(&str[i++], &str[p]) } int main() { string st = "Rizwan Haider"; ReverseOriginalString(st, 0, st.length()); std::cout << "Original String is Reversed: " << st << std::endl; return 0; }
Char array sorting and removing duplicates
I am trying to do some array manipulations. I am doing char array sorting and duplicates removal here. Your comments are welcome. Havent done much testing and error handling here though. #include<stdafx.h> #include<stdlib.h> #include<stdio.h> #include<string> using namespace std; void sort(char *& arr) { char temp; for(int i=0;i<strlen(arr);i++) { for(int j=i+1;j<strlen(arr);j++) { if(arr[i] > arr[j]) { temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } } bool ispresent(char *uniqueArr, char * arr) { bool isfound = false; for(int i=0;i<strlen(arr);i++) { for(int j=0;j<=strlen(uniqueArr);j++) { if(arr[i]== uniqueArr[j]) { isfound = true; return isfound; } else isfound = false; } } return isfound; } char * removeduplicates(char *&arr) { char * uniqqueArr = strdup(""); // To make this char array modifiable int index = 0; bool dup = false; while(*arr!=NULL) { dup = ispresent(uniqqueArr, arr); if(dup == true) {}//do nothing else// copy the char to new char array. { uniqqueArr[index] = *arr; index++; } arr++; } return uniqqueArr; } int main() { char *arr = strdup("saaangeetha"); // if strdup() is not used , access violation writing to //location occurs at arr[i] = arr[j]. //This makes the constant string modifiable sort(arr); char * uniqueArr = removeduplicates(arr); }
If you use std::string, your code (which is actually C-Style) can be written in C++ Style in just these lines: #include <iostream> #include <string> #include <algorithm> int main() { std::string s= "saaangeetha"; std::sort(s.begin(), s.end()); std::string::iterator it = std::unique (s.begin(), s.end()); s.resize( it - s.begin()); std::cout << s ; return 0; } Output: (all duplicates removed) aeghnst Demo : http://ideone.com/pHpPh If you want char* at the end, then you can do this: const char *uniqueChars = s.c_str(); //after removing the duplicates!
If I were doing it, I think I'd do the job quite a bit differently. If you can afford to ignore IBM mainframes, I'd do something like this: unsigned long bitset = 0; char *arr = "saaangeetha"; char *pos; for (pos=arr; *pos; ++pos) if (isalpha(*pos)) bitset |= 1 << (tolower(*pos)-'a'); This associates one bit in bitset with each possible letter. It then walks through the string and for each letter in the string, sets the associated bit in bitset. To print out the letters once you're done, you'd walk through bitset and print out the associated letter if that bit was set. If you do care about IBM mainframes, you can add a small lookup table: static char const *letters = "abcdefghijklkmnopqrstuvwxyz"; and use strchr to find the correct position for each letter. Edit: If you're using C++ rather than C (as the tag said when I wrote what's above), you can simplify the code a bit at the expense of using some extra storage (and probably being minutely slower): std::string arr = "saaangeetha"; std::set<char> letters((arr.begin()), arr.end()); std::copy(letters.begin(), letters.end(), std::ostream_iterator<char>(std::cout, " ")); Note, however, that while these appear the same for the test input, they can behave differently -- the previous version screens out anything but letters (and converts them all to lower case), but this distinguishes upper from lower case, and shows all non-alphabetic characters in the output as well.
char *arr = "saangeetha"; arr is pointing to read only section where string literal saangeetha is stored. So, it cannot be modified and is the reason for access violation error. Instead you need to do - char arr[] = "sangeetha"; // Now, the string literal can be modified because a copy is made.