I'm trying to write a little function that will flip lowercase characters to their symmetric counterparts in the second half of the alphabet - 26 letters = 13/13.
a = z, b = y, c = x...
I've tried the following code but for some reason it works only for the first character.
Say I enter "bamba"; it begins by switching the 'b' to 'y' but then it gets stuck and replaces all the other character to 'y' as well and I get "yyyyy".
I tried playing around with the code a bit and discovered that if I remove dependency by the current character, I can safely increase all the letters by, say, 1 (a = b, b = c...)
symmetric_difference = 1; **commented out** //21 - toCrypt[i];
I looked all over and the closest thing I found was
"Reversing alphabet value of individual characters in string" but it describes a way that seems weird and redundant.
Can anyone tell me what I did wrong please (assuming that I did)?
#include <iostream>
using namespace std;
void crypto(char[]);
int main()
{
char toCrypt[80];
cout << "enter a string:\n";
cin >> toCrypt;
crypto(toCrypt);
cout << "after crypto:\n";
cout << toCrypt;
}
void crypto(char toCrypt[]) // "Folding" encryption.
{
int size = strlen(toCrypt);
int symmetric_difference;
for (int i = 0; i < size; i++)
{
symmetric_difference = 121 - toCrypt[i]; // Calculate the difference the letter has from it's symmetric counterpart.
if (toCrypt[i] >= 97 && toCrypt[i] <= 110) // If the letter is in the lower half on the alphabet,
toCrypt[i] += symmetric_difference; // Increase it by the difference.
else
if (toCrypt[i] >= 111 && toCrypt[i] <= 122) // If it's in the upper half,
toCrypt[i] -= symmetric_difference; // decrease it by the difference.
}
}
You can try this
for (int i = 0; i < size; i++)
{
toCrypt[i] = 'z' - toCrypt[i] + 'a';
}
In your example, bamba, all of the characters go into the first if statement: toCrypt[i] += symmetric_difference;.
toCrypt[i] += symmetric_difference;
-> toCrypt[i] = toCrypt[i] + 121 - toCrypt[i];
-> toCrypt[i] = 121 = 'y'
Try the following function definition if I did not make a typo.
void crypto( char s[] )
{
static const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
const char *last = alpha + sizeof( alpha ) - 1;
while ( char &c = *s++ )
{
if ( const char *first = std::strchr( alpha, c ) ) c = *( last - ( first - alpha ) - 1 );
}
}
Take into account that it is not necessary that low case letters are ordered sequantially. For example if I am not mistaken it is not valid for EBCDIC.
I would like to substitute statement
const char *last = alpha + sizeof( alpha ) - 1;
for
const char *last = alpha + sizeof( alpha ) - sizeof( '\0' );
but the last is not compatible with C.:)
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' )
void inverse(char *string)
{
int i = 0;
int j = strlen(string) - 1;
char temp;
//Inverse the order
while ( i < j )
{
temp = *( string + i );
*( string + i ) = *( string + j );
*( string + j ) = temp;
i++;
j--;
}
//Capitalize letter after space
while( *string != '\0')
{
if ( *( string ) == ' ' && *( string + 1 ) != ' ')
{
*( ++string ) = toupper( *( string ) );
}
string++;
}
}
I just want to know if there is a better way to make this output, especially produce same output with less lines of code
Some general tips to cleanup and reduce the number of lines of code:
1. Use for loops instead of while loops. This
int i = 0;
while ( i < 10 )
{
// loop body
i++;
}
is better written as
for ( int i = 0; i < 10; i++ )
{
// loop body
}
2. Declare variables when you first use them. For example, the declaration of temp can be done inside the loop.
3. Use array syntax instead of pointer arithmetic. For example, this
*( string + i ) = *( string + j );
is better written as
string[i] = string[j];
With that in mind the code to reverse the string could be written as
for ( int i = 0, j = strlen(string)-1; i < j; i++, j-- )
{
char temp = string[i];
string[i] = string[j];
string[j] = temp;
}
As mentioned in the comments, the code to capitalize the first letter of words has some issues. The algorithm in the question advances the string pointer until it points to a space character, and then capitalizes the character at address string+1.
An alternative algorithm keeps a copy of the previous character. If the previous character was a space, then the current character is capitalized. Here's an implementation of that algorithm:
for ( char oldc = ' '; *string != '\0'; string++ )
{
if ( oldc == ' ' )
*string = toupper(*string);
oldc = *string;
}
Note that this will capitalize the first character in the string, and any character that follows a space. If you specifically only want to capitalize characters that follow a space, and not the first character, then change the initialization of oldc so that is doesn't start as a space, e.g.
for ( char oldc = 'a'; *string != '\0'; string++ )
Oh, you can optimize it greatly. Let's review the logic first.
We need to have each character that follows the space be uppercased in the result string. What does that mean? That means that in the original string such characters are located before the space. Thus, we have the criteria to find those in the original string and actually make them uppercase even before swapping. This renders second loop unnessessary -- we can do all in one.
Here's the example how it can be implemented:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void transform(char* s)
{
char temp;
char* endPtr = s + strlen(s) - 1;
while (s < endPtr)
{
/*
converting left hand part like 'c ' to 'C '
so that after swap it turns to ' C'
*/
if (!isspace(*s) && isspace(*(s + 1)))
*s = toupper(*s);
/* same to the right side */
if (isspace(*endPtr) && !isspace(*(endPtr - 1)))
*(endPtr - 1) = toupper(*(endPtr - 1));
/* swap */
temp = *s;
*s = *endPtr;
*endPtr = temp;
s++;
endPtr--;
}
}
int main(void)
{
char str[] = "this is a demo string! the one and only real demo string. crazy example ";
transform(str);
printf("'%s'\n", str);
return 0;
}
You can remove the temp variable while reversing using xor operation
int end= strlen(string)-1;
int start = 0;
while( start<end )
{
string[start] ^= string[end];
string[end] ^= string[start];
string[start]^= string[end];
++start;
--end;
}
To capitalized each letter, try with code below:
char* reversestr = *string;
while( *reversestr != '\0')
{
if (i==0 || *(reversestr - 1) ==' ' && *reversestr >= 'a' && *reversestr <= 'z')
*reversestr = toupper(*reversestr);
reversestr++;
}
I am not tested the code yet, but I think it should work.
How could I change an array of character (string) to an integer number without using any ready function (ex atoi();) for example :-
char a[5]='4534';
I want the number 4534 , How can I get it ?
Without using any existing libraries, you have to:
Convert character to numeric digit.
Combine digits to form a number.
Converting character to digit:
digit = character - '0';
Forming a number:
number = 0;
Loop:
number = number * 10 + digit;
Your function will have to check for '+' and '-' and other non-digits characters.
First of all this statement
char a[5]='4534';
will not compile. I think you mean
char a[5]="4534";
^^ ^^
To convert this string to a number is enough simple.
For example
int number = 0;
for ( const char *p = a; *p >= '0' && *p <= '9'; ++p )
{
number = 10 * number + *p - '0';
}
Or you could skip leading white spaces.
For example
int number = 0;
const char *p = s;
while ( std::isspace( ( unsigned char )*p ) ) ++p;
for ( ; *p >= '0' && *p <= '9'; ++p )
{
number = 10 * number + *p - '0';
}
If the string may contain sign '+' or '-' then you can check at first whether the first character is a sign.
You can go like this
It's working
#include <stdio.h>
#include <string.h>
#include <math.h>
int main()
{
char a[5] = "4534";
int converted = 0;
int arraysize = strlen(a);
int i = 0;
for (i = 0; i < arraysize ; i++)
{
converted = converted *10 + a[i] - '0';
}
printf("converted= %d", converted);
return 0;
}
I prefer to use the std::atoi() function to convert string into a number data type. In your example you have an non-zero terminated array "\0", so the function will not work with this code.
Consider to use zero terminated "strings", like:
char *a = "4534";
int mynumber = std::atoi( a ); // mynumber = 4534
How could I change an array of character (string) to an integer number without using any ready function (ex atoi();) for example :-
char a[5]='4534';
I want the number 4534 , How can I get it ?
Without using any existing libraries, you have to:
Convert character to numeric digit.
Combine digits to form a number.
Converting character to digit:
digit = character - '0';
Forming a number:
number = 0;
Loop:
number = number * 10 + digit;
Your function will have to check for '+' and '-' and other non-digits characters.
First of all this statement
char a[5]='4534';
will not compile. I think you mean
char a[5]="4534";
^^ ^^
To convert this string to a number is enough simple.
For example
int number = 0;
for ( const char *p = a; *p >= '0' && *p <= '9'; ++p )
{
number = 10 * number + *p - '0';
}
Or you could skip leading white spaces.
For example
int number = 0;
const char *p = s;
while ( std::isspace( ( unsigned char )*p ) ) ++p;
for ( ; *p >= '0' && *p <= '9'; ++p )
{
number = 10 * number + *p - '0';
}
If the string may contain sign '+' or '-' then you can check at first whether the first character is a sign.
You can go like this
It's working
#include <stdio.h>
#include <string.h>
#include <math.h>
int main()
{
char a[5] = "4534";
int converted = 0;
int arraysize = strlen(a);
int i = 0;
for (i = 0; i < arraysize ; i++)
{
converted = converted *10 + a[i] - '0';
}
printf("converted= %d", converted);
return 0;
}
I prefer to use the std::atoi() function to convert string into a number data type. In your example you have an non-zero terminated array "\0", so the function will not work with this code.
Consider to use zero terminated "strings", like:
char *a = "4534";
int mynumber = std::atoi( a ); // mynumber = 4534
For an assignment, I am working on creating a word shifter in C++. I have little to no experience with C++ so it has been very difficult. I think I am really close but just missing some syntax that is part of C++. Any help would be appreciated greatly.
string s = phrase;
int length = s.length();
//find length of input to create a new string
string new_phrase[length];
//create a new string that will be filled by my for loop
for (int i=0; i<length; i++)
//for loop to go through and change the letter from the original to the new and then put into a string
{
int letter = int(s[i]);
int new_phrase[i] = letter + shift;
//this is where I am coming up with an error saying that new_phrase is not initialized
if (new_phrase[i] > 122)
//make sure that it goes back to a if shifting past z
{
new_phrase[i] = new_phrase[i] - 26;
}
}
cout << new_phrase<< endl;
Considering your syntax,I wrote an example for you.Besides,it is conventional
to write comment before it's relevant code.
#include <iostream>
#include <string>
using namespace std;
int main()
{
//test value;
int shift = 3;
string s = "hello string";
//find length of input to create a new string
int length = s.length();
//create a new string.it's length is same as 's' and initialized with ' ';
string new_phrase(length, ' ');
for (int i=0; i<length; i++)
{
//no need to cast explicitly.It will be done implicitly.
int letter = s[i];
//It's assignment, not declaration
new_phrase[i] = letter + shift;
//'z' is equal to 126.but it's more readable
if (new_phrase[i] > 'z')
{
new_phrase[i] = new_phrase[i] - ('z' - 'a' + 1);
}
}
cout << new_phrase<< endl;
}
This should work.
// must be unsigned char for overflow checking to work.
char Shifter(unsigned char letter)
{
letter = letter + shift;
if (letter > 'z')
letter = letter - 26;
return letter;
}
// :
// :
string new_phrase = phrase; // mainly just allocating a string the same size.
// Step throught each char in phrase, preform Shifter on the char, then
// store the result in new_phrase.
std::transform(phrase.begin(), phrase.end(), new_phrase.begin(), Shifter);
cout << new_phrase<< endl;
UPDATE: made letter unsigned, so the overflow check works.
Try and investigate this code
#include <iostream>
#include <string>
#include <cctype>
void ShiftRight( std::string &s, std::string::size_type n )
{
if ( n >= 'Z' - 'A' + 1 ) return;
for ( char &c : s )
{
bool lower_case = std::islower( c );
c = std::toupper( c );
c = ( c + n -'A' ) % ('Z' -'A' + 1 ) + 'A';
if ( lower_case ) c = std::tolower( c );
}
}
int main()
{
std::string s( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
std::cout << s << std::endl << std::endl;
for ( std::string::size_type i = 1; i <= 'Z' -'A' + 1; i++ )
{
std::str std::string s( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
ShiftRight( s, i );
std::cout << s << std::endl;
}
return 0;
}
The output is
ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY
ABCDEFGHIJKLMNOPQRSTUVWXYZ
As for your code then it of course is wrong. You have not to define an array of strings. And do not use magic numbers as for example 122.
Also you may include in my code a check that a next symbol is an alpha symbol.