How to split an array using strings? - c++

I need to write a program that prompts the user to input a string, then determine the middle of the string, and generate a new string which swaps the two halves of the string and then output the results.
So far I have
int main(void) {
char *string = NULL;
char temp[1000];
cout << "Please enter a string" << endl;
cin.getline(temp, 999);
int length = strlen(temp);
string = new char[length];
strcpy(string,temp);
length = length / 2;
return EXIT_SUCCESS;
}
Which takes in the string and stores it. I just need a way to move that second half to a new array and I know I need to use strcpy() but I don't know how to properly reference that portion of the array.

Since this is C++ I'm going to suggest a standard library algorithm. You're asking to swap two halves of a sequence and std::rotate does just that. Unfortunately it does the rotation in-place and you want the result in a different string.
You could copy the string and then do the rotation but there is a std::rotate_copy algorithm that will do both (and faster than separate copy/rotate steps).
Example with char arrays:
#include <algorithm>
#include <cstring>
#include <iostream>
int main()
{
char text[1000], result[1000];
std::cout << "Please enter a string\n";
std::cin.getline(text, 999);
size_t length = strlen(text);
std::rotate_copy(text, text + length / 2, text + length, result);
result[length] = '\0';
std::cout << text << '\n' << result << '\n';
}
Example with std::string:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
std::string text, result;
std::cout << "Please enter a string\n";
std::getline(std::cin, text);
size_t length = text.size();
result.resize(length);
std::rotate_copy(text.begin(), text.begin() + length / 2, text.end(), result.begin());
std::cout << text << '\n' << result << '\n';
}
Demo on ideone.com
You could possibly use std::swap_ranges but that assumes both ranges are the same size.

if you are trying to use C, use strncpy. However, I recommend using C++ std::string and using the std::string.substr() and concatenation. The latter would be easier at least to me.

You were half way through the solution. Here I finished it using strncpy to get the first half and pointer incrementation to get the second one.
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int main(void)
{
char temp[1000];
cout << "Please enter a string" << endl;
cin.getline(temp, 999);
int length = strlen(temp);
char firstHalf[512];
strncpy (firstHalf, temp, length/2);
cout << "firstHalf: " << firstHalf << endl;
char* secondHalf = temp + length/2;
cout << "secondHalf: " << secondHalf << endl;
char* swapped_str = strcat(secondHalf, firstHalf);
cout << "Swapped string: " << swapped_str << endl;
return EXIT_SUCCESS;
}

std::string text(whatever...);
int sz = text.size() / 2;
for (int i = 0; i < sz; ++i)
std::swap(text[i], text[sz + i]);
This might be off by one when text.size() is odd.

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.

C++ reversing a string

I'm trying to reverse a string in my C++ code line below revStr.at(j) = str.at(size);
But it doesn't change any of the elements in revStr.
Is there another way to do it without using any libraries.
#include <iostream>
#include<sstream>
#include <iterator>
using namespace std;
int main() {
ostringstream d;
long long c = 123456789;
d << c;
//cout << c << endl;
string str = d.str();
//cout << str.at(0) << endl;
int size = str.size() - 1;
//cout << size << endl;
ostringstream e;
e << str;
string revStr = e.str();
for (int i = size; size==0; size--) {
//cout << str.at(size);
int j = 0;
revStr.at(j) = str.at(size);
j++;
} // End For
cout << "Original String is :" << str << endl;
cout << "Reversed String is :" << revStr << endl;
}
Use std::reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string test{"Hello"};
std::cout << "Original string: " << test << std::endl;
std::reverse(test.begin(), test.end());
std::cout << "Reversed string: " << test << std::endl;
return 0;
}
Output:
Original string: Hello
Reversed string: olleH
If you just want to reverse a string, you should use std::reverse, as described by Tyler Lewis. It is the best option.
If you want to learn C++, then writing your own version is good practice.
The line
for (int i = size; size==0; size--)
means “Create a new int called i and set it to size initially. Then, while size is zero, do the following and then decrement size”.
There are three problems with this:
Size is not zero unless you entered a one-character string
Since you never use i, there’s no point in declaring it
Inside the loop you use j which is set to zero each time.
You can fix the first by changing the middle part of the for loop to size >= 0 (but be careful—if you later change it so that size is an unsigned type, because it doesn’t make sense for it to be negative, that code won’t work; it’s generally better to increment going up instead). You can fix the second by using i everywhere in the loop statement, and not changing size. You can fix the third by using i in the loop body, and not declaring a new variable inside the loop.
I noticed you used std::string so I used std function swap and string. Depending on if you consider this as a 'library'. There are several definitions of 'reverse'. You could reverse the word order in a string, or a pure char to char reversal like I wrote. Reversal could also mean changing character case, etc... but this is simply swap first and last. Then swap the 2nd and 2nd to last, then swap the 3rd and 3rd to last, etc...
So some points from your code. You only need to loop half the string length. The swap is from the ith and the ith to last. So the last is numCharacters - 1, thus the ith to last would be Last - i or numCharacters - 1 - i. I believe this is what you intended by using a farLeft(i) and a farRight(j) index.
#include <iostream>
void reverseStringInPlace(std::string &stringToReverse)
{
int numCharacters = stringToReverse.length();
for (int i=0; i<numCharacters/2; i++)
{ std::swap(stringToReverse[i], stringToReverse[numCharacters-i-1]); }
}
int main()
{
std::string stringToReverse = "reversing a string";
std::cout << stringToReverse << std::endl;
reverseStringInPlace(stringToReverse);
std::cout << stringToReverse << std::endl;
return 0;
}
Output:
reversing a string
gnirts a gnisrever
Changes made to the piece of code in question, it works.
for (unsigned int i = size; size >= 0; size--) {
revStr[j] = str[size];
j++;
}

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;

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");

