C++: incompatible types in assignment of - c++

I create this struct:
struct message_text{
char text[1024];
};
message_text instance;
instance.text = "HELLO WORLD, FIRST MESSAGE";
I get this error:
error: incompatible types in assignment of ‘const char [27]’ to ‘char [1024]’
instance.text = "HELLO WORLD, FIRST MESSAGE";
I don't understand this error because the size of instance.text does not exceed the maximum message size, which is 1024 bytes.
I have seen other similar questions but I could not understand what my mistake was when creating the structure
Help is appreciated

char arrays don't work like that - you can't assign them in the same way you would an int, for example (although you can do it when initializing the array). If you want to copy that literal into your char array, use strncpy.
Or, better than that, seeing as you've tagged it as C++ - just use the standard string class.

As others mentioned, you should be using std::string. But if you really want to assign a string literal to the array, you can do like below:
struct message_text{
char text[1024];
template <int N>
void assignText(const char (&other)[N]) {
static_assert(N < 1024, "String contains more than 1024 chars");
for(int i =0 ; i < N ; ++i) {
text[i] = other[i];
}
}
};
Note:
The above only works for assigning from string literals or char arrays. Does not support null terminated strings.
Since assignText is a template, it generates a function for each usage with unique N. This might lead to increased binary size.
Since assignText is a template, you have to define it in a header or within the same source file.
Compiler Explorer: https://godbolt.org/g/1oLcAq

Related

Use the result of strlen as length of char*

My intention is to create a char[] from the length of a char* I've already created.
I asked myself why this is not valid:
void copyStringsV2() {
const char* source = "this is my string.";
const int length = strlen(source);
const char* dest[length];
}
The compiler gives me this hint:
Severity Code Description Project File Line Suppression State
Warning C4101 'str_b': unreferenced local variable CStrings
xxx\cstrings.cpp 46
Error C2131 expression did not evaluate to a constant CStrings
xxx\cstrings.cpp 161
Error (active) E0028 expression must have a constant value CStrings
xxx\CStrings.cpp 161
May you can help me out here?
You are trying to declare a variable-length array, which is not a standard feature in C++. A fixed-length array must have its length known at compile-time. That is what the compiler error is complaining about.
If you don't know the length until runtime, you will have to allocate the copied string dynamically instead, such as via new[]:
void copyStringsV2()
{
const char* source = "this is my string.";
const int length = strlen(source);
char* dest = new char[length+1];
strcpy(dest, source);
...
delete[] dest;
}
Or std::vector, so you don't need to use new[]/delete[] directly:
#include <vector>
void copyStringsV2()
{
const char* source = "this is my string.";
const int length = strlen(source);
std::vector<char> dest(length+1);
strcpy(dest.data(), source);
...
}
But, in this case, it would be better to use std::string instead:
#include <string>
void copyStringsV2()
{
const char* source = "this is my string.";
std::string dest = source;
...
}
For starters you should use the type size_t instead of the type int in this declaration
const int length = strlen(source);
^^^
This constant is a constant of the run-time. So you may not use it in the declaration
const char* dest[length];
because here is declared a variable length array and variable length arrays (VLA) is not a standard C++ feature.
Also it is unclear why the type of elements of the array is const char * instead const char.
And moreover a constant object shall be initialized.
My intention is to create a char[]
const char* dest[length];
That's not an array of char. That's an array of pointers to const char.
Also, if you want the array to be able to fit the original null termiated string, you must include the null terminator in the length of the array so that its size is length + 1.
I asked myself why this is not valid:
The compiler gives me this hint:
expression did not evaluate to a constant
May you can help me out here?
The size of an array must be a compile time constant. length is not a constant, therefore it cannot be used as length of an array.
Length of a string cannot be calculated at compile time through a pointer to element of the string. However, if you used a reference for example, and if you used a constexpr function to get the length, and used a constexpr (const works too) variable, then you could use it as the size of an array. There is such function in the C++ standard library:
auto& source = "this is my string.";
constexpr auto length = std::char_traits<char>::length(source);
char dest[length + 1];
why this is not compilable
Because this is C++, and C++ provide a wide variety of tools already1. Your best bet will be std::string. Strings can be copied and passed around with no additional code to write.
#include <string>
int main()
{
const std::string source = "this is my string.";
const std::string dest = source;
// do something with dest
}
1) So you don't need variable length arrays, which are not part of C++.

c++ create an array with string::size

