Creating strings by splitting a char array - c++

As part of my homework assignment, I have to split a char[] by its indices. So for example, the main function looks like:
int main()
{
char str[] = "A string to be split into given number of parts";
int split_size;
cout << "Enter the size of the part: ";
cin >> split_size;
int size = sizeof(str) / sizeof(str[0]);
SplitString(str, split_size, size);
int wait;
cin >> wait;
return 0;
}
Then using the function SplitString, the first x elements are printed, new line, then the next.
My first idea, was to use two for loops. One loops through the splits (i.e. if there are 4 splits, the range on this loop is 0 to 3), then the second loops through the split itself, iterating over the array elements.
My SplitString() function looks like this:
void SplitString(char str[], int split_size, int size) {
int parts = size / split_size;
for (int i = 0; i < parts; i++) {
for (int j = 0; j < split_size; j++) {
j = split_size * i;
cout << str[j];
}
cout << endl;
}
}
Is there an easier way to do this? I know in Python, you can use the arr[1:] to grab a range of elements from the array. Is there anything similar in C++? Is there some flaw in my logic? Is there something wrong with my code?

cout comes with a write function that takes a pointer and a size argument.
for (int i = 0; i < parts; i++) {
cout.write (str+i*split_size, split_size)
cout << endl;
}
Note that the code above does not check if the string is actually long enough. If the total size is not equal the split_size times a whole number, you will have to add an additional check.
Also, note that this:
int size = sizeof(str) / sizeof(str[0]);
can be written as:
int size = sizeof(str);
instead because the size of a char is always 1.

You can use std::string for this. Alternatively, if your compiler supports C++17, you can use std::string_view as the first argument of SplitString to avoid unnecessary copying.
#include <algorithm>
#include <iostream>
#include <string>
void SplitString(std::string s, std::size_t split_size)
{
while(!s.empty())
{
auto size = std::min(split_size, s.size());
std::cout << s.substr(0, size) << '\n';
s = s.substr(size, std::string::npos);
}
}
int main()
{
char str[] = "A string to be split into given number of parts";
int split_size = 5;
SplitString(str, split_size);
return 0;
}
Live example.

Related

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');
}
}

C++ one dimensional Char array saving to two dimensional Char array

