Issues with permutation function and swapping string values - c++

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

Related

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.

Get all N consecutive characters in string using stringstream in C++

I would like something that can window a std::string object into partitions of length N - for example (using a function update):
int main() {
std::string s = "abcdefg";
update<2>(s);
return 0;
}
Calling the above should result in:
ab
bc
cd
ef
fg
I have the following version of the update function:
template<std::size_t size>
void update(std::string s) {
std::string result(size, '\0');
std::stringstream ss{s};
int iterations = s.length() - size;
for (int i = 0; i<iterations; i++) {
ss.read(&result[0], result.size());
std::cout << result << std::endl;
}
return;
}
but this skips out combinations where the initial character lies at an odd index (the number of combinations is correct in my case, even though there is a repeat)
ab
cd
ef
gf
gf
A side note is that if there are any trailing characters then these should be omitted from the printed values (although I think this would be covered by the parameters of the for loop)
A final note is that I would like this to be as optimised as possible since I would typically be using strings of a very large length (>5M characters long) - my current solution may not be best for this so I am open to suggestions of alternative strategies.
With C++17 you can do it like this, which is way more readable:
void update(std::string_view s, int size) {
const int iterations = s.size() - size;
for (int i = 0; i <= iterations; i++) {
std::cout << s.substr(i, size) << "\n";
}
}
string_view is made exactly for this purpose, for fast read access to a string. string_view::substr is const complexity while string::substr is linear.
As a side note, besides what Nick mentioned, your code has few other small problems:
std::endl fflushes the stream, it heavily impacts performance. Here you could just use '\n' to make a newline.
the return at the end is absolutely redundant, void functions do not require returns
what is the purpose of templating this? This will easily bloat your code without any measurable performance increase. Just pass the N as a parameter.
also your main is declared as void and should be int (even more so as you do return a value at the end)
With range-v3, you might use sliding view:
std::string s = "abcdefg";
for (auto r : s | ranges::views::sliding(2)) {
std::cout << r << std::endl;
}
Demo
Your call to ss.read will always read two characters, and then advance the ptr in the string stream 2 characters. So you never read/repeat the previous character at the start of each line.
If you want to do it "your way" then you have to keep track of the last character seperately.
#include <iostream>
#include <sstream>
template<std::size_t size>
void update(std::string s) {
std::string result(size, '\0');
char lastChar;
std::stringstream ss{s};
int iterations = s.length() - size;
int read = 0;
if (ss.readsome(&result[0], 1)) {
lastChar = result[0];
}
for (int i = 0; i < iterations; i++) {
if (read = ss.readsome(&result[0], size - 1)) {
std::cout << lastChar << result << std::endl;
lastChar = result[read - 1];
}
}
}
That being said, the above is definitely not the best approach performance wise. You should be able to do all of this without any string streams or read function, just iterating the string. Something like this
#include <iostream>
void update(std::string s, size_t size) {
int len = s.length();
for (int i = 1; i < len; i+=size-1) {
fwrite(&s[i-1], size, 1, stdout);
putchar('\n');
}
}

Reversing characters from input

I am trying to reverse a char which has been provided in input from an user. I am having issues with the reverse function, particularly the loop. I can't get it to work- can I get advice?
#include <iostream>
using namespace std;
#include <cstring>
char* reverse(char* input) {
int len = strlen(input);
char temp[len];
for(int i=len; i>len; --i) {
temp[i]+=input[i];
}
return temp;
}
int main()
{
char input[100];
while(cin>>input) {
cout << reverse(input);
}
return 0;
}
Your Program has few issues
You're trying to return local variable address i.e. temp array address. The Function will return the address to main function. Since memory might get cleaned so it will print garbage value present at the address.
As Rohan Bari mentioned variable length array might cause undefined behavior. There for you can create a constant length array i.e.
char temp[100];
or you can dynamically allocate array on heap. Memory allocated on heap do not get cleared after termination of block but we have to manually delete it.
char* temp = new char[len];
As array start from 0 it goes till len-1 so loop condition should start from len-1 and has to go till 0 to reverse.
+ operator do not work's with array or char even if you are trying to add just char it preforms normal integer addition of their ASCII value.
Here is improved version of your code
#include<iostream>
using namespace std;
#include <cstring>
char* reverse(char* input) {
int len = strlen(input);
char* temp = new char [len]; // or you can use char temp[100];
int j = 0; //temp variable to enter values from 0th index if we use same as loop it just enter in the same order as original char array.
for(int i=len-1; i>=0; --i) {
temp[j++] = input[i];
}
temp[j] = '\0';
return temp;
}
You have got several errors in the program.
The variable-length arrays are used here:
char temp[len];
This should not be applied in C++ since this invokes undefined-behavior. Note that this is a valid statement in the C99 standard.
There is a better alternative to this. That is to take the std::string built-in type in use.
In the following line:
temp[i] += input[i];
You are not sequentially adding one character after another, but the values of them in a single integer. This could be not a problem if temp was of the type std::string.
The reverse function should look like this:
const char *reverse(char *input) {
int len = strlen(input);
std::string temp;
while (len--)
temp += input[len];
return temp.c_str();
}
len should actually be (len-1) and i should be >= 0 not len, so from (len-1) to 0 your loop should run.
for(int i = len-1; i >= 0; i--){}
You have to allocate the new array with the new keyword if you don't want to use a string. The following code does what you need:
char* reverse(char* input)
{
int len = strlen(input);
char* temp = new char[len + 1];
for (int i = len; i >= 0; --i)
{
temp[len-i-1] = input[i];
}
temp[len] = '\0';
return temp;
}
You could use a std::stack to reverse your input:
std::stack<char> s;
char c;
while (std::cin >> c)
{
s.push(c);
}
while (!s.empty())
{
std::cout << s.top();
s.pop();
}
It's 2021. Use the STL. If your instructor isn't aware of it or doesn't allow you to use it, your instructor is not keeping up-to-date and you should fire your instructor.
#include <algorithm>
#include <iostream>
#include <string>
int main() {
std::string input{};
while(std::getline(std::cin, input)) {
std::reverse(std::begin(input), std::end(input));
std::cout << input << '\n';
}
return 0;
}
There's quite many things wrong with the code as many people have already mentioned! Since you want to implement this without using STL it can be done this way,
#include <iostream>
using namespace std;
#include <cstring>
void reverse(char* input,int len) { //added len as argument
char temp[len];
for(int i=len-1; i>=0; --i) {
temp[len-i-1]=input[i];
cout<<temp[len-i-1]; //printing while reversing
}
cout<<endl;
}
int main()
{
char input[100];
int len=0;
//using do while since it has to run atleast once
do{
cin.getline(input,100);
len=strlen(input);
input[len]='\0';
if(len!=0)
reverse(input,len);
}while(len!=0) ;
return 0;
}

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

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

