How to use string.substr() function? - c++

I want to make a program that will read some number in string format and output it like this: if the number is 12345 it should then output 12 23 34 45 . I tried using the substr() function from the c++ string library, but it gives me strange results - it outputs 1 23 345 45 instead of the expected result. Why ?
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main(void)
{
string a;
cin >> a;
string b;
int c;
for(int i=0;i<a.size()-1;++i)
{
b = a.substr(i,i+1);
c = atoi(b.c_str());
cout << c << " ";
}
cout << endl;
return 0;
}

If I am correct, the second parameter of substr() should be the length of the substring. How about
b = a.substr(i,2);
?

As shown here, the second argument to substr is the length, not the ending position:
string substr ( size_t pos = 0, size_t n = npos ) const;
Generate substring
Returns a string object with its contents initialized to a substring of the current object. This substring is the character sequence that starts at character position pos and has a length of n characters.
Your line b = a.substr(i,i+1); will generate, for values of i:
substr(0,1) = 1
substr(1,2) = 23
substr(2,3) = 345
substr(3,4) = 45 (since your string stops there).
What you need is b = a.substr(i,2);
You should also be aware that your output will look funny for a number like 12045. You'll get 12 20 4 45 due to the fact that you're using atoi() on the string section and outputting that integer. You might want to try just outputing the string itself which will be two characters long:
b = a.substr(i,2);
cout << b << " ";
In fact, the entire thing could be more simply written as:
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string a;
cin >> a;
for (int i = 0; i < a.size() - 1; i++)
cout << a.substr(i,2) << " ";
cout << endl;
return 0;
}

Another interesting variant question can be:
How would you make "12345" as "12 23 34 45" without using another string?
Will following do?
for(int i=0; i < a.size()-1; ++i)
{
//b = a.substr(i, 2);
c = atoi((a.substr(i, 2)).c_str());
cout << c << " ";
}

substr(i,j) means that you start from the index i (assuming the first index to be 0) and take next j chars.
It does not mean going up to the index j.

You can get the above output using following code in c
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main()
{
char *str;
clrscr();
printf("\n Enter the string");
gets(str);
for(int i=0;i<strlen(str)-1;i++)
{
for(int j=i;j<=i+1;j++)
printf("%c",str[j]);
printf("\t");
}
getch();
return 0;
}

Possible solution without using substr()
#include<iostream>
#include<string>
using namespace std;
int main() {
string c="12345";
int p=0;
for(int i=0;i<c.length();i++) {
cout<<c[i];
p++;
if (p % 2 == 0 && i != c.length()-1) {
cout<<" "<<c[i];
p++;
}
}
}

Possible solution with string_view
void do_it_with_string_view( void )
{
std::string a { "12345" };
for ( std::string_view v { a }; v.size() - 1; v.remove_prefix( 1 ) )
std::cout << v.substr( 0, 2 ) << " ";
std::cout << std::endl;
}

The string constructor can be used to get a copy of a substring.
string(const string& str, size_t pos, size_t n)
For example...
b = string(a, i, 2); // substring of a from position i, including 2 characters
This differs from substr in that the length n cannot be omitted. I offer this only as an alternative, not as an improvement.

Related

Why is my code printing the wrong ciphertext?