char binarycode[5][5];
string tmp;
cout<<"Please type first 5 binary numbers: ";
cin>>tmp;
char tmp2[5];
strcpy(tmp2, tmp.c_str());
binarycode[0] = tmp2;
This is my code for me to save the empty char array with user input string. So there will be 5 string that will break up to one dimension char array and will be saved to each row of binarycode. Howerver, it does not seems to work like Java where i can just store the one dimension array to two dimension array. Are there any way to make this process easier or is making method is better?
Are there any way to make this process easier or is making method is
better?
Consider using std::vector of std::string like std::vector < std::string > binarycode ;
Then,
binarycode.reserve( 5 );
std::string tmp;
for ( int i = 1; i <=5; ++i )
{
std::cin >> tmp;
binarycode.push_back ( tmp );
}
Your objective is to take a 1 dimensional array with size T and to populate or convert it to a 2 dimensional array with size MxN. What you will need to do in order to construct this algorithm before writing any code implementation is you will need to know before hand the sizes or lengths of both M and N and in your case you have explicitly expressed that it will be a 5x5 in size; T shouldn't matter in this case. M will be the size of your rows, where N will be the size of your columns. To do this you will need to traverse the single array for its size and then depending on its indexed value it should correspond to a (m,n) value. Another words you need to map A(n) to B(m,n).
The method that you are trying to achieve which is not the simplest or even the most efficient but mimics the algorithm mathematically would be as follows:
#include <iostream>
#include <string>
int main() {
char binaryCode[5][5] { 0 }; // Initialize to all 0s
char temp;
int row = 0;
int col = 0;
do {
std::cout << "Enter 5 binary number: ";
std::cin >> temp;
for ( ; col < 5; col++ ) {
binaryCode[row][col] = temp[col];
}
col = 0;
temp.clear();
row++;
} while( row < 5 );
row = 0;
col = 0;
std::cout << "\nResults:\n";
for ( ; row < 5; row++ ) {
for ( ; col < 5; col++ ) {
std::cout << binaryCode[row][col] << " ";
}
std::cout << "\n";
col = 0;
}
return 0;
}
However this first approach is a little naïve and as P0W already stated with his answer:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> binaryCodes;
binaryCodes.reserve( 5 );
std::string tmp;
for ( int i = 1; i <=5; ++i ) {
std::cin >> tmp;
binarycode.push_back ( tmp );
}
return 0;
}
Is cleaner and simpler and does exactly the same thing that you would need.
The strcpy(0 function copies entire c-string to memory position you designated as destination. In code
char tmp2[5];
strcpy(tmp2, tmp.c_str());
In code
binarycode[0] = tmp2;
you attempted to save pointer - address of that buffer to a byte.
you statically allocated 5 bytes(!) of memory, then attempted to copy string to that memory. If anything, you would cause memory corruption this way, because rest of string would go somewhere.
C++ is not Java and you should thoroughly read books on this language, about syntax and standard you're using, not relying on something that "looks like". There are even principal differences between C and C++ in some areas.
If anything, iostreams provide all tools you need to get values from user input, but "proper" way to do requires handling cases of incorrect input. Consider this function:
#include <limits>
#include <iostream>
char getChar()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter a byte value: ";
int x; // if we'll use char, cin would assume it is a character
std::cin >> x;
if (std::cin.fail()) // has a previous extraction failed?
{
// let's handle the failure
// or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
// and remove the bad input
}
//else if ( ((char)(x & 0xff)) != x ){
else if(( x > std::numeric_limits<char>::max()) ||
( x < std::numeric_limits<char>::min()))
{
// char can be from -127 to 127, it's one byte..
// int is allowing large values
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return (char)(x & 0xff);
}
}
The char is a pain in the backside with std::iostream, it always should be an int instead. Casting to smaller variable, like (char)x might be an undefined behavior, so need to mask larger values (char)(x & 0xff); For other types this function can become a template based on the type requested.
Now we should make it understand binary input? there is no predefined manipulator for binary format, you must input a string, validate it, and convert yourself.
int binaryToDec(std::string number)
{
int result = 0, pow = 1;
for ( int i = number.length() - 1; i >= 0; --i, pow <<= 1 )
result += (number[i] - '0') * pow;
return result;
}
std::string validateEntry()
{
bool valid = true;
std::string tempStr;
do
{
valid = true;
getline(std::cin, tempStr);
for (int i = 0; i < tempStr.length(); i++)
{
if ((tempStr.compare(i, 1, "0") != 0) && (tempStr.compare(i, 1, "1") != 0))
{
valid = false;
std::cout << "Enter Valid Binary Number: ";
break;
}
}
} while (valid == false);
return tempStr;
}
Use those in pattern:
std::cout << "Enter Binary Number: ";
std::string binaryString = validateEntry();
int binaryNum = binaryToDec(binaryString);

Finding the highest number in an array of length 5

