`std::swap` doesn't work as intended in string manipulation - c++

I have tried to make basic string encryption, by swapping two consecutive letters.
And it didn't really work as I intended.
#include <iostream>
#include <string.h>
#include <algorithm>
int main()
{
std::string str = "This is a simple string.";
for (int i = 0; i <= str.length(); i++) {
std::swap(str[i], str[i + 1]);
}
std::cout << str;
std::cin.get();
}
I want to actually swap two near letters, so it will look like encrypted.
The Current result is
his is a simple string.

First of all, you have out of bound access because of
for (int i = 0; i <= str.length(); i++)
// ^^^^
hence the behavior of your program is undefined.
You want to iterate one past the size of the string. In addition to that, loop only if the string is not empty(credits #jww).
Secondly, there is a comparison between int and unsigend int(i.e. str.length()) which is also not you want.
Last but not least, add the proper header for std::string(as #PaulMcKenzie pointed out in the comments).
Altogether, you probably want this
#include <string>
for (std::size_t i = 0; !str.empty() && i < str.size()-1; i += 2) {
// ^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^
std::swap(str[i], str[i + 1]);
}

I think you were aiming for something like:
std::string str = "This is a simple string.";
for (int i = 0; i <= str.length()-2; i+=2)
{
std::swap(str[i], str[i + 1]);
}
std::cout << str;
with output
hTsii s aispmels rtni.g

Related

Reversing each word in a string without changing the order in C++

I am writing a code in C++ to reverse all the words in a string without changing the order of the list
This is my code:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s = "God Ding";
int n = s.size();
int i = 0, j = 0;
while(j < n){
if(s[j] == ' ' || j == n-1){
reverse(s.begin()+i, s.begin()+j);
j++;
i = j;
}
else{
j++;
}
}
cout << s;
return 0;
}
Expected Output: "doG gniD"
My output: doG Ding
2nd input: "Let's take LeetCode contest"
Expected Output: "s'teL ekat edoCteeL tsetnoc"
My Output: "s'teL ekat edoCteeL contest"
Everything is working fine but only the last word is not getting reversed
You need either to detect in your if the special situation of processing the last character, or add an extra reverse after the while, if the last word was not processed (i.e. the last char was not a space).
In your case, you've added the detection of last character, but did not process the reverse before the increment, as would be the case if the word ended with a space. To correct this situation, you must take into account this special situation:
if(s[j] == ' ' || j == n-1){
reverse(s.begin()+i, s.begin()+j+(j==n-1?1:0));
// ^ (if it's last, take +1)
...
I think this would be a better implementation for your code:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string s = "God Ding", reversed_string;
std::string word;
std::istringstream ss(s); // Declaring an in string stream
while (std::getline(ss, word, ' ')) // Here getline gets every word in ss and stores it in the variable 'word'
{
// This loop reverses the variable 'word'
for (int i = word.size() - 1; i >= 0; i--)
{
reversed_string.push_back(word[i]);
}
reversed_string.push_back(' ');
}
std::cout << reversed_string;
return 0;
}
Also look up to why is "using namespace std" considered as a bad practice.
Here you have a working example:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string s = "God Ding";
int i = 0;
int j = 0;
while (i <= s.length()) {
if (i == s.length() || s[i] == ' ') {
std::reverse(s.begin() + j, s.begin() + i);
j = i + 1;
}
i++;
}
std::cout << s << std::endl;
return 0;
}
I changed a lot of things.
These are the issues you need to fix:
Make your loop go beyond the last char.
Reverse if j (from your code) is beyond the last char.
In order to reverse a word, you need i to index the first char, and j to index the char after the last one.
However, your loop exits whenever j indexes the char after the last one. That's why it never reverses the last word.
The simplest fix is to do one more check after the loop exits, and reverse the last word if there is one:
while(j < n) {
if(s[j] == ' ') { // remove the `j==n-1` test
reverse(s.begin()+i, s.begin()+j);
j++;
i = j;
} else {
j++;
}
}
if(i < j) {
reverse(s.begin()+i, s.begin()+j);
}
The alternative would be to rewrite the loop in some way that finesses the problem. I don't really recommend this, given that you have something that almost works and that you know how to fix.

std::copy doesn't copy vector in C++

