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.
Related
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
Can somebody help me out with below error. Shall I cast len before I try to pass buf?
int len=2;
unsigned char tmp[len + 1];
unsigned char * buf = &tmp;
The error is:
error: cannot convert 'unsigned char (*)[(((unsigned int)((int)len)) + 1)]' to 'unsigned char*' in assignment
If you just want a pointer to the array, use
unsigned char * buf = tmp;
By the way, the way you declare tmp makes it a variable-length array (VLA). Technically, these are not allowed in C++, although many compilers support VLAs as an extension.
The problem is not len. The problem is that you are trying to take the address of the array, rather than the address of the first element of the array; the types simply don't match.
Instead:
unsigned char* buf = &tmp[0];
Also, the array name conveniently (FSVO "conveniently") decays to &tmp[0] anyway, so you could write simply:
unsigned char* buf = tmp;
In addition you are presently not using a constant value for the array's dimension — ensure that len is made const and initialised with a constant value. In C++11, this'd better be constexpr to really ensure that you're not accidentally attempting to use GCC VLAs.
When I try the following, I get an error:
unsigned char * data = "00000000"; //error: cannot convert const char to unsigned char
Is there a special way to do this which I'm missing?
Update
For the sake of brevity, I'll explain what I'm trying to achieve:
I'd like to create a StringBuffer in C++ which uses unsigned values for raw binary data. It seems that an unsigned char is the best way to accomplish this. If there is a better method?
std::vector<unsigned char> data(8, '0');
Or, if the data is not uniform:
auto & arr = "abcdefg";
std::vector<unsigned char> data(arr, arr + sizeof(arr) - 1);
Or, so you can assign directly from a literal:
std::basic_string<unsigned char> data = (const unsigned char *)"abcdefg";
Yes, do this:
const char *data = "00000000";
A string literal is an array of char, not unsigned char.
If you need to pass this to a function that takes const unsigned char *, well, you'll need to cast it:
foo(static_cast<const unsigned char *>(data));
You have many ways. One is to write:
const unsigned char *data = (const unsigned char *)"00000000";
Another, which is more recommended is to declare data as it should be:
const char *data = "00000000";
And when you pass it to your function:
myFunc((const unsigned char *)data);
Note that, in general a string of unsigned char is unusual. An array of unsigned chars is more common, but you wouldn't initialize it with a string ("00000000")
Response to your update
If you want raw binary data, first let me tell you that instead of unsigned char, you are better off using bigger containers, such as long int or long long. This is because when you perform operations on the binary literal (which is an array), your operations are cut by 4 or 8, which is a speed boost.
Second, if you want your class to represent binary values, don't initialize it with a string, but with individual values. In your case would be:
unsigned char data[] = {0x30, 0x30, 0x30, 0x30, /* etc */}
Note that I assume you are storing binary as binary! That is, you get 8 bits in an unsigned char. If you, on the other hand, mean binary as in string of 0s and 1s, which is not really a good idea, but either way, you don't really need unsigned char and just char is sufficient.
unsigned char data[] = "00000000";
This will copy "00000000" into an unsigned char[] buffer, which also means that the buffer won't be read-only like a string literal.
The reason why the way you're doing it won't work is because your pointing data to a (signed) string literal (char[]), so data has to be of type char*. You can't do that without explicitly casting "00000000", such as: (unsigned char*)"00000000".
Note that string literals aren't explicitly of type constchar[], however if you don't treat them as such and try and modify them, you will cause undefined behaviour - a lot of the times being an access violation error.
You're trying to assign string value to pointer to unsigned char. You cannot do that. If you have pointer, you can assign only memory address or NULL to that.
Use const char instead.
Your target variable is a pointer to an unsigned char. "00000000" is a string literal. It's type is const char[9]. You have two type mismatches here. One is that unsigned char and char are different types. The lack of a const qualifier is also a big problem.
You can do this:
unsigned char * data = (unsigned char *)"00000000";
But this is something you should not do. Ever. Casting away the constness of a string literal will get you in big trouble some day.
The following is a little better, but strictly speaking it is still unspecified behavior (maybe undefined behavior; I don't want to chase down which it is in the standard):
const unsigned char * data = (const unsigned char *)"00000000";
Here you are preserving the constness but you are changing the pointer type from char* to unsigned char*.
#Holland -
unsigned char * data = "00000000";
One very important point I'm not sure we're making clear: the string "00000000\0" (9 bytes, including delimiter) might be in READ-ONLY MEMORY (depending on your platform).
In other words, if you defined your variable ("data") this way, and you passed it to a function that might try to CHANGE "data" ... then you could get an ACCESS VIOLATION.
The solution is:
1) declare as "const char *" (as the others have already said)
... and ...
2) TREAT it as "const char *" (do NOT modify its contents, or pass it to a function that might modify its contents).
I'm trying to use a Union in a Windows Forms application in C++. My code goes like this:
union mytypes1_t {
unsigned long mylong;
char mychar;
} mytypes1;
After the includes at the top of my Form1.h file, and:
for (int num = 0;num<3;num++) {
mytypes1.mychar[0]='a';
}
When a button is clicked.
I get the error ... "subscript requires array or pointer type"
Where am I going wrong?
Your mychar is not an array or pointer you could instead declare it like so:
union mytypes1_t {
unsigned long mylong;
char mychar[4];
} mytypes1;
char mychar; is not an array nor pointer type.
for (int num = 0;num<3;num++) { mytypes1.mychar[0]='a'; }
^^^
and the loop makes no sense.
Well, like the error says, you can only use subscript [] with an array or a pointer type.
mytypes1.mychar is of type char - That is not an array, nor is it a pointer.
An array would be something like this: char mychar[12];
A pointer would be something like this: char* mychar; - but if you use the pointer, be sure to make it point to something first (such as a heap-allocated array).
A char is a single character. When we do char* or char[] it allows us to store multiple chars on the the computer. This also means, you cannot access non-pointer chars like an array as you attempted to do (since arrays are essentially convient form of pointers when it comes to storing stuff).
You can change your code to the following:
union mytypes1_t {
unsigned long mylong;
char *mychar;
} mytypes1;
I have followed the code example here
toupper c++ example
And implemented it in my own code as follows
void CharString::MakeUpper()
{
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
char* c;
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
}
But this gives me the following compiler error
CharString.cpp: In member function 'void CharString::MakeUpper()':
CharString.cpp:276: error: invalid conversion from 'char*' to 'int'
CharString.cpp:276: error: initializing argument 1of 'int toupper(int)'
CharString.cpp: In member function 'void CharString::MakeLower()':
This is line 276
putchar (toupper(c));
I understand that toupper is looking for int as a parameter and returns an int also, is that the problem? If so how does the example work?
Also,
char* str[strlen(m_pString)];
int i=0;
str[strlen(m_pString)]=m_pString;
is not valid C++ - arrays must be dimensioned using compile time constants - this is a C99 feature. And I really don't think the code would do what you want it to, even if it were legal, as you seem to be accessing one past the end of the array. It would be handy if you posted the complete class definition.
I don't think your code does what you want it to do and in fact if it compiled it would explode.
char* str[strlen(m_pString)]; // you've made an array of X C strings where
// X is the length of your original string.
int i=0;
str[strlen(m_pString)]=m_pString; // You've attempted to assign the C string in your array
// at location X to point at you m_pString. X is the
// same X as before and so is 1 past the end of the array
// This is a buffer overrun.
I think what you actually wanted to do was to copy the content of m_pString into str. You'd do that like so:
char * str = new char[strlen(m_pString)];
memcpy(str, m_pString); // I may have the operands reversed, see the docs.
The easier way to do this though is to stop using C strings and to use C++ strings:
std::string str = m_pString;
There are more issues, but this should get you steer you more toward the right direction.
You need to feed toupper() an int (or a char) instead of a char *, which is how you've declared c.
try:
char c;
Also,
char* str[strlen(m_pString)];
is an an array of pointers to characters, not just a single string.
This line:
str[strlen(m_pString)]=m_pString;
is an assignment to a bad pointer then, since there was no allocation.
I'm going to go with the assumption that m_pString is a C style string (char *). You're doing way more fiddling than you need to be doing.
void CharString::MakeUpper()
{
char* str = m_pString; // Since you're not modifying the string, there's no need to make a local copy, just get a pointer to the existing string.
while (*str) // You can use the string pointer as an iterator over the individual chars
{
putchar (toupper(*str)); // Dereference the pointer to get each char.
str++; // Move to the next char (you can merge this into the previous line if so desired, but there's no need.
}
}
In the example you cite, the reason it works is because of how the variables are declared.
int main ()
{
int i=0;
char str[]="Test String.\n"; // This is a compile time string literal, so it's ok to initialize the array with it. Also, it's an array of `char`s not `char*`s.
char c; // Note that this is also a `char`, not a `char *`
while (str[i])
{
c=str[i];
putchar (toupper(c));
i++;
}
return 0;
}
Because of the error-prone ways of using C strings, your best bet is std::string:
void CharString::MakeUpper()
{
string str(m_pString);
transform(str.begin(), str.end(), ostream_iterator<char>(cout), &toupper);
}
There is not a built-in conversion from char * to int, which is why the error occurs. Since you're trying to capitalize a character, you need to dereference the pointer.
putchar(toupper(*c));