This should be really simple, but I'm used to higher level languages and am missing something. I'm just trying to make sure the input is five numbers long, and then find the highest number. Unfortunately, something goes wrong in that second part.
#include <iostream>
#include <string>
bool isFiveDigits(int num) {
if (std::to_string(num).length() == 5) {
return true;
} else {
return false;
}
}
int highestInArr(int *nums) {
int highest = nums[0];
for (int i = 1; i < sizeof(nums); i++) {
int temp = nums[i];
if (temp > highest) {
highest = temp;
}
}
return highest;
}
int main() {
using namespace std;
int num;
int nums [5];
cout << "Enter a five digit number!\n";
cin >> num;
if (!isFiveDigits(num)) {
cout << "Not five digits, can you even count?";
return 1;
}
string numstr = to_string(num);
for (int i = 0; i < numstr.length(); i++) {
cout << numstr[i] << " ";
nums[i] = (int)numstr[i];
}
cout << "\n" << highestInArr(nums);
}
When this runs, I get:
Enter a five digit number!
12345
1 2 3 4 5
1424080487
Of course, 1,424,080,487 is not in [1, 2, 3, 4, 5].
You cannot pass a pointer into a function and get the size of it without template deduction. At runtime, all the function receives is a pointer. When you call sizeof(nums), you are not getting the size of the original array. You are simply getting the size of the pointer, which is the same as saying sizeof(int_ptr). Instead, you should be using a std::vector when using collections whose sizes are dynamic.
Now, you CAN receive the size by doing something like this:
#include <iostream>
template<typename num_t, size_t N>
num_t max_num(num_t(&arr)[N]) {
num_t m = (num_t)0;
for (size_t i = 0; i < N; ++i)
if (arr[i] > m)
m = arr[i];
return m;
}
int main(){
int foo[] = { 1, 5, 2, 4, 3 };
int m = max_num(foo);
std::cout << m << std::endl;
std::cin.get();
return 0;
}
However, this is not necessarily preferred and assumes that the array was created on the caller's stack. It does not work for dynamically allocated arrays that were created with new[]. If you do this multiple times with different sizes, you will have multiple implementations of the same function (that's what templates do). The same goes for using an std::array<int, N>. If you use N as a size_t template parameter, it will do the same thing.
There are two preferred options:
Send the size of the array into the function so that the caller is responsible for the size.
Use a different container such as std::vector so the callee is responsible for the size.
Example:
#include <vector>
#include <iostream>
#include <algorithm>
int main(){
std::vector<int> vec{ 1, 5, 2, 4, 3 };
int m = *std::max_element(std::cbegin(vec), std::cend(vec));
std::cout << m << std::endl;
std::cin.get();
return 0;
}
As for the is_5_digits, you should use the base-10 logarithm function.
#include <cmath>
// ...
int i = 12345;
size_t length = (i > 0 ? (int)log10(i) : 0) + 1;
std::cout << length << std::endl; // prints 5;
First of all, you can't simply convert a char to int just like (int)numstr[i] assuming that it will return the digit which it contains.
See, if you have a char '0', it means it's ASCII equivalent is stored, which is 48 in case of 0, 49 in case of '1' and so on.
So in order to get that digit (0,1,2,...,9), you've to substract 48 from the ASCII value.
So change this line:
nums[i] = (int)numstr[i];
to:
nums[i] = (int)numstr[i] - 48; // or nums[i] = (int)numstr[i] - '0';
And another thing, in your highestInArr function, you're getting a pointer as parameter, and in the function, you're using sizeof to determine the size of the array. You can't simply do that, the sizeof will return the size of int*, which is not the size of the array, so you've to pass size as the second argument to the function, and use it in the loop.
Like this:
int highestInArr(int *nums, int size) {
// ...
for (int i = 1; i < size; i++) {
// ...
}
// ...
}

run time error with function convert from string to int