Im trying to create an array with the string::size member but its complaining at the declaration of "char message[msgSize]" that the expression did not evalute to a constant.
However it alows me to declare "msgSize".
How can this be? Why am i allowed to make a constant but i'm not allowed to use it to something that needs a const.
If the answer is that: "the size of the string could change" then the same argument can be made for using sizeof(), but that works.
const unsigned int msgSize =
saveAs.size() +
sizeof("NOTE| sent get request to: ") + 10;
char message[msgSize];
memset(message, 0, msgSize);
sprintf_s(message, msgSize,"NOTE| sent get request to: %s", saveAs.c_str());
_cRec->output(message);
Well const just means that you promise that the value won't change. And you can even override that with a const_cast.
What compiler needs there is a value that can be evaluated at the compile time. This is a stronger requirement. Such values are marked with constexpr keyword.
Unfortunately you are out of luck with std::string... size() is not a constexpr.
I played with the following example:
#include <iostream>
#include <string>
using namespace std;
const string msg("Some msg");
constexpr int msg_len = msg.size();
int main() {
char msg[msg_len];
cout << sizeof(msg);
return 0;
}
The thing is that size() is not a constexpr, and you cannot make string a constexpr because it has a non-trivial destructor.
Why it is designed this way is beyond me. Seems like a counter intuitive and serious limitation. However, there are pretty clever implementation of string, for example with small storage optimization. It might be hard to make them constexpr with out serious changes in the implementation.
You would have to make your array dynamic.
The size of the string is not known at compile time, but only at run time.
Also, your listing is not a minimal compilable example. I can only assume saveAs is an std::string.
The following would work:
int main()
{
std::string myString("My string");
char * myCStyleString = new char[myString.size()];
delete[] myCStyleString;
}
because we are dynamically allocating an array there.
What are you trying to do? It looks like you just want to copy a filename into a message string. Just keep using std::string;
int main()
{
std::string myString("My string");
std::string message = "I like beans and rice with: ";
message += myString;
return 0;
}
but again, I'd need a minimal compilable example to determine your goal.
In C++ you cannot declare VLAs.
When you declare an array, for example:
char message[x];
The expression x must to be valuable at compile time, that is its value has to be well-known when the source is compiled.
In you example:
char message[msgSize];
The expression (variable) msgSize is not known at compile time, but only at run time. That because the compiler has to know how many bytes reserve in the stack.
Note: the variable msgSize is a constant value. A constant value is not an expression evaluate at compile time. It simply means that its value cannot change once has been assigned.
In C++11 has been introduced the keywork constexpr in order to define an expression which should be evaluate at compile time.
However in your case there is not way to get the size of a dynamic string at compile time. So what you have to do is use dynamic array (dynamic memory).
char* message = new char[msgSize];
// now you have an array of msgSize lenght
// ... do stuff...
// do not forget to release the memory when end
delete[] message;
Finally, I suggest you to re-elaborate your code because it's likely you don't need a dynamic array of chars, but just a std::string. Indeed you can use overloaded operator + in order to concatenate strings and the method std::string::c_str() to access as const char* for backward compatibility.
Why am i allowed to make a constant but i'm not allowed to use it to
something that needs a const.
This is because the "constant" expression you have is made up of non constant parts i.e. the size method of the string class. It is not truly constant in terms of having a known value at compile time.
Consider using constexpr variable/function in the future
If the answer is that: "the size of the string could change" then the
same argument can be made for using sizeof(), but that works.
No that same argument cannot be used for sizeof because sizeof does not need it's arguement to be a constant.
If you know for a fact that saveAs contains a string with a known size, then perhaps it would be best if you declare that size as a constant and then refer to it in your calculation:
constexpr unsigned int msgSize =
SAVEAS_SIZE +
sizeof("NOTE| sent get request to: ") + 10;
Then this will allow you to do:
char message[msgSize];
You need a compile-time constant with char message[msgSize]; because this is a local variable which uses static memory that is allocated in the data segment, so the compiler needs to calculate the number of bytes required by the code, including the local variables and arrays.
You can use dynamic memory to solve your problem. The dynamic memory is allocated in the heap. In C, you should use malloc(). In C++, you should use new[] (or better, std::vector, or even std::string). Then you can specify the memory size using a runtime value in a variable.
So, your code would look more like the follow:
char* message = new char[msgSize]; //Allocated memory
//Do everything that you need...
delete[] message; //Release memory
Or:
#include <vector>
std::vector<char> message(msgSize); //Allocated memory
//Do everything that you need...

Putting a constant char in a char matrix

