Using Unions in Visual C++ - c++

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;

Related

strange behaviour of assigning char array to single char

// example: class constructor
#include <iostream>
#include <string>
class Test{
public:
char* getColor(){
return color;
}
private:
char color[5] = "Blau";
};
int main () {
Test s;
char *myChar = s.getColor();
std::cout << myChar;
return 0;
};
I don't really understand how this actually returns "Blau" instead of just B or something else.
What I'm doing is assigning the starting pointer if a char array to a single char pointer.
I'd really like to understand why this happens like this. Maybe it's because of std::cout getting all values of that type? So instead of "B" it says "Blau"
There is no difference between a pointer to a single object and a pointer to the first element of an array. It's up to the programmer to know how it should be interpreted; or to use friendlier types like std::string.
When you stream a char* with <<, it assumes that it's the pointer to the first element of a zero-terminated C-style string, and prints all the characters it finds, starting from that one, until it finds one with a zero value.
myChar is not a single char but a pointer to such (and you can always do pointer-arithmetic / indexing instead of straight dereferencing).
And operator<< has an overload for ostream&+char*, to output it as a pointer to a 0-terminated string.
So, not really any surprise.
Array in c++ is the const pointer to first element of data block. Therefore your color variable is the pointer.

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.

Converting from std::vector<> to a double pointer?

I was wondering out of curiosity if it is possible to cast a std::vector<> to a double pointer.
I've never had an issue passing a std::vector as a pointer in this fashion:
std::vector<char> myCharVector;
myCharVector.push_back('a');
myCharVector.push_back('b');
myCharVector.push_back('c');
char *myCharPointer = &myCharVector[0];
So I was curious if it was possible to assign the address of the pointer in a similar way to this:
char *myPointer = "abc";
char **myDoublePointer = &myPointer;
I've tried:
char **myDoublePointer = (char**)&myCharVector;
But it doesn't work. Is there any way of achieving this?
You already know that &myCharVector[0] is a pointer to char. So if you store it in a variable:
char *cstr = &myCharVector[0];
then you can take the address of that variable:
char **ptrToCstr = &cstr;
But simply dereferencing twice like this:
char **ptrToCstr = &(&myCharVector[0])
is invalid because the value (&myCharVector[0]) isn't stored in memory anywhere yet.
In C++11, you can do:
char *myCharPointer = myCharVector.data();
But you cannot take the address of the return value of data() because it does not return a reference to the underlying storage, just the pointer value.
If the purpose is to be able to change what the pointer is pointing to, then you may really want a pointer to a vector, rather than a pointer to a pointer to a char. But, the STL doesn't let you change the underlying pointer within the vector itself without going through the regular vector APIs (like resize or swap).
You most definitely can't do this. std::vector and a char ** are completely different types of objects and you can't just "cast" one to another.
The reason you were able to do char *myCharPointer = &myCharVector[0] is that myCharVector[0] gives you a char, and thus &myCharVector[0] gives you the address of that char, which you can assign to a char *.
The only way you could convert a full std::vector into a char * (not char **) is to loop over your std::vector and construct a char * from the data manually.
For instance something like:
char *ptr = malloc(myCharVector.size()+1);
for (unsigned int i=0; i < myCharVector.size(); i++) {
ptr[i] = myCharVector[i];
}
ptr[myCharVector.size()] = 0;
Then ptr will be a C string of chars.

Assigning a string of characters to a char array