I have a string contains numbers but also contains spaces between them, i need to convert the string to int and store them in an int array .
Th following function produces a run time error
void fun(string m)
{
string temp;
int j = 0;
int h = 0;
int d;
int arr[10];
for (int i = 0; i < m.length(); i++)
{
while (m[i] != ' ')
temp[j++] = m[i];
d = atoi(temp.c_str());
arr[h++] = d;
}
for (int i = 0; i < sizeof(arr); i++)
{
cout << arr[i];
}
}
I would suggest using a stringstream for this vs. rolling your own implementation.
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::stringstream ss("1 2 3 4 5 6 7");
auto head = std::istream_iterator<int>(ss);
auto tail = std::istream_iterator<int>();
while(head!=tail)
{
std::cout << *head << "\n";
++head;
}
return 0;
}
if you're receiving the string in a method you can easily adapt the function above to create an empty stringstream and then pass it the string.
#include <sstream>
#include <iterator>
#include <iostream>
int main()
{
std::string astring = "1 2 3 4 5 6";
std::stringstream ss;
ss << astring;
auto head = std::istream_iterator<int>(ss);
auto tail = std::istream_iterator<int>();
while(head!=tail)
{
std::cout << *head << "\n";
++head;
}
return 0;
}
You are making several mistakes in your code.
You have not initialized temp to contain anything, but you are trying to index into its characters. Instead of temp[j++] = m[i], you need to use temp += m[i]; or temp.push_back(m[i]); or temp.append(&m[i], 1);. Or consider using an std::ostringstream to gather the characters, and then call its str() method to extract the final std::string value.
you are not incrementing i in your while loop. As soon as the for loop reaches a non-whitespace character, your while loop will end up running endlessly, continuously (and unsuccessfully) trying to append the same character to temp.
you are not doing any bounds checking to make sure your for loop does not exceed arr's max capacity of 10 numbers.
you are misusing sizeof(). sizeof(arr) returns the number of bytes that arr occupies in memory (10 * sizeof(int), which is 20 or 40 bytes, depending on your compiler's implementation of int). It is not the number of elements in the array (10). So you will exceed the bounds of the array trying to display 20/40 numbers instead of 10 numbers.
Your code is more complicated than it needs to be. You can use a std::istringstream for parsing and let it ignore whitespace for you. Use std::vector or other dynamically-sized container to receive the parsed numbers.
#include <sstream>
#include <vector>
void fun(string m)
{
std::istreamstream iss(m);
std::vector<int> vec;
int num;
vec.reserve(10); // optional
while (iss >> num) {
vec.push_back(num);
}
for (int i = 0; i < vec.size(); ++i) {
std::cout << vec[i];
}
/*
alternatively:
for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); ++iter) {
std::cout << *iter;
}
*/
/*
alternatively (C++11 and later):
for (auto i: vec) {
std::cout << i;
}
*/
/*
alternatively (C++11 and later):
std::for_each(vec.begin(), vec.end(), [](int &n){ std::cout << n; });
*/
}
You cannot do for (int i = 0; i < sizeof(arr); i++)
The sizeof() operator gives you the size of something in bytes, which for an array of 10 ints probably amounts to 40. You need to use something like this:
#define COUNTOF(x) ((x)/sizeof((x)[0]))
for (int i = 0; i < COUNTOF(arr); i++)
The problem is in your while loop, J is 0 the first iteration through the While loop and gets incremented the first time it's called while also trying to assign it to the next letter.
Despite this issue I'd suggest using a string stream for this problem like others have said.
Here's a good reference.

Error-correcting loop in C++, find specific chars in a string and flag as bad input

Here is v1.0 of the binary_to_decimal converter I wrote. I want to make several changes as I keep improving the spec. Classes and pointers will be added as well in the future. Just to keep me fresh and well practiced.
Well, I now want to implement an error-correcting loop that will flag any character that is not a 0 or a 1 and ask for input again.
I have been trying something along the line of this code block that worked with an array.
It might be way off but I think I can tweak it. I am still learning 0_0
I want to add something like this:
while ((cin >> strint).get())
{
cin.clear(); //reset the input
while (cin.get() != '\n') //clear all the way to the newline char
continue; //
cout << "Enter zeroes and/or ones only! \n";
}
Here is the final code without the error-correcting loop:
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
const int MAX = 100;
int conv(int z[MAX], int l[MAX], int a);
int main()
{
int zelda[MAX];
int link[MAX];
string strint;
int am;
cout << "Enter a binary number: \n";
(cin >> strint).get(); //add error-correction to only read 0s and 1s.
am = strint.size();
cout << am << " digits entered." << endl;
int i = 0;
int p = 0;
while (i < am)
{
zelda[i] = strint[p] - '0'; //copies the string array elements into the int array; essentially STRING TO INT (the minus FORCES a conversion because it is arithmetic) <---- EXTREMELY CLEVER!
++i;
++p;
}
cout << conv(zelda, link, am);
cin.get();
return 0;
}
int conv(int zelda[MAX], int link[MAX], int length)
{
int sum = 0;
for (int t = 0; t < length; t++)
{
long int h, i;
for (int h = length - 1, i = 0; h >= 0; --h, ++i)
if (zelda[t] == 1)
link[h] = pow(2.0, i);
else
link[h] = 0;
sum += link[t];
}
return sum;
}
thanks guys.
I'm not completely sure of what you're trying to do, but I think what you're wanting is string::find_first_not_of. There's an example included in that link. You could have something like: myString.find_first_not_of("01");
If the return value is string::npos, then there are no characters in the string other than 1 or 0, therefore it's valid. If the return value is anything else, then prompt again for valid input and continue looping until the input's valid.