How do I assign a char* to a char array? - c++

Compiler tell me "incompatibles type in assignments of char* to char[32]"
this is my code:
char* generalOperations[2]={"Off","On"};
void test(){
char value[32];
switch(swapVariable){
case 0:
value=generalOperations[0]; //<==Error HERE!
break;
}
}
[Solved]:
strcpy(value,generalOperations[0]);

Use std::string instead of char* and std::array<T, N> instead of T[N]. Both are type safe (as opposed to memcpy), both are in modern C++ style and both are directly assignable using the assignment operator.
#include <array>
#include <string>
std::array<std::string, 2> generalOperations{"Off", "On"};
void test() {
std::string value;
switch(swapVariable) {
case 0: value = generalOperations[0]; break;
}
}

You can't assign arrays. You can either change the type of value to a char* or copy the content of generalOptions[0] into value. If you are going to copy the content, then you need to ensure that value has enough space to hold the content of the element in generalOperations.
Modifying a string literal is undefined behaviour, by changing the type to const char* the compiler can detect any attempt to modify one of the entries in generalOperations instead of experiencing odd behaviour at runtime:
const char* generalOperations [2]={"Off","On"};
const char* value;
Note you don't have to specify the number of elements in the array if you are initialising it:
const char* generalOperations [] = {"Off","On"};
Or, if this really is C++ you can make value a std::string instead and just assign to it which will copy the generalOperations element.
As C++ appears to really be the language and C++11 features are permitted instead of using a switch you could create a std::map that associates the int values with the std::string:
#include <iostream>
#include <string>
#include <map>
const std::map<int, std::string> generalOperations{ {17, "Off"},
{29, "On" } };
int main()
{
auto e = generalOperations.find(17);
if (e != generalOperations.end())
{
// Do something with e->second.
std::cout << e->second << "\n";
}
return 0;
}
Demo: http://ideone.com/rvFxH.

#include <string.h>
...
strcpy(value, generalOptions[0]);
You cannot assign arrays in C/C++. There are functions do to that for you. If your char array represents a C style string (i.e. a null terminated sequence of characters), then there are more specialist functions for that as well. strcpy is one of those functions.

Your assignment is wrong, since you cannot assign a char * to char array instead of using this assignment you can use strcpy().

Related

How to read uint8_t data that was converted from vector of string?

I need to use a function func(uint8_t* buffer, uint size); supposing I can't change its parameters, I want to pass it a string.
I have a vector<string> that I must convert to uint8_t* and then read it and convert it back to vector<string>.
I tried this code for reading (printing) the vector.data() output but it prints garbage:
#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
int main() {
std::string a1 = {"ath"};
std::cout <<"1: "<< a1<<" end\n";
std::vector<std::string> vec;
vec.push_back(a1);
uint8_t *ptr = reinterpret_cast<uint8_t*>(vec.data());
std::cout <<"2: "<< ptr[0]<<" end\n";
}
output:
1: ath end
2: � end
questions:
why this doesn't work?
I saw in some links that they init a std::string with char* array like this:
char *ptr={'a'};
std::string myStr(ptr);
I suppose this works because of added '\0', is this related to my problem?
why this doesn't work?
This can't work, because a std::string is not just a contiguous piece of memory containing nothing but the characters in the string. You're simply mistaken about what std::string is!
Using a vector here is plain not the right approach. A vector does not contain your string's contents. Just the std::string objects themselves, which are not the string data.
Instead, you want to make one long std::string:
std::string foo {"foo"};
std::string bar {"bar "};
std::string baz {"bazaz"};
std::string complete = foo + bar + baz;
auto* whole_cstring = reinterpret_cast<uint8_t*>(complete.c_str());
// call your C-string-accepting function
func(whole_cstring, complete.length());
If you actually do have a std::vector of std::strings to begin with, the concatenation can be done in a simple loop:
std::vector<std::string> my_vector_of_strings;
// insert strings into the vector
/// … ///
std::string complete;
for(const auto& individual_string : my_vector_of_strings) {
complete += individual_string;
}
auto* whole_cstring = reinterpret_cast<uint8_t*>(complete.c_str());
// call your C-string-accepting function
func(whole_cstring, complete.length());
… missing \0 … I suppose this works because of added '\0', is this related to my problem?
No, that's completely unrelated.
I have a vector that I must convert to uint8_t*
std::vector<std::string> vec;
"Converting" has a relatively strong definition in the C++ (and other languages) world. If I understand what you mean, I'd suggest the following:
#include <string>
#include <vector>
#include <algorithm>
int main(){
std::vector<std::string> vec;
// populate
std::vector<uint8_t*> vec2(vec.size());
std::transform(begin(vec), end(vec), begin(vec2), [](auto& s){ return reinterpret_cast<unsigned char*>(s.data()); });
}
Alternatively, if possible, you can use a std::basic_string<uint8_t> instead of std::string (a/k/a std::basic_string<char>) to avoid reinterpreting its content.