I am trying to make a program that turns a string into encryption by going ten letters ahead of each letter. https://gyazo.com/86f9d708c2f02cf2d70dbc1cd9fa9a06 I am doing part 2. When I input "helloworld" something like 0x45 something comes up. Please help! This is due soon!
I am tried messing around with the for loops but it didn't help.
#include <iostream>
using namespace std;
int main()
{
//Input Message
cout << "Enter a message" << endl;
string message;
getline(cin, message);
//Convert Message to Numbers
int numMess[message.length()];
for (int i = 0; i<message.length(); i++) {
numMess[i] = (int)message[i];
}
cout << numMess << endl;
//Encrypt Number Message by adding ten to each one
int encryptNumMess[message.length()];
for (int a = 0; a < message.length(); a++){
encryptNumMess[a] = numMess[a] + 10;
if (encryptNumMess[a] > 122) {
encryptNumMess[a] = 97;
}
}
cout << encryptNumMess << endl;
//Convert Encrypted Number Message to letters
string encryption[message.length()];
for (int b = 0; b<message.length(); b++) {
encryption[b] = (char)encryptNumMess[b];
}
cout << encryption << endl;
return 0;
}
I expect when I type "helloworld" the final product will be "rovvygybvn"
If you are willing to scrap the hand-coded loops, you can use the STL algorithms such as std::transform to accomplish this:
But first, there are a few things you should do:
Don't use magic numbers such as 122, 97, etc. Instead use the actual character constants, i.e a, b, etc. However if we assume ASCII, where the alphabetic character codes are contiguous, your particular program could simply use a constant string to denote the alphabet, and then use simple indexing to pick out the character.
const char *alphabet = "abcdefghijklmnopqrstuvwxyz";
Then to get the letter a, a simple subtraction is all that's required to get the index:
char ch = 'b';
int index = ch - 'a'; // same as 'b' - 'a' == 98 - 97 == 1
std::cout << alphabet[index]; // will print 'b'
Given this, the next thing is to figure out what character is reached if you add 10 to the value, and if greater than 26, wrap around to the beginning of the alphabet. This can be done using modulus (remainder after division)
char ch = 'x';
int index = (ch - 'a' + 10) % 26; // Same as ('x' - 'a' + 10) % 26 == (120 - 97 + 10) % 26 == 33 % 26 == 7
std::cout << alphabet[index]; // will print 'h'
The next thing is to figure out the opposite, where given an encrypted character, you have to find the unencrypted character by subtracting 10. Here this wraps the opposite way, so a little more work needs to be done (not shown, but code sample reflects what is done).
Putting this all together, and using std::transform and lambdas, we get the following small program:
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
#include <cmath>
int main()
{
//Input Message
const char *alphabet="abcdefghijklmnopqrstuvwxyz";
std::string message = "helloworld";
std::string result;
// set the encrypted string using the formula above and std::transform
std::transform(message.begin(), message.end(), std::back_inserter(result),
[&](char ch) { return alphabet[(ch - 'a' + 10) % 26]; });
std::cout << "Encrypted: " << result << '\n';
// convert back to unencrypted using the above formula and std::transform
std::string result2;
std::transform(result.begin(), result.end(), std::back_inserter(result2),
[&](char ch)
{ int index = ch - 'a' - 10; index = index < 0?26 - (abs(index) % 26):index % 26; return alphabet[index];});
std::cout << "Unencrypted: " << result2;
}
Output:
Encrypted: rovvygybvn
Unencrypted: helloworld
This code works for encrypt, if you want to decrypt you should chande newAlphabet and oldAlphabet
I comment in the code that which newAlphabet and oldAlphabet are for encrypt and which are for decrypt
#include <windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
int main()
{
// For Encrypt
string newAlphabet = "abcdefghijklmnopqrstuvwxyz";
string oldAlphabet = "klmnopqrstuvwxyzabcdefghij";
// For Decrypt
//string newAlphabet = "klmnopqrstuvwxyzabcdefghij";
//string oldAlphabet = "abcdefghijklmnopqrstuvwxyz";
string input = "";
string output = "";
getline(cin, input);
int inputLen = input.size();
if (oldAlphabet.size() != newAlphabet.size())
return false;
for (int i = 0; i < inputLen; ++i)
{
int oldCharIndex = oldAlphabet.find(tolower(input[i]));
if (oldCharIndex >= 0)
output += isupper(input[i]) ? toupper(newAlphabet[oldCharIndex]) : newAlphabet[oldCharIndex];
else
output += input[i];
}
cout << output << endl;
return 0;
}
As others have already mentioned int numMess[message.length()]; is not valid c++.
If it works for you, you're using compiler extension which you really shouldn't rely on. The correct way would be:
std::vector <int> numMess(message.length());
Look up the std::vector reference for more info.
Next, int encryptNumMess[100]; creates a C array style array. encryptNumMess is the base pointer to the array. when you try std::cout << encryptNumMess it'll output the pointer value, NOT the array. You'll need a for loop for doing that, like so :
for(int i = 0; i < 100; ++i)
std::cout << encryptNumMess[i] << " ";
std::cout << endl;
The above also works when you convert this to a vector like we did with numMess whereas in that case, std::cout << encryptNumMess wouldn't even compile.
Thirdly, string encryption[100] creates an array of 100 strings! Not a string of size 100. To do that:
std::string foo(message.length(), '\0');
We have to specify what character to fill the string with. Thus us '\0'.
And now, for the string, to output it, you may use std::cout << foo.
Lastly, since arithmetic is allowed on char, the entire program may be shortened to just this
#include <iostream>
int main()
{
// Input Message
std::cout << "Enter a message" << std::endl;
std::string message, encryption;
getline(std::cin, message);
// Resize encryption string to the desired length
encryption.resize(message.length());
// Do the encryption
for(size_t i = 0; i < message.length(); ++i) {
encryption[i] = message[i] + 10;
if (encryption[i] > 122) {
encryption[i] = 97;
}
}
// Output the string
std::cout << encryption << std::endl;
return 0;
}
Of course, your encryption algorithm is still not correct as per instructions, but I'll leave that for you to figure out. I believe #PaulMcKenzie has already told you most of how to fix it, and also to not use magic numbers.

