C++ std::string array to unsigned char array conversion - c++

I have a std::string array which I need to convert to an unsigned char array so that I can use this array with third-party library which only accepts unsigned char array.
let say my array is
std::string array[3];
array[0] = "a105b";
array[1] = "c258e"
array[2] = "ff587";
I need to transfer this array into:
unsigned char cArray[3][5];
I can do hardwire the unsigned char as below:
unsigned char cArray[3][5] = {"a105b", "c258e", "ff587"};
but I was unable to find a way to do it using C++ code to transfer the data from the std::string array to the unsigned char array.

You could make a function that loops through the two arrays and copies from one to the other.
Example:
#include <algorithm>
#include <iostream>
#include <string>
template<size_t R, size_t N>
void foo(const std::string(&src)[R], unsigned char(&dest)[R][N]) {
// both `src` and `dest` must be arrays with `R` rows
// `N` is how many unsigned chars each inner array in `dest` has
for(size_t idx = 0; idx < R; ++idx) {
// Copy from `src[idx]` to `dest[idx]`
// Copy at most `N` chars but no more than the length of the string + 1
// for the null terminator:
std::copy_n(src[idx].c_str(), std::min(N, src[idx].size() + 1), dest[idx]);
// Add the below line if the arrays in cArray are supposed to
// be null terminated strings:
//dest[idx][N - 1] = '\0';
}
}
int main() {
std::string array[3];
array[0] = "a105b";
array[1] = "c258e";
array[2] = "ff587";
unsigned char cArray[3][5];
foo(array, cArray);
}
I can do hardwire the unsigned char as below
unsigned char cArray[3][5] = {"a105b", "c258e", "ff587"};
No, that's not valid in C++. You would have to make the inner array [6] in C++:
unsigned char cArray[3][6] = {"a105b", "c258e", "ff587"};

In code it could look like this:
#include <array>
#include <algorithm>
#include <cstring>
#include <string>
template<typename to_type, size_t buf_size, size_t number_of_strings>
void to_array(const std::array<std::string, number_of_strings>& input,
to_type (&output)[number_of_strings][buf_size])
{
for (std::size_t n = 0; n < number_of_strings; ++n)
{
const auto input_str = input[n].c_str();
// for input string include trailing 0 on input so add one to length
const auto copy_len = std::min(input[n].length()+1, buf_size);
std::memcpy(output[n], input_str, copy_len);
}
}
int main()
{
std::array<std::string, 3> input_array{ "a105b", "c258e", "ff587" };
unsigned char c_array[3][6];
to_array<unsigned char, 6>(input_array, c_array);
return 0;
}
It showed me again that 'c' style arrays are not nice to work with.
You can't return them from a function (like you can with std::array).
So you have to pass the output array as parameter to the conversion function too.

You are not permitted to assign to a plain array. You cannot define your own assignment operator for the plain array, because C++ does not allow overload of the assignment operator except as a non-static member function of a class.
One workaround may be to define an overload for a shift operator, and give a similar syntax to an input stream.
template <unsigned N>
void operator >> (std::string s, unsigned char (&a)[N]) {
auto n = (s.size() < N) ? s.size() + 1 : N;
std::copy_n(s.c_str(), n, a);
}
/*...*/
unsigned char cArray[3][5];
array[0] >> cArray[0];
array[1] >> cArray[1];
array[2] >> cArray[2];

Related

c++ code type substition fail