Statically allocate string array with an initial size

I'm working on a system in which I cannot use dynamic allocation.
I want to have an array of strings which will be filled later.
To my understanding, using
string myArr[20];
will not work, as when I will call
myArr[5] = newString
the copy constructor will allocate new memory dynamically, because the initial length is zero.
Is it possible?
First of all the dynamic memory allocations comes from the fact that you are using std::string, not from the C-like array. If you want to avoid that use const char* instead of std::string.
Secondly, I believe it's generally discouraged to use C-like arrays in C++. If you are working with C++11 or later version you can use std::array.
Yes but it requires coding or external library, just to give you a basic idea :
#include <iostream>
#include <array>
#include <string>
// helper class to just give a basic idea, there are better libaries out there :)
// statically allocates a string buffer of (N+1) chars
template<size_t N>
class static_string
{
public:
static_string() = default;
~static_string() = default;
void operator=(const std::string& str)
{
str.copy(&m_str[0], std::min(str.length(),N) + 1); // string plus trailing 0
}
const char* c_str() const noexcept
{
return &m_str[0];
}
private:
std::array<char, N + 1> m_str{}; // init to zero, zo last char is also always *
};
int main()
{
std::array<static_string<4>, 5> strings;
strings[3] = "Hello world!"; // only will assign first 4 characters, will not resize memory
// outputs a truncated string
std::cout << strings[3].c_str();
return 0;
}

How do I convert a vector<string> to a const char* const* in c++?

I am trying to convert data into the right format for a specific unit test.
The task is to mine a set of words, the unit tests will make sure the results are correct. I have no access to the unit tests, just the declaration which takes a const char* const* Result.
So I need to get my
std::vector<string> Words;
to
const char* const* Result;
divided by a non-alpha char (for example space).
I am aware that this is a constant pointer to a constant character, so I am not sure what to do here since they both constant?
Any pointers (word pun not really intended) are appreciated!
You cannot meaningfully convert one to the other. However, you can convert an array of std::string into an array of pointers to char, and a pointer to the first element of such array would be compatible with your desired result:
std::vector<const char*> Ptrs;
std::transform(
std::cbegin(Words), std::cend(Words),
std::back_inserter(Ptrs),
[](auto& str) { return str.c_str(); }
);
const char* const* Result = Ptrs.data();
Just remember that the strings themselves are still stored in the std::string objects and those pointers within the new vector are only valid as long as the strings in the original vector exist, aren't resized, and the original vector itself isn't resized.
And the pointer to first element of the new vector is only valid as long as that vector exists and isn't resized.
Seems easy enough
#include <algorithm>
#include <functional>
// ...
std::vector<char const*> result_owner(Words.size());
std::transform(begin(Words), end(Words), begin(result_owner),
std::mem_fn(&std::string::c_str));
const char* const* Result = result_owner.data();
Just because Result must provide a const view of the buffer, doesn't mean the buffer has to really be const itself. So it's just another vector that we obtain by projecting Words on the std::string::c_str member.
After that Result can simply be another reference to result_owner.data();.
This of course assumes that Result doesn't have to own the buffer it points at. Owning raw pointers are best avoided.
And the caveman way to do it :)
#include <iostream>
#include <vector>
#include <string>
#include <string.h>
using namespace std;
char **foo(const vector<string> &vec_of_strings)
{
int num_strings = vec_of_strings.size();
int max_str_len = 0;
for (int i=0;i<num_strings;i++)
{
if (max_str_len < vec_of_strings[i].length()) {
max_str_len = vec_of_strings[i].length();
}
}
// for null termination ...
max_str_len++;
char **result = (char **) malloc(num_strings);
for (int i=0;i<num_strings;i++)
{
result[i] = (char *) malloc(max_str_len);
strcpy(result[i],vec_of_strings[i].c_str());
}
return result;
}
int main(int argc, char **argv)
{
vector<string> vec_of_strings;
vec_of_strings.push_back("Long");
vec_of_strings.push_back("Livvvvvvvve");
vec_of_strings.push_back("The");
vec_of_strings.push_back("King");
const char * const * Result = foo(vec_of_strings);
for (int i=0;i<4;i++)
{
printf("%s\n",Result[i]);
}
}