Error coverting int to string C++

I'm working on this code that takes a numeric string and fills an array with each "digit" of the string. The issue I'm having is trying to convert an integer to a string. I tried using to_string to no avail.
Here is the code (note this is pulled from a larger program with other functions):
#include <cstdlib>
#include <stdlib.h>
#include <iostream>
#include <time.h>
#include <typeinfo>
int fillarr(int &length) {
int arr[length];
string test = "10010"; //test is an example of a numeric string
int x = 25 + ( std::rand() % ( 10000 - 100 + 1 ) );
std::string xstr = std::to_string(x); //unable to resolve identifier to_string
cout << xstr << endl;
cout << typeid (xstr).name() << endl; //just used to verify type change
length = test.length(); //using var test to play with the function
int size = (int) length;
for (unsigned int i = 0; i < test.size(); i++) {
char c = test[i];
cout << c << endl;
arr[int(i)] = atoi(&c);
}
return *arr;
}
How can I convert int x to a string? I have this error: unable to resolve identifier to_string.
As mentioned by user 4581301, you need an #include <string> to use string functions.
The following, though is wrong:
arr[int(i)] = atoi(&c);
The atoi() will possibly crash because c by itself is not a string and that mean there will be no null terminator.
You would have to use a buffer of 2 characters and make sure the second one is '\0'. Something like that:
char buf[2];
buf[1] = '\0';
for(...)
{
buf[0] = test[i];
...
}
That being said, if your string is decimal (which is what std::to_string() generates) then you do not need atoi(). Instead you can calculate the digit value using a subtraction (much faster):
arr[int(i)] = c - '0';
Okay I modified my code a bit per suggestion from everyone and ended up handling the conversion like this:
string String = static_cast<ostringstream*>( &(ostringstream() << x) )->str();
cout << String << endl;

Output not as expected from the array

