I'm writing a program that solves Caesar ciphers in C++. It takes a string of the alphabet and shifts it to the left each loop: "abc....yz" --> "bcd.....yza". The problem is after another loop it goes: "bcd.....yza" --> "cde.....yzaa".
char temp; // holds the first character of string
string letters = "abcdefghijklmnopqrstuvwxyz";
while (true)
{
temp = letters[0];
for (int i = 0; i < 26; i++)
{
if (i == 25)
{
letters += temp;
}
letters[i] = letters[i + 1];
cout << letters[i];
}
cin.get();
}
Copy and paste that code and you'll see what I'm talking about. How do I fix this mysterious problem?
If I'm not mistaken, your loop does precisely the same as the following code:
letters = letters.substr(1,25) + letters.substr(0,1);
// [skip 1, take 25] + [first char goes last]
I think you need letters to be 27 characters, not 26, and instead of letters += temp (which grows the string every time), use letters[26] = temp[0].
...at which point you can just ditch temp entirely:
string letters = "abcdefghijklmnopqrstuvwxyz.";
while (true)
{
letters[26] = letters[0];
for (int i = 0; i < 26; i++)
{
letters[i] = letters[i + 1];
cout << letters[i];
}
cin.get();
}
[edit]
Although the more natural way to handle this is to use arithmetic on the characters themselves. The expression 'a' + ((c - 'a' + n) % 26) will shift a char c by n places Caesar-style.
You can achieve this easily using valarray< char >::cshift(n) (cyclical shift) method.
Related
I was training on solving algorithms, I wrote a code but it won't compile
in (if) I can not check s[i]=='S' .
I'm trying to if s[i] is S character or not but I don't know where my problem is.
If I can't use this syntax, what could be a solution?
#include<iostream>
#include<string>
using namespace std;
int main()
{
double v_w=25,v_s=25,d_w=25,d_s=25;
int n;
cin>>n;
string s[]={"WSSS"};
int i ;
for (i=0; i<n; i++)
{
if( s[i] == "W" )
{
v_s += 50;
d_w = d_w + (v_w/2);
d_s = d_s + (v_s/2);
cout<<"1 \n";
}
if(s[i]=='W')
{
v_w +=50;
d_w = d_w + (v_w/2);
d_s = d_s + (v_s/2);
cout<<"2 \n";
}
return 0;
}
cout<< d_w<<endl<<d_s;
}
string s[]={"WSSS"}; means an array of strings which the first one is "WSSS".
What you need is:
std::string s="WSSS";
string s[] = {"Hello"} is an array of strings (well, of one string).
If you iterate over it, or index into it s[0] is "Hello".
Whereas
string s{"Hello"} is one string, which is made up of characters.
If you iterate over it, or index into it s[0], you will get 'H'.
To pre-empt all the other things that are going to go wrong when the string versus character problem is sorted, lets move the return 0; from the middle of the for loop.
Then let's think about what happens if the number n entered is larger than the length of the string:
int n;
cin>>n; //<- no reason to assume this will be s.length (0 or less) or even positive
string s{"WSSS"}; //one string is probably enough
int i ;
for(i=0;i<n;i++)
{
if( s[i] == 'W' ) //ARGGGGGGG may have gone beyond the end of s
{
In fact, let's just drop that for now and come back to it later. And let's use a range based for loop...
#include<iostream>
#include<string>
using namespace std;
int main()
{
double v_w = 25, v_s = 25, d_w = 25, d_s = 25;
string s{ "WSSS" };
for (auto && c : s)
{
if (c == 'W')
{
v_w += 50;
d_w = d_w + (v_w / 2);
d_s = d_s + (v_s / 2);
cout << "2 \n";
}
}
cout << d_w << '\n' << d_s << '\n'; //<- removed endl just because...
return 0;
}
s is an array of strings in this case it has only element:
string s[] = {"WSSS"};
so writing s[2]; // is Undefined behavior
your code will produce a UB if the user enters n greater than the number of elements in s:
n = 4;
for(i = 0; i < n; i++) // s[3] will be used which causes UB
{
if( s[i] == 'W' ) // s[i] is a string not just a single char
{
}
}
also as long as s is an array of strings then to check its elements check them as strings not just single chars:
if( s[i] == "W" ) // not if( s[i] == 'W' )
I think you wanted a single string:
string s = {"WSSS"};
because maybe you are accustomed to add the subscript operator to character strings:
char s[] = {"WSSS"};
if so then the condition above is correct:
if( s[i] == 'W' )
Having some trouble understanding parts of the code; the output I am getting is also wrong. The problem is to replace all spaces in a string with '%20'. The full code is shown below; it compiles but doesn't run exactly as it should.
#include <iostream>
#include <string>
using namespace std;
void replaceSpaces(string str){
//Getting the length of the string, counting the number of spaces
int strLen = str.length();
int i, count = 0;
for (i = 0; i <= strLen; i++) {
if(str[i]==' ')
count++;
}
//Determining the new length needed to allocate for replacement characters '%20'
int newLength = strLen + count * 2;
str[newLength] = '\0';
for (i = strLen - 1; i >= 0; i--) {
if (str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
}
else {
str[newLength - 1] = str[i];
newLength = newLength -1;
}
}
cout << str <<endl;
}
int main() {
string str = "hello jellybean hello";
replaceSpaces(str);
return 0;
}
I am probably missing something obvious, but when allocating for the new string length in this line:
int newLength = strLen + count * 2;
Here we are multiplying the number of spaces by 2, but if we are trying to replace all spaces with '%20', why not multiply it by 3?
str[newLength] = '\0';
Does this line indicate that the position past the last character in the string is assigned a null space?
Am also confused about the else statement.
else {
str[newLength - 1] = str[i];
newLength = newLength -1;
}
Not sure if I completely understand the circumstance when this would be executed.
When the functions are compiled and run, if
string str = "hello jellybean hello";
the expected output would be hello%20jellybean%20hello, except the output I am getting is hello%20jellybean%20h.
In terms of time complexity, since there are two independent for loops, would the time complexity be O(n)?
I know I'm asking a lot of different questions, many thanks in advance for any answers!
This is wrong:
str[newLength] = '\0';
std::string objects maintain their NUL terminator internally based on their size. You want
str.resize(newLength);
instead.
int newLength = strLen + count * 2;
says to allocate space (later), equal to the length of the string, plus the number of whitespaces found multiplied by two, which makes sense.
For example: so glad to help, should use the slots that the whitespaces live into for the % and they will need two more slots each, for the 20 part of the replacement that will come into play.
This is WRONG:
str[newLength] = '\0';
can't you see? You access memory out of the bounds of your string. You act like you actually allocated space equal to the newLength, but you haven't that anywhere in the code yet.
Out of bounds accessing result in Undefined Behavior and that's bad.
The else statement is just for copying non-whitespace characters, but you should already given up on that code (if it's not yours) and start from scratch or/and take a sneak peak at: Encode/Decode URLs in C++.
As for the wrong result, you should know by reaching that point of that answer, that this is expected.
Trying to do the modification in place is tricky. It's much easier to create a new string:
std::string new_string;
for (int i = 0; i < str.length(); ++i) {
if (str[i] == ' ')
new_string += "%20";
else
new_string += str[i];
}
return new_string;
or, if you like range-for:
std::string new_string;
for (char ch : str) {
if (ch == ' ')
new_string += "%20";
else
new_string += ch;
}
return new_string;
You can change that string argument in function to reference, then there wont be any need for new string, at other part of the code, you can use insert function to add '2' and '0', and you only need to convert space to '&'.
void replaceSpaces(string &str) {
size_t strLen = str.length();
for (int i = 0; i < strLen; i++) {
if (str[i] == ' ') {
str[i] = '%';
str.insert(str.begin() + i + 1, '2');
str.insert(str.begin() + i + 2, '0');
strLen += 2;
}
}
}
This is easy; replace examplestring with your string in the code, and use as you would:
#include <iostream> //debug output
#include <string>
using std::string;
using std::cout;
using std::endl;
//the string to convert
string examplestring = "this is the example string for spaces into %20";
int main()
{
int countspaces = 0; //its faster to fill a known size
for (auto &x : examplestring)if (x == ' ')countspaces++; //counts spaces
string newstring; //declare new string
newstring.resize(examplestring.size() + (countspaces*3)); //pre-set size to make it run faster
int newstringiterator = 0; //keep track of new string location
//if ' '(space), place %20 in newstring and add 3 to iteration
//else just place the letter and iterate
for (int i=0;i<examplestring.size();i++)
{
if (examplestring[i] == ' ')
{
newstring.insert(newstringiterator, "%20");
newstringiterator += 3;
}
else newstring[newstringiterator++] = examplestring[i];
}
//final newstring is the original with %20 instead of spaces.
cout << newstring << endl;
system("PAUSE"); //to read console output
return 0; //return to zero
}
This will output newstring, which is the old string with '%20' instead of spaces.
I need to insert symbol '+' into string after its each five symbol.
st - the member of class String of type string
int i = 1;
int original_size = st.size;
int count = 0;
int j;
for (j = 0; j < st.size; j++)
{
if (i % 5)
count++;
}
while (st.size < original_size + count)
{
if (i % 5)
{
st.insert(i + 1, 1, '+');
st.size++;
}
i++;
}
return st;
I got an error in this part of code. I think it is connected with conditions of of the while-cycle. Can you help me please how to do this right?
If I've understood you correctly then you want to insert a '+' character every 5 chars in the original string. One way to do this would be to create a temporary string and then reassign the original string:
std::string st("A test string with some chars");
std::string temp;
for (int i = 1; i <= st.size(); ++i)
{
temp += st[i - 1];
if (i % 5 == 0)
{
temp += '+';
}
}
st = temp;
You'll notice I've started the loop at 1, this is to avoid the '+' being inserted on the first iteration (0%5==0).
#AlexB's answer shows how to generate a new string with the resulting text.
That said, if your problem is to perform in-place insertions your code should look similar to this:
std::string st{ "abcdefghijk" };
for(auto i = 4; i != st.size(); i += 5)
st.insert(i+1, 1, '+'); // insert 1 character = '+' at position i
assert(st == "abcde+fghij+k");
std::string InsertEveryNSymbols(const std::string & st, size_t n, char c)
{
const size_t size(st.size());
std::string result;
result.reserve(size + size / n);
for (size_t i(0); i != size; ++i)
{
result.push_back(st[i]);
if (i % n == n - 1)
result.push_back(c);
}
return result;
}
You don't need a loop to calculate the length of the resulting string. It's going to be simply size + size / 5. And doing multiple inserts makes it a quadratic-complexity algorithm when you can just as easily keep it linear.
Nothing no one else has done, but eliminates the string resizing and the modulus and takes advantage of a few new and fun language features.
std::string temp(st.length() + st.length()/5, '\0');
// preallocate string to eliminate need for resizing.
auto loc = temp.begin(); // iterator for temp string
size_t count = 0;
for (char ch: st) // iterate through source string
{
*loc++ = ch;
if (--count == 0) // decrement and test for zero much faster than
// modulus and test for zero
{
*loc++ = '+';
count = 5; // even with this assignment
}
}
st = temp;
Here is my function to reverse a string:
void reverse(char *str){
int lengthStr = strlen(str);
int j, i;
char reversedString[100];
for (j = 0, i = lengthStr-1; i >= 0; i--, j++){
reversedString[j] = str[i];
}
cout << reversedString;
}
The string does appear as reversed, but at the end there's a bunch of weird characters that appears. What could be causing this issue?
If you want to reverse the string there are many cleaner approaches already available like: std::reverse_copy etc.
But if you want to fix this function then try this:
char reversedString[100];
memset(reversedString, 0, 100*sizeof(char);
OR
for (j = 0, i = lengthStr-1; i >= 0; i--, j++){
reversedString[j] = str[i];
}
reversedString[j] = '\0'; //! Add null character at the end to indicate end of the string
cout << reversedString;
Note: Your program fails if input string has length >= 100.
Add a zero to the characters you assigned to reversedString. Otherwise, the unitialized extra portion of the new string will show up as garbage. A zero is used to mark the end of the string.
First of all the function is invalid and has no sense. You do not reverse the original string and the local string that is defined in the function can be less than the original string. Also you do not append the reversed local string with the terminating zero. The function can look like
void reverse( char *str )
{
size_t n = std::strlen( str );
for ( size_t i = 0; i < n / 2; i++ )
{
char c = str[i];
str[i] = str[n - i - 1];
str[n - i - 1] = c;
}
}
The original reversed string can be displayed in the code that calls the function.
Below is an example code that is not working the way I want.
#include <iostream>
using namespace std;
int main()
{
char testArray[] = "1 test";
int numReplace = 2;
testArray[0] = (int)numReplace;
cout<< testArray<<endl; //output is "? test" I wanted it 2, not a '?' there
//I was trying different things and hoping (int) helped
testArray[0] = '2';
cout<<testArray<<endl;//"2 test" which is what I want, but it was hardcoded in
//Is there a way to do it based on a variable?
return 0;
}
In a string with characters and integers, how do you go about replacing numbers? And when implementing this, is it different between doing it in C and C++?
If numReplace will be in range [0,9] you can do :-
testArray[0] = numReplace + '0';
If numReplace is outside [0,9] you need to
a) convert numReplace into string equivalent
b) code a function to replace a part of string by another evaluated in (a)
Ref: Best way to replace a part of string by another in c and other relevant post on SO
Also, since this is C++ code, you might consider using std::string, here replacement, number to string conversion, etc are much simpler.
You should look over the ASCII table over here: http://www.asciitable.com/
It's very comfortable - always look on the Decimal column for the ASCII value you're using.
In the line: TestArray[0] = (int)numreplace; You've actually put in the first spot the character with the decimal ASCII value of 2. numReplace + '0' could do the trick :)
About the C/C++ question, it is the same in both and about the characters and integers...
You should look for your number start and ending.
You should make a loop that'll look like this:
int temp = 0, numberLen, i, j, isOk = 1, isOk2 = 1, from, to, num;
char str[] = "asd 12983 asd";//will be added 1 to.
char *nstr;
for(i = 0 ; i < strlen(str) && isOk ; i++)
{
if(str[i] >= '0' && str[i] <= '9')
{
from = i;
for(j = i ; j < strlen(str) && isOk2)
{
if(str[j] < '0' || str[j] > '9')//not a number;
{
to=j-1;
isOk2 = 0;
}
}
isOk = 0; //for the loop to stop.
}
}
numberLen = to-from+1;
nstr = malloc(sizeof(char)*numberLen);//creating a string with the length of the number.
for(i = from ; i <= to ; i++)
{
nstr[i-from] = str[i];
}
/*nstr now contains the number*/
num = atoi(numstr);
num++; //adding - we wanted to have the number+1 in string.
itoa(num, nstr, 10);//putting num into nstr
for(i = from ; i <= to ; i++)
{
str[i] = nstr[i-from];
}
/*Now the string will contain "asd 12984 asd"*/
By the way, the most efficient way would probably be just looking for the last digit and add 1 to it's value (ASCII again) as the numbers in ASCII are following each other - '0'=48, '1'=49 and so on. But I just showed you how to treat them as numbers and work with them as integers and so. Hope it helped :)