To find all sequences of fixed length which contain only 0 and 1 I use this code:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
void print_array(vector<string> arr) {
cout << '[';
int n = arr.size();
for (size_t i = 0; i < n; i++) {
cout << arr[i];
if (i < (n - 1)) {
cout << ", ";
}
}
cout << ']' << endl;
}
vector<string> get_variants(int n) {
vector<string> result = {"0", "1"};
vector<string> temp;
temp.reserve(2);
result.reserve(2);
for (int i=0; i < (n - 1); ++i) {
copy(result.begin(), result.end(), temp.end()); // [1]
for (int j=0; j < result.size(); ++j) {
temp[j] += "0";
result[j] += "1";
}
copy(temp.begin(),temp.end(), result.end());
temp.clear();
}
return result;
}
int main(int argc, char const *argv[]) {
int n;
cin >> n;
vector<string> maybe = get_variants(n);
print_array(maybe);
return 0;
}
But vector temp is empty, before copying in line which I marked [1] and after. So, my program's output was [0111, 1111]. What I'm doing wrong?
A more straightforward way than using std::copy is the use of .insert():
temp.insert(temp.end(), result.begin(), result.end()); //1
...
result.insert(result.end(), temp.begin(), temp.end()); // 2nd copy
You are writing to temp.end() and result.end(). These iterators represent "one past the end", and therefore writing to these iterators is Undefined Behavior.
You seem to be looking for std::back_inserter. This will create an iterator that will insert a new element to your container when it is written through.
std::copy(result.begin(), result.end(), std::back_inserter(temp));
While this answers the posted question, there remain other errors in your code leading to Undefined Behavior.
Trying to compile your program with a C++ compiler will not work, because you include #include <bits/stdc++.h>which is a non tC++ standard compliant header.
You should never include this file.
You are using typical competitive programming stuff, but including all C++ headers and not use them will eat up Compile time for no good reason.
Then, you typedef the typical competitive programming abbreviations. 2 of them, you do not use. Then there is no reason to define them.
I recommend to not do this any longer. And in C++, please use the using statement.
Then, although you want to be fast, you pass arr by value to your print function. This will copy the whole vector.
You assign/compare a lot of int with unsigned int values. This you should not do.
Additionally: Please use meaningful variable names and write comments. The more the better.
Regarding your specific bug. Both std::copy statements use end iterator as target. End is end. It is past the end of the vector. Please use std::back_inserter instead.
Regarding the algorithm. I took a while for me to realize that you basically want to create binary numbers. Nothing else. Unfortunately you translated that in a very complicated way.
Normally, you just would count from 0 to 2^n-1 and then show the data. Thats all. Becuase the numbers may be of arbitraty length, we will use manual addition of digits like in scholl on a peice of paper. Very simple.
Everthing then biols down to some lines of code.
Please see:
#include <iostream>
#include <vector>
int main() {
// Read length of binary number to create and validate input
if (int numberOfDigits{}; (std::cin >> numberOfDigits and numberOfDigits > 0)) {
// Here we will store the binary digits, so 0s or 1s
std::vector<int> digits(numberOfDigits,0);
// Som printing helper
std::cout << '[';
bool printComma{};
// We need to print 2^n possible combinations
for (int i = 0; i < (1 << numberOfDigits); ++i) {
// Print comma, if need
if (printComma) std::cout << ','; printComma = true;
// Print all digits of the binary number
for (const int d : digits) std::cout << d;
// Calculate next binary number
int carry = 0;
for (int index=numberOfDigits -1; index >=0; --index) {
const int sum = digits[index] + ((index == (numberOfDigits - 1)?1:0)) + carry;
carry = sum / 2;
digits[index] = sum % 2;
}
}
std::cout << ']';
}
}
If there should be questions, then I am happy to answer.

I have a char array and I want to insert two more spaces for each space

My logic is as follows :
#include<bits/stdc++.h>
using namespace std;
int main(){
char a[50] = {'h','i',' ','m','e',' ','t','e'};
// k = 4 because i have 2 spaces and for each
// space i have to insert 2 spaces . so total 4
//spaces
int k=4;
for(int i=strlen(a)-1 ; i>0 && k >0 ; i--){
if(a[i] != ' ')
{
a[i+k] = a[i];
a[i] = ' ';
}
else
{
k = k - 2;
}
}
printf("%s" , a);
return 0;
}
I have to character array to solve it. I am able to
do it using string stl
The output i get is
hi---me.
But the answer is
hi---me---te.
Your code is tagged C++. But there is nothing C++ in your code. It is pure C.
And, your are including #include<bits/stdc++.h> and using the std namespace using namespace std;. From now on: Please never ever in your whole life do such things again. Or, stop working with C++.
Additionally never ever use plain C-style array like your char a[50] in C++.
In your code you have some bugs. Most critical is the missing terminating 0 and then calling strlen. Before you use a function, always check somewhere, how this function works. Use meaningful variable names. Write comments. Always check boundaries.
I updated your C-Code:
#include <stdio.h>
int main()
{
// Character String to work on
char charString[50] = "hi me te";
// Check all possible positions in string
for (int index = 0; (index < 49) && (0 != charString[index]); ++index)
{
// If there is a space in the string
if (' ' == charString[index])
{
// Shift all characters one position to the right
for (int shiftPosition = 48; shiftPosition >= index; --shiftPosition)
{
charString[shiftPosition + 1] = charString[shiftPosition];
}
++index;
}
}
// Show result
printf("%s\n", charString);
return 0;
}
And here the C++ solution
#include <iostream>
#include <string>
#include <regex>
int main()
{
// Text to work on
std::string text("hi me te");
// Replace every space with 2 spaces. Print result
std::cout << std::regex_replace(text, std::regex(" "), " ");
return 0;
}