I am writing a code where I take user user text input, convert it to binary, store each binary character in an element in an array and then print A or T for 0 and G or C for 1 at random. But the ATGC seem to not follow this rule and they come at random for every digit; 0 and 1. So If the binary is 0010101 I need output as ATGACTG. Also when I store the binary in an int variable, the zero in front of it vanishes. Is there a way to keep it?
#include <iostream>
#include <cstdlib>
#include <bitset>
#include <string>
#include <ctime>
int main()
{
using namespace std;
int p, i=0, a[100000];
int s;
string myString;
int binary;
cout << "Type your text: ";
std::getline (std::cin,myString);
for (std::size_t k=0; k < myString.size(); ++k)
{
std::bitset<8> y(myString[k]);
std::string dna = y.to_string();
binary = atoi(dna.c_str());
cout << binary;
while (binary != 0)
{
a[i] = binary % 10;
binary = binary / 10;
i++;
}
}
std::cout << std::endl;
srand(time(0));
for (int j = (i-1); j>-1; j--)
{
if (a[j] == 0)
{
p = rand() %2;
if (p==0)
cout<< "A";
else
cout<< "T";
}
if (a[j] == 1)
{
s = rand() %2;
if (s == 0)
cout<< "G";
else
cout<< "C";
}
else
{
cout << "";
}
}
}
I don't know why exactly you wrote so much wrong code, but I've managed to extract (and change) the code that actually does the job.
#include <iostream>
#include <string>
#include <bitset>
#include <ctime>
int main()
{
int i = 0, a[8];
std::string myString;
std::cout << "Type your text: " << std::endl;
std::getline(std::cin, myString);
for(auto x : std::bitset<8>(myString).to_string())
a[i++] = x == '1';
std::cout << std::endl;
srand(time(0));
for(int j = 0; j < i; ++j)
if(a[j] == 0)
std::cout << (rand() % 2 ? "T" : "A");
else if(a[j] == 1)
std::cout << (rand() % 2 ? "C" : "G");
std::cout << std::endl;
}
And here's neater version of main:
int main()
{
std::vector<int> a; // using std::vector
std::bitset<8> bs;
std::cout << "Type your text: " << std::endl;
std::cin >> bs; // std::bitset can be read from stream via operator>>
for(auto x : bs.to_string())
a.push_back(x == '1');
std::cout << std::endl;
srand(time(0));
for(auto x : a)
if(x == 0)
std::cout << (rand() % 2 ? "T" : "A");
else if(x == 1)
std::cout << (rand() % 2 ? "C" : "G");
std::cout << std::endl;
}
Just ask if you want an explanation on some specific part.
I told you not to convert the string to an integer. You didn't listen. This is why leading 0 vanishes.
Your output seams to be completely random because you reverse the order of characters in the sequence when reading the information from a.
Here is how I'd solve your problem: run online
#include <iostream>
#include <string>
#include <bitset>
#include <ctime>
#include <cstdlib>
int main()
{
std::cout << "Type your text: " << std::endl;
std::string in_str;
std::getline(std::cin, in_str);
std::string binary_str;
for(int i = 0; i < in_str.size(); ++i)
{
char c = in_str.at(i);
binary_str.append(std::bitset<8>(c).to_string());
}
std::cout << binary_str << std::endl;
srand(time(0));
for(int i = 0; i < binary_str.size(); ++i)
{
char c = binary_str.at(i);
if(c == '0')
std::cout << (rand() % 2 ? "T" : "A");
else
std::cout << (rand() % 2 ? "C" : "G");
}
std::cout << std::endl;
}
If you have any questions, ask me in the comments.
Edit: the OP asked me to explain all mistakes in his program.
Where did all those zeros gone?
To answer this question I'll have to explain all things your program does line-by-line.
Here you convert a symbol to a bitset:
std::bitset<8> y(myString[k])
For example: if k is 'a', then the y would be 01100001.
Here you convert the bitset to a string:
std::string dna = y.to_string();
In our example the dna would be "01100001".
Here you convert the string to an integer:
binary = atoi(dna.c_str());
A very simplified version of what atoi does:
binary = 0;
for(int i = 0; i < dna.size(); ++i)
binary = binary * 10 + (dna.at(i) - '0')
In our example the binary would be 1100001.
Note: that's NOT where you loose zeros. At this point you are still able to extract them because you know that you need to extract 8 digits. So you can append leading zeros to up it's length to 8.
The next line is where you actually loose zeros the first time because cout doesn't know that you want to print 8 digits.
cout << binary;
In our example it would print 1100001.
And here you loose zeros again because you stop extracting digits as soon as binary == 0 even if you extracted less than 8 digits. Also note that you are actually reversing what the function atoi just did with the only difference that you don't get your leading zeros back and the reverse order of bits (see the next paragraph):
while (binary != 0)
{
a[i] = binary % 10;
binary = binary / 10;
i++;
}
Why the output is "random"?
Here you are iterating through myString in the standard order
for (std::size_t k=0; k < myString.size(); ++k)
e.g. if myString is "abc" than
in the first iteration myString[k] would be 'a'
in the second iteration myString[k] would be 'b'
in the third iteration myString[k] would be 'c':
But in this loop you extract digits in reverse order:
while (binary != 0)
{
a[i] = binary % 10;
binary = binary / 10;
i++;
}
eg if binary is 1100001
in the 1st iteration you extract 1 and binary becomes 110000
in the 2nd iteration you extract 0 and binary becomes 11000
in the 3rd iteration you extract 0 and binary becomes 1100
in the 4th iteration you extract 0 and binary becomes 110
in the 5th iteration you extract 0 and binary becomes 11
in the 6th iteration you extract 1 and binary becomes 1
in the 7th iteration you extract 1 and binary becomes 0
Now you end up with an array where bits inside a character code are reversed, but different characters are stored in the array in the normal order.
e.g. If the input string was "abc", then a would become:
1,0,0,0,0,1,1, 0,1,0,0,0,1,1, 1,1,0,0,0,1,1
reversed 'a' reversed 'b' reversed 'c'
If you iterate through a in normal order, the order of bits inside character codes would be reversed. If you iterate through a in reverse order, you get the reversed order of characters.
As a rule of thumb: don't program by guessing, program by thinking.
Further reading
The Zen of Python. Most of this aphorisms are applicable to every programming language with the exception of Brainfuck
Raw C arrays are evil