I Want to know why the first statements works and why not second one in c++
char a[10]="iqbal"; // it works
a="iqbal"; // does not work
Strictly speaking, an array is not a pointer! And an array ( base address of the array ) cant be a modifiable lvalue. ie it cannot appear on the left hand side of an assignment operator.Arrays decay into pointers only in certain circumstances. Read this SO post to learn when arrays decay into pointers. Here is one more nice article which explains the differences between arrays and pointers
Also read about lvalues and rvalues here so that you get an idea of things which cannot appear on the LHS of =
char a[10]="iqbal";  // it works
In this case, internally what happens is
a[0] = 'i';
a[1] = 'q';
.
.
a[5] = '\0';
So everything is fine as array[i] is a modifiable lvalue.
a="iqbal"; // does not work
Internally, this is roughly equivalent to
0x60000(Address of a, but is a simple number here ) = Address of "iqbal"
This is wrong as we cannot assign something to a number.
The char array a will be static and can not be changed if you initialize it like this. Anyway you can never assign a character string a="iqbal" in c. You have to use strncpy or memcpy for that. Otherwise you will try to overwrite the pointer to the string, and that is not what you want.
So the correct code would do something like:
char a[10];
strncpy(a, "iqbal", sizeof(a) - 1);
a[sizeof(a) - 1] = 0;
The -1 is to reserve a byte for the terminating zero. Note, you will have to check for yourself if the string is null terminated or not. Bad api. There is a strlcpy() call that does this for you but it is not included in glibc.
The first line is not a statement but a declaration with an initialization.
The second line is an expression statement with the assignment operator.
You cannot assign arrays in C.
But you can initialize an array with the elements of a string literal.
why the first statements works and why not second one in c++
Because they are different statements, almost wholly unrelated. Do not be confused by the fact that they both use the = symbol. In one case, it represents object initialization. In the other case, the assignment operator.
Your first line is legal because it is legal to initialize aggregates, including character arrays.
Your second line is not legal because it is not legal to assign to an array.
Since this is C++, may I suggest that you avoid naked arrays? For character strings use std::string. For other arrays use std::vector. If you do, you example becomes:
std::string a = "iqbal"; // it works
a="iqbal"; // so does this
When writing
char a[10]="iqbal"
You are initializing the elements of the character array a with the characters. We can do the same with int type (note that the char type gets a slightly different treatment) :
int a[10]={1,2,...};
But writing the following after declaration part would be invalid as a would be treated just like a pointer. So writing something like
a={1,2,...};
or a="iqbal"
won't be making any sense!
try:
char a[10]="iqbal";
char *my_a = a;
and work with my_a.
In C++11 you can use a lambda to do the initialization, like so:
bool test = true;
/*const*/ char a[10] = { //Aggregate initialization
[=] //capture by value
()//no parameters
{ //start lambda
switch (test) {
case true: return *"test=true"; //*"xxx" don't return a pointer, but the 'string' itself
case false: return *"test=false";
} //switch
}()}; //}, close the lambda, (), call it, }; close aggregate initialization
This comes in handy when your environment does not support std::string, like NVidia's CUDA or some strange embedded environment.
The lambda gets to be inlined, so internally it translates to char a[10] = test?"xxx":"yyy";
If you have the option to do so, you obviously want to always use std::string, because fixed sized char buffers are fundamentally a bad idea.
If you use std::string you can convert that to a char array using: chararray = mystring.c_str();. Which is useful if you insist on using printf: printf("s = %s", mystring.c_str());.
You cannot assign a string literal to a char array after the latter's declaration.
A nice, simple & effective alternative is to use std::strcpy to do so, like so:
struct S
{
char name[30];
};
S s;
std::strcpy( s.name,
"The moribunds salute you." );

how do i use fill_n() on the following array?

I have this array
unsigned char bit_table_[10][100];
What is the right way to fill it with 0.
I tried
std::fill_n(bit_table_,sizeof(bit_table_),0x00);
but vc 2010 flags it as error.
On initialization:
unsigned char bit_table_[10][100] = {};
If it's a class member, you can initialize it in the constructor, like this:
MyClass::MyClass()
:bit_table_()
{}
Otherwise:
std::fill_n(*bit_table_,sizeof(bit_table_),0);
The type of bit_table_ is unsigned char [10][100], which will decay (that is, the compiler allows it to be implicitly converted to) into unsigned char (*)[100], that is, a pointer to an array of 100 unsigned chars.
std::fill_n(bit_table_, ...) is then instantiated as:
std::fill_n(unsigned char (*)[100], ...) which means it expects a value of type unsigned char [100] to initialize bit_table_ with. 0 is not convertible to that type, so the compilation fails.
Another way to think about it is that the STL functions that deal with iterators only deal with a single dimension. If you are passing in a multidimensional structure those STL functions will only deal with a single dimension.
Ultimately, you can't do this; there is no way to assign to an array type. I.e., since you can't do this:
char table[100];
char another_table[100]= { };
table= another_table;
you can't use std::fill_n on multidimensional arrays.
You can also try unsigned char bit_table_[10][100]= { 0 } to fill it with zeros.
int main()
{
unsigned char bit_table_[10][100]= { 0 };
return 0;
}