String output gives weird letters

#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
string s = "Too many tags";
for(int i = 0; i < s.size(); i++){
if(!(isspace(s[i]))){
s[i] = '#' + s[i];
}
}
cout << s << endl;
return 0;
}
I'm trying to make a program which adds # tag before each letter in the string, but on output I get weird letters.. where is my mistake?
s[i] = '#' + s[i];
modifies the value of an existing character. If you want to add new characters into your string, you should use insert:
s.insert(i, "#");
As Mark Ransom points out, you also need to move one further char through your string to avoid constantly adding "#" before the same letter. You could do this using
s.insert(i++, "#");
Note that you could always take VladimirM's advice and make slightly larger changes to something like
int i=0;
while (i<s.size()) {
if (!isspace(s[i])) {
s.insert(i++, "#");
}
i++;
}
This line:
s[i] = '#' + s[i];
isn't doing what you think it is. s[i] is a char, # is also a char. Adding these together doesn't give you the concatenation of the two characters, it gives you the addition of the integer code of the characters (so 35 for # and the ASCII code for whatever s[i] happens to be).
I add more: I think the simpler way is to use temporary variable otherwise your loop with 'insert' will go to endless loop and will hang:
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
string s = "Too many tags";
string res = "";
for(int i = 0; i < s.size(); i++){
if(!(isspace(s[i]))){
res += "#";
}
res += s[i];
}
cout << res << endl;
return 0;
}

Issues with permutation function and swapping string values

Okay, so I need some help getting my string to swap around.
Here is the overall code of what I am trying to do, but I can't just move the string around. I started off trying to convert it to characters but the majority of replies said to just use the std::swap function, however I am really lost in using this...
My overall goal is to permute a string, which can be specified to a certain section of the string. I am new to C++, I am just unsure how to use C++ methods/functions in order to achieve this.
(there is also a main.cc and Permutation h. but its only for defining variables, skeletal code basically)
All help appreciated, I shall check back here in about 2 hours.
UPDATED CODE)
#include <iostream> // for cout
#include <cstdio> // for printf()
#include <sstream> // for stringstream
#include <stdio.h>
#include <string.h>
#include "Permutation.h"
using namespace std;
Permutation::Permutation() {
/* nothing needed in the constructor */
}
void Permutation::permute(const string& str) {
string stringnew = str;
int j;
int low = 0;
int high = str.length();
cout << stringnew << endl;
for (j = 0; j <= high; j++) {
string strtemp = stringnew[j];
std::swap((strtemp + low), (strtemp + j));
permute(str, low + 1, high);
std::swap(str[j + low], str[j + j]);
}
}
void Permutation::permute(const string& str, int low, int high) {
// int j;
// if (low == high) {
// cout << str << endl;
// } else {
// for (j = low; j <= high; j++) {
// std::swap(str[j + low], str[j + j]);
// permute(str, low + 1, high);
// std::swap(str[j + low], str[j + j]);
// }
// }
}
You must work through the class interface. You cannot get a writeable character array from a std::string.
What you can do is use the array subscript operator and access it as str[i]. You can also use iterators.
The reason for this is that prior to C++03, std::string was not required to be a character array. It could be discontinuous. At least one implementation used a std::deque style "array of pointers to arrays" backing store, which gave it fast insert, prepend and delete-from-the-middle abilities.
Also, from an Object Oriented programming design perspective, it is Not Nice to reach into an object's guts and rearrange them.
Just for fun because I wanted a break from work, some code that messes with a string using array subscripts:
#include <cctype>
#include <string>
#include <iostream>
void uc(std::string &s)
{
size_t i;
const size_t len = s.length();
for(i=0; i<len; ++i) {
s[i] = toupper(s[i]);
}
}
void mix(std::string &s)
{
size_t i;
const size_t len = s.length();
for(i=1; i<len/2+1; ++i) {
std::swap(s[i-1], s[len-i]);
}
}
int main()
{
std::string s("Test String");
uc(s);
std::cout << s << std::endl;
mix(s);
std::cout << s << std::endl;
return 0;
}
Just take the c_str()-function
std::string str("I'm a text");
char *pStr = str.c_str();
This is C++ not java as in thread you pointed.
First of all
char[] x
is valid declaration only for compile time known sizes of table.
The other thing is that std::string does not have .toCharArray method but it has .c_str() method you can use to get const char* from std::string.
HTH