mingwCC compile error (Eclipse Juno)

Okay, so I am trying to compile something right now and I am new to C++ so maybe the code itself is causing the error however no red marks show up in the code itself that Eclipse is showing me.
Here is what the error says
c:\mingw\bin../lib/gcc/mingw32/4.6.2/include/c++/bits/move.h:128:7:
error: assignment of read-only reference '__a'
c:\mingw\bin../lib/gcc/mingw32/4.6.2/include/c++/bits/move.h:129:7:
error: assignment of read-only reference '__b'
Any ideas on what I need to do? on a Win7, using Eclipse Juno for C++ with MingwCC
Here is what I am compiling, the only new thing I added was this "swap" thing that someone told me to use for my permutation program.
UPDATED
Permutation.cc
#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(string str) {
int low = 0;
int high = str.length();
int j;
if (low == high) {
cout << str << endl;
} else {
for (j = low; j <= high; j++) {
std::swap(str[low], str[j]);
permute(str, low + 1, high);
std::swap(str[low], str[j]);
}
}
}
void Permutation::permute(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]);
// }
// }
}
Permutation.h
#pragma once
#include <string>
using namespace std;
class Permutation {
public:
Permutation();
void permute (string);
void permute (string, int, int);
private:
/* attemp to solve this problem without adding
* any instance variables/data members, but
* you may add private helper function members
* as many as you need */
};
main.cc
#include "Permutation.h"
int main()
{
Permutation p;
p.permute ("Permute");
p.permute ("--*--", 2, 3);
}
I rewrote the C code you linked to in C++:
// this method should be private or protected because
// str is passed by reference and will be modified !
// if you prefer a free standing function, don't add the
// declaration to the header, this for internal use only
void do_permute(std::string& str, unsigned i, unsigned n) {
// you COULD pass str by value here, which
// would remove the need to backtrack.
// however, it would create a new copy for every
// iteration which is terrible for performance,
// especially with long strings.
if(i==n)
std::cout << str << '\n';
else
for(unsigned j=i; j<=n; ++j) {
std::swap(str[i],str[j]);
do_permute(str,i+1,n);
std::swap(str[i],str[j]); // backtrack (undo swap)
}
}
// this is the public method;
// pass string by value (copy), to allow do_permute()
// to modify the string.
void permute(std::string str, unsigned i=0, unsigned n=0) {
if( n >= str.length() )
return; // prevent out of bounds access
// if n is 0 (default value) use the string length instead
do_permute(str, i, n ? n : (str.length()-1) );
}
int main() {
permute("BAR");
permute("FO0BAR", 3); // FOO***
permute("FO0BAR", 0, 2); // ***BAR
}
Figured out how to swap it correctly.
int low = 0;
int high = str.length() - 1;
// make sure the string is a permutation and not a partial mix.
if (low == high) {
cout << str << endl;
} else {
//Takes each initial letter, then permutes the remaining string. Then moves to next character.
for (int i = low; i <= high; i++) {
std::swap(str[low], str[i]);
permute(str, low + 1, high);
std::swap(str[low], str[i]);
}
}