I have a char matrix (relation[][]) and I want to put some character in several items of that. look:
char relation[num_obj][num_obj];
for(k1=0; k1<num_obj; ++k1)
for(k2=0; k2<num_obj; ++k2)
if(k1 != k2)
if(Top[i][j]==1)
{
strstr((const char *)relation[i][j], "T");
strstr((const char *)relation[i][j], "B");
}
k1,k2,num_obj are some defined variable.
As you see I am trying to put some constant char (like " T, B) to some elements of matrix, but I receive this warning:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Can any one help me in removing this warning.
Thanks in advance and all the best :)
If you're just trying to write a 'T' into the array, that's just assignment:
relation[i][j] = 'T';
strstr is a method to find a substring in a string. It's only useful for its return-value, so even if you got your code to compile, it just wouldn't do anything.

Finding the length of a character array in c++ [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 8 years ago.
I have an character array of the form
char x[]='asdasdadsadasdas';
int p = sizeof(x)/sizeof(*x)
gives me correct result but when I pass this as an argument in another function like
void X(char* a)
int i = sizeof(a)/sizeof(*a)
and I call it
X(x)
p and i are not equal.How is it possible ?
When the char array gets passed to a function accepting a char*, the array is said to 'decay' to a pointer. This conversion is automatic, and the length information which was previously statically available to the compiler is lost.
Possible solutions are:
Pass the size of the array as an additional parameter.
Make the char-Array 0-terminated (i.e., a string literal) and use strlen. This is the common ways of operating on strings in C and C++. However, this introduces runtime cost which is not strictly necessary. However it provides some convenience (same API for statically and dynamically sized strings) and error resilience (the length is always correct).
Use templates to capture the length of the array. This is explained here..
void X(char* a)
int i = sizeof(a)/sizeof(*a)
Here, a is a pointer and *a is a char. So sizeof(a) won't return the size of the array, but the size of the pointer to the first element in the array.
In order to find the length of the string (which isn't the same as "the size of the array"), you have a few options.
One, don't use a char* at all, but a std::string (may create a temporary):
void X (const std::string& s)
{
size_t i = s.length();
}
Two, scan the string for the null-terminator (linear complexity):
void X (const char* p)
{
size_t i = strlen (p);
}
Three, use a template (needlessly complex code):
template <size_t N> void X (const char (&arr)[N])
{
size_t i = N;
}
Each of the above has it's own set of cons. But this is all best avoided if you take a broader look at your program and see where you can make improvements. Here's one that stands out to me:
char x[]='asdasdadsadasdas';
C-style arrays present their own problems and are best avoided altogether. Instead of using a C-style array, use a tool from the StdLib designed for just this problem:
std::string x = "asdasdadsadasdas";
sizeof(char *)
Gives you the size of a pointer. Eight bytes on my system.
char x[] = "fred";
sizeof(x);
Returns 5. The size of the string with the null termination.
void x(char * c) {
sizeof (*c);
}
Returns the size of a a char.
This is true no matter what the length or original type of the array is passed to void x(). Note that sizeof() is evaluated at compile time. At compile time the compiler cannot normally know what length of array it's been passed. For a run-time evaluation of string length, as said above, use strlen if you actually want the strings length in characters. (Or a template - but that's probably a more unusual solution).

Making a std::string out of a Char* in C++

OSX 10.8, Carbon
I have a std::string that I want to derive from a Char*
Example:
CFStringRef *s;
char *c[128];
CFStringGetCString(*s, *c, 128, kCFStringEncodingUTF8);
int size = sizeof(c);
g_uid.assign(c, size);
But I am getting an invalid conversion and I dont understand why
error: invalid conversion from 'char**' to 'long unsigned int'
std::string g_uid = ""; is defined as a global
You're too generous with the asterisks - you generally don't need a pointer to CFStringRef, and your array is actually an array of pointers, which is not what you want.
It should look more like this:
CFStringRef s;
char c[128];
if (CFStringGetCString(s, c, 128, kCFStringEncodingUTF8))
{
g_uid = c;
}
else
{
// 128 characters wasn't enough.
}
If c where a char*, the following would work:
g_uid.assign(c, size);
The problem is that c isn't char*, it's an array of 128 char*s:
char *c[128];
This is a common beginners mistake in C/C++. I remember making this same mistake back in the day. A declaration like
char *c[128]; isn't giving you an array of 128 characters as you might be led to believe. Its actually giving you an array of 128 pointers to chars. You don't want that.
You want to declare an array of 128 chars which looks like:
char c[128];
Now you might not think that c was a char* because you don't see any *s but any time you declare an array of something, that variable is automatically a pointer of whatever type you specify. It actually points to the address of the very first element of the array.