I am trying to return a Character Array but, I'm only getting the first letter returned

I'm working on a small little thing here for school. After hours of researching, and a ton of errors and logic reworking I've almost completed my little program here.
I'm trying to take user input, store it into the string, get a character array from the string ( dont ask why, I just have to put this into a character array ), then get the reversed order of the phrase that the user entered. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <String>
#include <cstring>
using namespace std;
using namespace System;
#pragma hdrstop
char* getCharArray(string);
string reversePhrase( int, char* );
void main(void)
{
string sPhrase = "";
int sSize = 0;
string sReversed = "";
char* cPhrase = NULL;
cout << "Welcome to the You Type It & We'll Reverse it! [Version 1.0] " << endl;
cout << "This program will reverse your phrase, and count how many characters are in it!" << endl;
cout << "To begin just enter a phrase." << endl;
cout << "Enter a phrase: ";
getline( cin, sPhrase);
sSize = sPhrase.length();
cout << endl;
cPhrase = getCharArray(sPhrase);
sReversed = reversePhrase( sSize, cPhrase );
cout << sReversed;
system("pause");
}
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
int place = size;
for ( int i = 0; i < size ; i ++ )
{
sReversed.append(1, cPhrase[place]);
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size];
for (int i = 0 ; i < size ; i++)
{
cArray[size] = sPhrase.at(i);
}
return cArray;
}
When I type in "ownage" into the program, this is what I get returned:
It is almost like my Character Array is getting garbage collected before it can use all of the characters. This is probably an easy fix but, I just don't see how I can get around this one.
Try rewriting getCharArray like this
char* getCharArray(string sPhrase)
{
int size = 1;
size = sPhrase.length();
char* cArray = NULL;
cArray = new char[size+1]; // NOTE
for (int i = 0 ; i < size ; i++)
{
cArray[i] = sPhrase.at(i); // NOTE
}
}
cArray[size]=0; // NOTE
return cArray;
}
Note that the assignment in the loop now uses the index variable. Also, you need to allocate one extra char in the array to set the null terminator for the string and then you need to set it at the end.
You'll also need to think about deallocating the array at some point
The bug is in this line:
cArray[size] = sPhrase.at(i);
That size should be your loop index.
You should probably look at using std::string more, and not poke around with character arrays when there's no need to.
Why use a char array at all? It's not only useless – it complicates the code substantially (the usage of your function is more difficult, and you've forgotten to free the memory allocated by new!). Why not just have the following function:
string reverse(string const& input);
(Passing the argument by const reference instead of by value saves you a copy!)
In fact, implementing the function only takes a single line using the features of the string class (one of its constructors takes two iterators):
string reverse(string const& input) {
return string(input.rbegin(), input.rend());
}
reversePhrase is also not correct. Try something like this:
string reversePhrase(int size , char* cPhrase)
{
string sReversed = "";
sReversed.resize(size);
int place = size - 1;
for ( int i = 0; i < size ; i ++ )
{
sReversed [i] = cPhrase[place];
cout << "Current string: " << sReversed << endl;
cout << "Current character: " << cPhrase[place] << endl;
place--;
}
return sReversed;
}
First, start the array with -1. After that, use a for loop with -1 and increment inside the loop. Then, you can get the first element of the array.