Print number as number in string type

I have the following code :
string a = "wwwwaaadexxxxxx";
Intended Output : "w4a3d1e1x6";
somewhere in my code I have int count = 1; ... count++;
Also, somewhere in my code I have to print this count as a[i] but as a number only .. like 1,2,3 and not the character equivalent of 1,2,3.
I am trying the following : printf("%c%d",a[i],count);
i also read something like :
stringstream ss;
ss << 100
What is the correct way to do so in CPP?
EDIT :
so i Modified the code to add a number at index i in a string as :
stringstream newSS;
newSS << count;
char t = newSS.str().at(0);
a[i] = t;
You can use a stringstream to concatenate the string and the count,
stringstream newSS;
newSS << a[i] << count;
and then finally convert it to string and then print it or return (if this is done inside a function)
string output = newSS.str();
cout << output << endl;
But if your objective is only to print the output, then using the printf is fine.
If you need to update in place, then you can use two pointers. Let them be i,j.
You use j to set the new value and i to count the count. This is the standard runLength Encoding Problem.
There is no "correct" way. You could use snprintf, stringstream, etc. Or you could roll your algorithm. Assuming this is a base 10 number, you want the number in base 10.
#include <iostream>
#include <string>
#include <algorithm>
int main(void)
{
int a = 1194;
int rem = 0;
std::string output;
do {
rem = a % 10;
a = a / 10;
output.append(1, rem + '0');
} while(a != 0);
std::reverse(output.begin(), output.end());
std::cout << output << std::endl;
return 0;
}

string does not end with null

I'm a beginning student of C++ and i encountered a problem with the following code:
I'm trying to concatenate a 'new line' or "\n" to a string in a matrix of char.
So far I managed to concatenate a " " char but the char "\n" or just typing multiple " " won't work.
The actual sample is getting 3 strings in const value of 10 (max chars) for each of the 3 matrix's I defined-assigning values to the first two and using a function to 'change' the third and printing it.
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int LINES = 3;
const int MAXCHARS = 10; //TO DO: change to 81 for final version
void cpyAndCat(char[][MAXCHARS], char[][MAXCHARS], char[][MAXCHARS], int);
void main()
{
char text1[LINES][MAXCHARS], text2[LINES][MAXCHARS], text3[LINES][MAXCHARS];
cout << "Enter " << LINES << " lines into text1:\n";
for (int i = 0; i < LINES; i++) // assign the matrix of chars text1 with strings
{
_flushall();
cin.getline(text1[i], MAXCHARS);
}
cout << "Enter " << LINES << " lines into text2: \n";
for (int i = 0; i < LINES; i++) // assign the matrix of chars text2 with strings
{
_flushall();
cin.getline(text2[i], MAXCHARS);
}
//TO DO: call the function which will recieve text1 and text2
//and put blank line(line too long) or copied line from text1 and catanted line form text2.(long correct size)
cpyAndCat(text1, text2, text3, LINES);
cout << "============================================================\n";
for (int i = 0; i < LINES; i++) // print third matrix of chars, prints 3 lines of either text or '\n'
{
_flushall();
cout << text3[i];
cout << endl;
}
system("pause");
}
void cpyAndCat(char text1[][MAXCHARS], char text2[][MAXCHARS], char text3[][MAXCHARS], int lines)
{
for (int i = 0; i < lines; i++) // searches if length of string from first 2 matrix is valid
{
if (strlen(text1[i]) + strlen(text2[i]) < MAXCHARS) // if so, copy the first to the third and catanate the second to the third
{
strcpy_s(text3[i], text1[i]);
strcat_s(text3[i], text2[i]);
}
else // if else (: , catanate 'new line' to the third matrix
{
strcat_s(text3[i], "\n"); // not working
}
cout << endl;
}
}
strcat_s and strcpy_s need three parameters, not two. I'm suprised you have anything compiling at all.
Also, you strcat onto text3 without ever initializing it. So that's probably undefined behaviour...
strcat_s takes 3 arguments, you are missing the size in bytes, also, the string was never initialized.
You would want to copy into the string and afterwards, if needed, concatenate.
Don't forget to take into account the '\0' at the end of every string.
strcpy_s(text3[i], 2, "\n");