I have this code, but is impossible to compile with g++ or msvc. I am trying to make a custom type CharNw that I can use it as string, in existing all string routines or pass as argument all existing functions:
#include <string.h>
#include <stdio.h>
void fx(unsigned int x)
{
/*this is the reason of all this
but is ok, not is problem here */
.....
}
class CharNw
{
int wt;
char cr;
public:
CharNw() { wt = -1; cr = '\0'; }
CharNw( char c) { if wt > 0 fx( (unsigned int) wt); cr = c; }
operator char () { if wt > 0 fx( (unsigned int) wt); return cr ;}
assgn( int f) { wt = f;}
};
int main(void)
{
CharNw hs[40]; //it is ok
CharNw tf[] = "This is not working, Why?\n";
char dst[40];
strcpy(dst, tf); //impossible to compile
printf("dst = %s, tf = %s", dst, tf); //too
return 0;
}
Can help me?
Line by line.
CharNw hs[40]; //it is ok
The above is an array of CharNw objects with a capacity of 40 elements. This is good.
CharNw tf[] = "This is not working, Why?\n";
On the right hand side (RHS) of the assignment, you have a type char const * const* and on the left you have an array ofCharNw. TheCharNw` is not a character, so you have a problem here. Prefer to have both sides of an assignment to have the same type.
char dst[40];
An array of characters. Nothing more, nothing less. It has a capacity of 40 characters. The dst array is not a string. You should prefer to use #define for your array capacities.
strcpy(dst, tf); //impossible to compile
The strcpy requires both parameters to be pointers to char. The left parameter can be decomposed to a pointer to the first char of the array. The tf is an array of CharNw which is not compatible with an array of char nor a pointer to char.
printf("dst = %s, tf = %s", dst, tf); //too
The printf format specifier %s requires a pointer to a character, preferably a C-Style, nul terminated array (or sequence) of characters. The tf parameter is an array of CharNw which is not an array of characters nor a pointer to a single character or a C-Style string.
Edit 1: Conversion Operators
The method operator char () in your class converts a character variable to a CharNw variable. It does not apply to pointers nor arrays.
You would need some messy pointer conversion functions.
Here is an examples:
const unsigned int ARRAY_CAPACITY = 40U;
const char text[] = "I am Sam. Sam I am."
CharNw tf[ARRAY_CAPACITY];
for (unsigned int i = 0U; i < sizeof(text); ++i)
{
tf[i] = text[i]; // OK, Converts via constructor.
}
for (unsigned int i = 0U; i < sizeof(text); ++i)
{
printf("%c", tf[i]); // The tf[i] should use the operator char () method.
}
A better approach is to declare a class using std::basic_string, rather than trying to squeeze your class into the C-Style string functions.
For example:
class StringNw : public std::basic_string<CharNw>
{
};

Using a <string,string> or <string, char> map instead of <char, char> in C++

I am new to STL and want to get used to string datatype instead of the char datatype. I am trying to map a string to a char in this code but it gives 2 compilation errors at lines 13 and 14 - "error: invalid conversion from 'char' to 'const char*' and error: invalid conversion from 'int' to 'const char*'". How can I fix these errors?
I have written the correct code in commented lines (using a map of char,char) to show what I want to implement with strings. I think the problem is probably that a string is not taken as an array of characters in C++.
What is the best way to implement the same without using char datatype?
#include <bits/stdc++.h>
using namespace std;
int main()
{
//map<char,char> M;
map<string, char> M;
string S,R;
cin>>S>>R;
for(int i=0;i<26;i++)
{
//M[S[i]]=(char)(i+'a');
//M[(char)toupper(S[i])]=(char)(i+'A');
M[S[i]]=(char)(i+'a');
M[toupper(S[i])]=(char)(i+'A');
}
for(int i=0;i<R.size();i++)
cout<<M[R[i]];
return 0;
}
Thanks in advance.
S[i] returns a single char, while toupper() returns an int. std::string does not have a constructor that accepts a single char by itself (but it does have an = operator that does) or an int at all. You need to use something more like this instead:
// using string(const char* s, size_type count)
char c = S[i];
M[string(&c, 1)] = (char)(i+'a');
c = (char) toupper(c);
M[string(&c, 1)] = (char)(i+'A');
Or:
// using string(size_type count, char ch)
char c = S[i];
M[string(1, c)] = (char)(i+'a');
c = (char) toupper(c);
M[string(1, c)] = (char)(i+'A');
Or:
// using operator=(char ch)
string tmp;
tmp = S[i];
M[tmp] = (char)(i+'a');
tmp = (char) toupper(c);
M[tmp] = (char)(i+'A');

Conversion from string to Ice::ByteSeq

I gotta question about Ice in C++. One of my methods requires that I pass in a Ice::ByteSeq. I would like to build this ByteSeq from a string. How is this conversion possible?
I tried the options below.
Ice::ByteSeq("bytes") // Invalid conversion to unsigned int
Ice::ByteSeq((byte*)"bytes") // Invalid conversion from byte* to unsigned int
(Ice::ByteSeq)"bytes" // Invalid conversion from const char& to unsigned int
(Ice::ByteSeq)(unsigned int)atoi("bytes") // Blank (obviously, why did I try this?)
How can I make this happen?
EDIT
"bytes" is a placeholder value. My actualy string is non-numeric text information.
Looking at the header, ByteSeq is an alias for vector<Byte>. You can initialise that from a std::string in the usual way
std::string s = "whatever";
Ice::ByteSeq bs(s.begin(), s.end());
or from a string literal with a bit more flappery, such as
template <size_t N>
Ice::ByteSeq byteseq_from_literal(char (&s)[N]) {
return Ice::ByteSeq(s, s+N-1); // assuming you don't want to include the terminator
}
Ice::ByteSeq bs = byteseq_from_literal("whatever");
You were almost there,
Ice::ByteSeq((unsigned int)atoi("bytes"));
should do it
Assuming your Ice::ByteSeq has a constructor that takes unsigned int
To split this down, it's basically doing
int num = atoi("12345"); // num = (int) 12345
unsigned int num2 = (unsigned int)num; // num2 = (unsigned int) 12345
Ice::ByteSeq(num2);
If Ice::ByteSeq is simply a vector of bytes you can convert a string to a vector of bytes by doing a variation of the following:
std::string str = "Hello World";
std::vector<char> bytes(str.begin(), str.end());
The implementation of Ice::Byte is an unsigned char just change the standard code I posted from:
std::vector<char> bytes(str.begin(), str.end());
to
std::vector<unsigned char> bytes(str.begin(), str.end());
and the generated vector should be directly compatible with an Ice::ByteSeq
sample code:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::string str = "Hello World";
std::vector<unsigned char> bytes(str.begin(), str.end());
cout << str << endl;
for(int i=0; i < bytes.size(); i++)
std::cout << bytes[i] << '\n';
return 0;
}
Hope this helps:)

Dividing a string to smaller strings in C++

I have a string which has 1000 characters. I want to split this string to an array of strings of 5 characters each. The code is:
int main()
{
string myarray[200];
int k = 0;
string num = "a string with 1000 characters";
while(!num.empty())
{
strncpy(myarray[k],num.c_str(),5);
num.erase(0,5);
k++;
}
}
This code gives this error :
cannot convert 'std::string {aka std::basic_string}' to 'char*'
for argument '1' to 'char* strncpy(char*, const char*, size_t)'|
I tried the code without .c_str(), the result was same.
How can I fix this? Thanks.
Function strncpy expect first argument is char* while you passed string to it. Compiler will complain that it can't convert std::string to char*:
char *strncpy( char *dest, const char *src, std::size_t count );
Better use std::vector and call std::string::substr:
#include <string>
#include <vector>
std::string num("a string with 1000 characters");
std::vector<std::string> myarray;
myarray.reserve(200);
for (int i=0; i<num.size(); i+=5)
{
myarray.push_back(num.substr(i, 5));
}
You should use std::substr and std::vector:
#include <string>
#include <vector>
std::string num = "a string with 1000 characters";
std::vector<std::string> myArray;
for ( unsigned int i = 0; i < num.length(); i += 5 )
{
myArray.push_back( num.substr( i, 5 ) );
}
std::vector is a bit more flexible than array.
A working live example.
You may use std::substr as:
string MyArray[200];
for int i = 0;i<1000;i+=5)
{
MyArray[i] = num.substr(i,5);
}
And I would advice you to use vector<string> instead of MyArray[200] for a bit more flexibility.

How do I convert a string in C++ or C to an integer array?

How do I convert a string into an array of integers? Can I use sstream, because atoi doesn't work?!
As you said in the comments, you got a binary string and you want to convert it into integers. Use bitset for that:
std::istringstream is(str);
std::bitset<32> bits; // assuming each num is 32 bits long
while(is >> bits) {
unsigned long number = bits.to_ulong();
// now, do whatever you want with that long.
v.push_back(number);
}
If you only have one binary number in that string str, you can get away with
unsigned long number = std::bitset<32>(str).to_ulong();
Converting that in C is also possible...
long value;
char const *c = str;
for(;;) {
char * endp;
value = strtol(c, &endp, 2);
if(endp == c)
break;
/* huh, no vector in C. You gotta print it out maybe */
printf("%d\n", value);
c = endp;
}
atoi can't parse binary numbers. But strtol can parse them if you tell it the right base.
How exactly would you like the conversion to work?
Do you simply want an array containing the ASCII value of each character in the array? (so "abc" becomes [97, 98, 99, 0])?
Or do you want to parse the string somehow? ("1, 2, 3" becomes an array [1, 2, 3])
In the first case, in C++, I'd do something like this:
struct convert {
int operator()(char c) {
return static_cast<int>(c);
}
};
std::string str = "hello world";
std::vector<int> result;
std::transform(str.begin(), str.end(), std::back_inserter(result), convert())
Of course you could use a raw array instead of the vector, but since the length of the string is probably going to be variable, and then arrays are just asking for trouble.
If this wasn't what you wanted, you might want to edit your question to be more specific.
From what I understand, for input string "110013" would be converted to array {1,1,0,0,1,3}. Here is how to do it in C++:
string a = "1110011000";
vector<int> v;
for(int i = 0 ; i < a.length() ; i++){
v.push_back(a[i] -'0');
}
// Check the result
for(int i = 0 ; i < v.size() ; i++){
cout << v[i] << endl;
}
Quick string splitter routine:
convert(string str, string delim, vector<int>& results)
{
int next;
char buf[20];
while( (next= str.find_first_of(delim)) != str.npos ) {
if (next> 0)
results.push_back(atoi(str.substr(0,next), buf, 10));
str = str.substr(next+1);
}
if(str.length() > 0)
results.push_back(atoi(str.substr(0,next), buf, 10));
}
You can use stringstream instead of atoi (which does work, on a single int at a time)
int i;
stringstream s (input_string)
s >> i;
If you combine my and jalf's code, you'll get something really good.
Use the istream_iterator in conjunction with a string stream.
By Array I am assuming you really mean a std::vector as you don't know the number of integers at compile time. But the code can easily be modified to use an array rather than a vector.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::string data = "5 6 7 8 9";
std::vector<int> store;
std::stringstream dataStream(data);
std::copy(std::istream_iterator<int>(dataStream),
std::istream_iterator<int>(),
std::back_inserter(store)
);
// This line just copies the store to the std::cout
// To verify it worked.
std::copy(store.begin(),
store.end(),
std::ostream_iterator<int>(std::cout,",")
);
}
Language: C
Header:
#include <stdlib.h>
Function Prototype:
long int strtol(const char *nptr, char **endptr, int base);
Example Usage:
strtol(nptr, (char **) NULL, 10);