Why aren't string literals passed as references to arrays instead of opaque pointers?

In C++, the type of string literals is const char [N], where N, as std::size_t, is the number of characters plus one (the zero-byte terminator). They reside in static storage and are available from program initialization to termination.
Often, functions taking a constant string doesn't need the interface of std::basic_string or would prefer to avoid dynamic allocation; they may just need, for instance, the string itself and its length. std::basic_string, particularly, has to offer a way to be constructed from the language's native string literals. Such functions offer a variant that takes a C-style string:
void function_that_takes_a_constant_string ( const char * /*const*/ s );
// Array-to-pointer decay happens, and takes away the string's length
function_that_takes_a_constant_string( "Hello, World!" );
As explained in this answer, arrays decay to pointers, but their dimensions are taken away. In the case of string literals, this means that their length, which was known at compile-time, is lost and must be recalculated at runtime by iterating through the pointed memory until a zero-byte is found. This is not optimal.
However, string literals, and, in general, arrays, may be passed as references using template parameter deduction to keep their size:
template<std::size_t N>
void function_that_takes_a_constant_string ( const char (& s)[N] );
// Transparent, and the string's length is kept
function_that_takes_a_constant_string( "Hello, World!" );
The template function could serve as a proxy to another function, the real one, which would take a pointer to the string and its length, so that code exposure was avoided and the length was kept.
// Calling the wrapped function directly would be cumbersome.
// This wrapper is transparent and preserves the string's length.
template<std::size_t N> inline auto
function_that_takes_a_constant_string
( const char (& s)[N] )
{
// `s` decays to a pointer
// `N-1` is the length of the string
return function_that_takes_a_constant_string_private_impl( s , N-1 );
}
// Isn't everyone happy now?
function_that_takes_a_constant_string( "Hello, World!" );
Why isn't this used more broadly? In particular, why doesn't std::basic_string have a constructor with the proposed signature?
Note: I don't know how the proposed parameter is named; if you know how, please, suggest an edition to the question's title.
It's largely historical, in a sense. While you're correct that there's no real reason this can't be done (if you don't want to use your whole buffer, pass a length argument, right?) it's still true that if you have a character array it's usually a buffer not all of which you're using at any one time:
char buf[MAX_LEN];
Since this is usually how they're used, it seems needless or even risky to go to the trouble of adding a new basic_string constructor template for const CharT (&)[N].
The whole thing is pretty borderline though.
The trouble with adding such a templated overload is simple:
It would be used whenever the function is called with a static buffer of char-type, even if the buffer is not as a whole a string, and you really wanted to pass only the initial string (embedded zeroes are far less common than terminating zeroes, and using part of a buffer is very common): Current code rarely contains explicit decay from array to pointer to first element, using a cast or function-call.
Demo-code (On coliru):
#include <stdio.h>
#include <string.h>
auto f(const char* s, size_t n) {
printf("char* size_t %u\n", (unsigned)n);
(void)s;
}
auto f(const char* s) {
printf("char*\n");
return f(s, strlen(s));
}
template<size_t N> inline auto
f( const char (& s)[N] ) {
printf("char[&u]\n");
return f(s, N-1);
}
int main() {
char buffer[] = "Hello World";
f(buffer);
f(+buffer);
buffer[5] = 0;
f(buffer);
f(+buffer);
}
Keep in mind: If you talk about a string in C, it always denotes a 0-terminated string, while in C++ it can also denote a std::string, which is counted.
I believe this is being addressed in C++14 building on user defined string literals
http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
#include <string>
int main()
{
//no need to write 'using namespace std::literals::string_literals'
using namespace std::string_literals;
std::string s2 = "abc\0\0def"; // forms the string "abc"
std::string s1 = "abc\0\0def"s; // form the string "abc\0\0def"
}
You can create helper class that will fix that without using overload for every function
struct string_view
{
const char* ptr;
size_t size;
template<size_t N>
string_view(const char (&s)[N])
{
ptr = s;
size = N;
}
string_view(const std::string& s)
{
ptr = s.data();
size = s.size() + 1; // for '\0' at end
}
};
void f(string_view);
main()
{
string_view s { "Hello world!" };
f("test");
}
You should expand this class for helper function (like begine and end) to simplify usage in your program.

_dynamic_ array initialization

This is a bit weird, but here goes.
I have many hardcoded "tables" that I'm defining as arrays of std::strings or const char *.
So for example:
const char* resp_desc[] = {
"00=Approved",
"01=Declined",
"03=Incorrect User name",
// more values
NULL
};
In some functions these are passed as the table to lookup the description:
const char* lookup(const char* code, const char** table, const char*default="") {
// lookup code is here..
}
my question is, is it possible to call the lookup function without creating the resp_desc array?
The below code was my first attempt, but I get syntax errors around the {} when trying to use it:
const char* desc = lookup("00", {"00=Approved", "01-Invalid Record", NULL})
It doesn't work with the current C++03, but C++0x will allow to initialize i.e. std::vector with
std::vector<std::string>{"00=Approved", "01-Invalid Record"}
Edit: This works with g++ --std=c++0x (gcc --version is 4.4.3)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
bool contains(string item, vector<string> const& table) {
return find(table.begin(), table.end(), item) != table.end();
}
int main() {
cout << (contains("foo", vector<string>{"foo", "bar"}) ? "found" : "not found") << "\n";
return 0;
}
If you are willing to change your look-up function, you could alternatively use utilities like Boost.Assign:
// alternative lookup function:
std::string lookup(const std::string& code,
const std::vector<std::string>& table,
const std::string& default="");
// example:
const std::string desc = lookup("00", boost::assign::list_of
("00=Approved")("01-Invalid Record"));
or maybe simply something like this:
typedef std::map<std::string,std::string> Table;
std::string lookup(const std::string& code,
const Table& table,
const std::string& default="")
{
Table::iterator it = table.find(code);
return (it != table.end()) ? it->second : default;
}
const std::string desc = lookup("00", boost::assign::map_list_of
("00","Approved")("01","Invalid Record"));
In short, no. C++ doesn't provide array or structure literals, only array or structure initializers. That is, the { yadda, yadda, yadda } syntax only means what you want when it occurs on the right side of sometype name[] =.
The answer is no.
In C++ (and also C), array types in function parameters are automatically converted to pointer types, as your signature for lookup shows:
const char* lookup(const char* code, const char** table, const char *default);
table is a const char ** and so needs a pointer value. To have a pointer, you need an object in memory to point at.
If you had a simple function such as:
void myfunc(int foo);
you can call myfunc(1) and that's fine. The constant expression 1 is a temporary value which doesn't have a location in memory, and myfunc receives the value directly.
If however you call your lookup function:
const char* desc = lookup("00", /* array constant */);
we can ask: what could /* array constant */ possibly be? lookup needs a pointer to an array object which exists somewhere in memory; but a constant expression doesn't have a location in memory (it is not an lvalue or object) and so there can be no pointer which refers to the constant array expression. As a result, such constant expressions do not exist.
(The one exception to this rule of "no constants which decay to pointers" is the string literal: "Hello World". A string literal creates an array in memory with static duration which exists for the lifetime of the program, and its value returned is a const char * pointing to that array. Sadly, the equivalent for array literals does not exist.)
No sir! The curly bracket syntax is for array initialization only. It does not represent a literal array.