When I try a test program with just these two lines
char array[256];
char** arrayPointer=&array;
I get the error
cannot convert from char*[256] to char**.
Yet if I do this:
char array[256];
char* temp=array;
char** arrayPointer=&temp;
I get no such complaint.
I figured that it was eclipse acting buggy (which my eclipase is acting funny right now) but when I tried to do a cast of the &array to char** for the function I ended up with unusual behavior and my debugger implying that the array isn't being modified as it should.
PS. all of this was written by hand, forgive typos.
In C++, arrays and pointers are not the same thing. Arrays in many cases can implicitly be converted to a pointer, but array types and pointer types are different.
In your case, the variable
char array[256];
has type char[256]. If you take its address by writing &array, you get a pointer to an array of 256 chars, which has type char (*)[256]. This is not the same a char**. This is actually a good thing. If you could do the conversion, what would happen if you did this?
char array[256];
char** ptrPtr = &array; // Not legal!
*ptrPtr = new char[256];
In this case, the third line would "reassign" array to point to a new array of 256 elements. However, array is not a pointer! This operation is meaningless.
The reason you got a weird debugger error when writing
char array[256];
char** ptrPtr = (char**) &array; // Legal, but Bad Times!
*ptrPtr = new char[256];
is that the cast you've put in results in undefined behavior. You're pretending that a pointer to an array of 256 actual char objects is really a pointer to a pointer to a char. This is a meaningless cast, so all bets are off when you do it.
On the other hand, if you explicitly introduce a char* variable like this:
char array[256];
char* ptr = array;
char** ptrPtr = &ptr;
Then everything is fine. In the second line, you create a pointer (actual type char*) that points to the first element of array. In the third line, you create a pointer to that new pointer. If you then write
*ptrPtr = new char[137];
Then nothing bad happens; you've just changed where ptr was pointing, and didn't destroy array.
Hope this helps!
Related
char* pointer = new char [5];
strcpy_s(pointer,4, "foo");
I am not fully understanding how pointers work. In my understanding the variable pointer is supposed to store the starting address of the new allocated string of chars. If so why is it important that the pointer is a char since its only storing an address.
why can't i just type
void* pointer = new char [5]
Thanks.
the pointer needs to know the size of its element, thanks to it you can use [] operator to reach a certain element of the array, how else would it know how much memory it has to move to get to the n-th element? If you could declare a pointer to any type as void, then it would have to automatically deduce the type it points to. Consider this piece of code:
char* pointer = new char[5];
pointer[3] = 'a';
for void* this would not be possible. I suppose that the strcpy_s function expects the first parameter as char*, not void* and that is the reason why your code doesn't compile. Pointer itself just allows you to know where some variable/array or even function is in memory, but when you specify pointer's type it gives it more flexibility.
I have one function which have argument as char** I need to pass an array value in the same argument how could I pass that?
int fun(char** val)
{
std::cout<<"val:"<<*val<<"\n";
}
int main()
{
char ch[20];
strlcpy(ch, "test", sizeof(ch));
fun(&ch[0]) // here how can I pass the char array getting build issue
}
I think it is best to figure out, what the intent of the function fun is on the basis of the signature, i.e. the type of the parameter:
fun takes a pointer to a pointer to a single character or to the beginning of a bunch of characters. In the first place this means fun wants to have a "reference" to a pointer. This usually means func wants to modify this pointer and pass this modification back to the caller. It seams val is in fact an out parameter containing a pointer. If this is you actual intend, go with this function signature! In this case you would call fun this way:
char *c = NULL;
fun(&c);
// c is set by fun to a certain value
If you simply want to print out the characters it is way easier and much more obvious for a reader of your code to change the signature of fun to
int fun(char *val) { /* ... */ }
This says fun takes a pointer to a single character or a bunch of characters. It will get this pointer by value, any modification to the pointer itself won't be visibly outside of fun. In this case you'll call fun by
char c[] = "Hello World!";
fun(c);
Now, why did you get a build issue: The type of &ch[0] is char *, i.e. a pointer to some characters. But your fun expected char **, i.e. a pointer to a pointer to some characters. That's clearly an issue. And it contradicts the intend expressed by the function signature too: fun wants to have a "reference" to a pointer in order to modify this referenced pointer.
Edit: So, it sounds like you're stuck with a weird API and need to pass an character array into a function expecting a char ** parameter. In this case the other answers provide the correct, albeit still questionable solution:
char c[] = "Hello World";
char *ptr = &c[0];
fun(&ptr);
The ptr points to the first character of c. The variable ptr has itself an address, namely &ptr, which has type char **. So &ptr is the needed "reference" to a pointer to a bunch of characters you can pass to fun.
But be aware of the fact, that fun is free to change the value of ptr, i.e. the address ptr itself points to. It might be possible that, returning from the call to fun, the value of ptr is something completely different, pointing to an address you didn't expect. Heck, it might be even possible that you're expected to call free(ptr) at the end even though you started with an address in ptr to some static memory you shall never call free() to. To know these details you have to read the detailed specifications of the function fun.
ch is a char[] array. &ch[0] is dereferencing the array to access the 1st element, yielding a char, and then is taking the address of that char, yielding a char*. But the function wants a char** instead. So save that char* to a variable and pass the address of that variable to the function, eg:
int main()
{
char ch[20];
strlcpy(ch, "test", sizeof(ch));
char *ptr = ch; // same as: ptr = &ch[0]
fun(&ptr);
}
Recently, I need to declare a string array, so I wrote down the following statement:
const char** directories = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
However, g++ showed me the error:
error: scalar object ‘directories’ requires one element in initializer
So I changed the statement to this:
const char* directories[] = {"cricket_batting", "cricket_bowling", "croquet", "tennis_forehand", "tennis_serve", "volleyball_smash"};
This time, it was right. But I can't exactly know the difference between char** and char[].
= {...};
Initialisation of this form is known as list-initialization.
const char**
This type is a "pointer to pointer to const char".
const char*[]
This type is an "array of pointer to const char".
Simply put, you cannot initialise a pointer with list-initialization. You can initialise an array with list-initialization; it initializes each of the elements in the array with the items in the braced list.
The reason comes down to what exactly you get from a declaration. When you declare a const char**, all you get is a single pointer object. It's a const char**, which is a pointer promising to point at a pointer to const char. Nonetheless, all you actually have is the outer pointer. You can't then initialise this as though it's an array, since you only have one pointer. Where exactly are you going to store the elements of the initialization list? There is no array of pointers in which you can store them.
However, when you declare a const char*[], what you get is an array of pointers. The size of the array is determined by the size of the list because you have omitted it.
The former is a pointer to a pointer to const char while the latter is an array to pointer to const char. The latter is the correct way to initialize an array of strings.
You would need to allocate memory using new to set up char** , for you can't simply initialize pointers with { }.
When you write int a[] we are making an array of integers. Similarly when you write const char* directories[] you are creating an array of char* pointers. Now each char* can point to a char or a string as in your case. This creates individual string constants and assigns the base address of each to the corresponding pointer in the array
char **directories is pointer to a pointer and you can't assign value to a pointer using { .. }
I have the following source:
#include <iostream>
using namespace std;
void main(int j)
{
char arr[10][10];
char** ptr;
ptr = arr;
}
when I compile it using VS2010 I get this error:
error : a value of type "char (*)[10]" cannot be assigned to an entity of type "char **"
I thought arrays in c++ were just pointers. So a char[][] could also be char**. What am I doing wrong?
Arrays aren't pointers.
An array decays to a pointer in most circumstances, but this isn't recursive. So a T[] decays to a T *, but a T[][] doesn't decay to a T**.
I suggest reading the whole of the C FAQ chapter on arrays and pointers; in particular, the section on 2D arrays and pointers-to-pointers.
The existing answers, though correct, don't make it very clear that there is a fundamental reason (apart from the language rules) why you cannot cast char [10][10] to char **. Even if you force the cast by saying something like
char arr[2][2];
char ** ptr = (char **)arr;
it won't actually work.
The reason is that in C and C++ a two-dimensional array is laid out in memory as an array of arrays. That is, in C a two-dimensional array is laid out in memory as a single allocation,
arr -> arr[0][0]
arr[0][1]
arr[1][0]
arr[1][1]
You'll notice that arr doesn't point to a char * but to arr[0][0] which is a char; therefore, while arr can be cast to a char *, it cannot be cast to a char **.
The correct forced cast would be
char arr[2][2];
char * ptr = (char *)arr;
If you don't want to force the cast (always a good idea if possible!) you would say
char arr[2][2];
char * ptr = arr[0];
or, to make the outcome clearer,
char arr[2][2];
char * ptr = &arr[0][0];
And you now have (in effect) a pointer to an array of 4 characters. [Proviso: I can't find anything in the C standard that prohibits an implementation from adding padding between two rows of an array, but I don't believe that any real-world implementations do so, and common coding practice depends on the assumption that there will be no such padding.]
If you really needed to convert arr to a char ** you would have to explicitly create an array of pointers:
char arr[2][2]
char * arr_ptrs[2];
char ** ptr;
arr_ptrs[0] = arr[0];
arr_ptrs[1] = arr[1];
ptr = arr_ptrs;
The C language could in principle do this for you automatically if you tried to cast a two-dimensional array to a pointer-to-pointer but that would violate the programmer's expectation that a cast does not have side-effects such as allocating memory.
In Java, by way of comparison, a two-dimensional array is always an array of pointers to arrays, so that the array
char arr[][] = { {'a', 'b'}, {'c', 'd'} };
is laid out in memory as three separate allocations, in arbitrary order and not necessarily adjacent,
arr -> arr[0]
arr[1]
arr[0] -> arr[0][0]
arr[0][1]
arr[1] -> arr[1][0]
arr[1][1]
You will immediately notice that this requires more memory than the equivalent C array, and is slower to evaluate at runtime. On the other hand, it does allow the rows of an array to have different lengths.
The types char[10][10] and char** and char (*)[10] are all different types. However, the first one cannot convert into the second one, it can convert into the third one.
So try this:
char arr[10][10];
char (*ptr)[10];
ptr = arr; //ok
It will work, because as I said object of type char[10][10] can convert into an object of type char (*)[10]. They're compatible types.
I thought arrays in c++ were just pointers.
No, an array is a set of objects laid out contiguously in memory. In some circumstances, they are convertible to a pointer to the first element.
So a char[][] could also be char**
No. It is convertible to a pointer to the first one-dimensional array (which is the type char (*)[10] mentioned in the error message); but that array is not a pointer, so it is not convertible to a pointer-to-pointer.
The error exactly tells you whats wrong a double dimensional array can be assigned to an pointer to array not an double pointer. So what you need is:
char (*ptr)[10] = arr;
What am I doing wrong?
First things first
Arrays are not pointers!! but they act sometimes like pointers.
The rule is:
An expression with array type (which could be an array name) converts to a pointer anytime an array type is not legal, but a pointer type is.
So if you have a single dimensional array:
char arr[10];
Then arr decays to address of the zeroth element it has the type char *.
Hence:
char *ptr = arr;
But if you have an 2 dimensional array which is essentially an array of arrays.
char arr[10][10];
Then arr decays to the pointer to an array of 10 characters.
So, In order to assign arr to something, you will need that something to match the type, which is pointer to an array of characters.
Hence:
char (*ptr)[10] = arr;
Arrays are NOT just pointers -- arrays are arrays. Arrays are not first-class types, however, so you can't use them in many places. The thing that causes your confusion is that array names CAN be implicitly converted into pointers to the array's first element, which means that you can use an array in many places where you need a pointer and it 'just works'. This, however, is not one of those places.
Arrays are not pointers (I notice a lot of books tend to make you think this, though). They are something completely different. A pointer is a memory address while an array is a contiguous set of some data.
In some cases, an array can decay to a pointer to its first element. You can then use pointer arithmetic to iterate through the contiguous memory. An example of this case would be when passing an array to a function as a parameter.
What you probably want to do here is something like:
char arr[10];
char * i = &arr[0];
Obviously you'll need to use 2D arrays and char** in your case. I'll leave that to you to figure out :)
When you cast ar[10][10] to pointer you will get a array of pointer as said above *ar[10] and not **ar.
I'm studying linux C++ programing when I see
int execve(const char *path,
char *const argv[],
char *const envp[]);
I don't understand what is char *const argv[] . I know char *const foo is a const pointer to char. And const char *foo is a pointer to a const char. But what's char *const argv[]?
Is it an array of const pointers to char or an array of pointers to const char?
And I have a vector<string> now, how to convert it to char *const argv[]?
Is it an array of const pointers to char or an array of pointers to const char?
Read types right to left:
const always binds to the left (unless it is on the very left)
char *const argv[]
^^ Array of
^^^^^ const
^ pointer to
^^^^ char
An array of "const pointer" to char
So the pointers in the array can not be modified.
But what they point at can be modified.
Note: As pointed out by Steve below. Because this is being used as a parameter. It actually decays to a "A pointer to "const pointer" to char" or "char* const *".
And I have a vector<string> now, how to convert it to char *const argv[]?
int execve(const char *path,
char *const argv[],
char *const envp[]);
int main()
{
std::vector<std::string> data; /// fill
std::vector<char*> argv;
std::vector<char*> envp;
for(std::vector<std::string>::iterator loop = data.begin(); loop != data.end(); ++loop)
{
argv.push_back(&(*loop)[0]);
}
// I also bet that argv and envp need to be NULL terminated
argv.push_back(NULL);
envp.push_back(NULL);
execve("MyAppName", &argv[0], &envp[0]);
}
cdecl.org says:
char *const argv[]
declare argv as array of const pointer to char
// says: argv is a constant pointer pointing to a char*
int main(int c, char *const argv[]);
You won't be able to change "argv" within the function.
As you are just learning C, i recommend you to really try to understand the differences between arrays and pointers first instead of the common things.
In the area of parameters and arrays, there are a few confusing rules that should be clear before going on. First, what you declare in a parameter list is treated special. There are such situations where things don't make sense as a function parameter in C. These are
Functions as parameters
Arrays as parameters
Arrays as parameters
The second maybe is not immediately clear. But it becomes clear when you consider that the size of an array dimension is part of the type in C (and an array whose dimension size isn't given has an incomplete type). So, if you would create a function that takes an array by-value (receives a copy), then it could do so only for one size! In addition, arrays can become large, and C tries to be as fast as possible.
In C, for these reasons, array-values are not existent. If you want to get the value of an array, what you get instead is a pointer to the first element of that array. And herein actually already lies the solution. Instead of drawing an array parameter invalid up-front, a C compiler will transform the type of the respective parameter to be a pointer. Remember this, it's very important. The parameter won't be an array, but instead it will be a pointer to the respective element type.
Now, if you try to pass an array, what is passed instead is a pointer to the arrays' first element.
Excursion: Functions as parameters
For completion, and because i think this will help you better understand the matter, let's look what the state of affairs is when you try to have a function as a parameter. Indeed, first it won't make any sense. How can a parameter be a function? Huh, we want a variable at that place, of course! So what the compiler does when that happens is, again, to transform the function into a function pointer. Trying to pass a function will pass a pointer to that respective function instead. So, the following are the same (analogous to the array example):
void f(void g(void));
void f(void (*g)(void));
Note that parentheses around *g is needed. Otherwise, it would specify a function returning void*, instead of a pointer to a function returning void.
Back to arrays
Now, i said at the beginning that arrays can have an incomplete type - which happens if you don't give a size yet. Since we already figured that an array parameter is not existent but instead any array parameter is a pointer, the array's size doesn't matter. That means, the compiler will translate all of the following, and all are the same thing:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
Of course, it doesn't make much sense to be able to put any size in it, and it's just thrown away. For that reason, C99 came up with a new meaning for those numbers, and allows other things to appear between the brackets:
// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory.
int main(int c, char *argv[static 5]);
// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);
// says the same as the previous one
int main(int c, char ** const argv);
The last two lines say that you won't be able to change "argv" within the function - it has become a const pointer. Only few C compilers support those C99 features though. But these features make it clear that the "array" isn't actually one. It's a pointer.
A word of Warning
Note that all i said above is true only when you have got an array as a parameter of a function. If you work with local arrays, an array won't be a pointer. It will behave as a pointer, because as explained earlier an array will be converted to a pointer when its value is read. But it should not be confused with pointers.
One classic example is the following:
char c[10];
char **c = &c; // does not work.
typedef char array[10];
array *pc = &c; // *does* work.
// same without typedef. Parens needed, because [...] has
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;