Can I safely cast a &char[] to char**? - c

Having the following code:
char data[2048];
And a function declared like this:
int f(char** data);
Can I safely call it like this:
f((char**)&data);
If I just use &data, the compiler issue the following warning:
warning C4047: 'function' : 'char **' differs in levels of indirection from 'char (*)[2048]'

No, you cannot.
data is an array. &data is a pointer to an array. It is not a pointer to a pointer. Despite the fact that data decays to a pointer in multiple contexts, it is not itself a pointer - taking the address gives you the address of the array.
If you want a pointer to a pointer to the array, you might try something like this:
char *pdata = data; // data decays to a pointer here
// (a pointer to the first element of the array)
f(&pdata); // Now &pdata is of type char ** (pointer to a pointer).
though, of course, what you actually need will depend on what your usecase is.

A pointer-to-pointer is not an array, nor is it a pointer to an array, nor should it be used to point at an array. Except for the special case where it can be used to point at the first item of an array of pointers, which is not the case here.
A function int f(char** data); cannot accept a char data[2048]; array as parameter. Either the array type needs to be changed, or the function needs to be rewritten.
Correct function alternatives would be:
int f (char* data);
int f (char data[2048]); // completely equivalent to char* data
int f (char (*data)[2048]); // array pointer, would require to pass the address of the array

As stated in this more detailed example:
While an array name may decay into a pointer, the address of the array does not decay into a pointer to a pointer. And why should it? What sense does it make to treat an array so?
Pointers to pointers are sometimes passed to modify the pointers (simple pointer arguments don't work here because C passes by value, which would only allow to modify what's pointed, not the pointer itself). Here's some imaginary code (won't compile):
void test(int** p)
{
*p = malloc ... /* retarget '*p' */
}
int main()
{
int arr[] = {30, 450, 14, 5};
int* ptr;
/* Fine!
** test will retarget ptr, and its new value
** will appear after this call.
*/
test(&ptr);
/* Makes no sense!
** You cannot retarget 'arr', since it's a
** constant label created by the compiler.
*/
test(&arr);
return 0;
}

You can do something like that.
char data[2048];
char *a=&data[0];
char **b=&a;
f(b);

Related

C pointer to pointer warning

I get a warning when i point to a pointer. I am not sure why; the types are the same.
char delay_buffer1[40];
char delay_buffer2[40];
char** delay_buffer_front;
delay_buffer_front = &delay_buffer1;
the objective is to swap buffers:
void swap_string_buffer(void** pointer, void* buffer1, void* buffer2) {
printf("pointer: %u. buffer1: %u. buffer2 %u\n", pointer, buffer1, buffer2);
if(*pointer == buffer1) *pointer = buffer2;
else *pointer = buffer1;
}
example code:
copy_content_to(delay_buffer_front);
swap_string_buffer((void**) delay_buffer_front, (void*) delay_buffer1,(void*)delay_buffer2);
fprintf(file, "%s", delay_buffer_front);
warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
delay_buffer_front = &delay_buffer1;
the types are the same.
No, they aren't. You're probably confused (this is quite common) by the fact, that the identifier of an array evaluates to a pointer to its first element in nearly all contexts (exceptions are e.g. with the operators & and sizeof).
But that doesn't change the fact that an array is an array and a pointer is a pointer.
This is a pointer to a pointer:
char **delay_buffer_front;
What you probably wanted was a pointer to an array:
char (*delay_buffer_front)[40];
Or you might simply have wanted a plain pointer pointing to the first element of the array:
char *delay_buffer_front;
With that declaration, you can just assign the array's identifier because as explained above, it evaluates to such a pointer:
char *delay_buffer_front = delay_buffer1;
It means exactly that, the two pointers are incompatible. It's more an error than a warning.
You probably want this:
char* delay_buffer_front;
delay_buffer_front = delay_buffer1;
instead of:
char** delay_buffer_front;
delay_buffer_front = &delay_buffer1;
As all you want is to swap the buffers you dont have to create a pointer to a pointer. Simply create an intermediate pointer of similar type and use it for swapping.
char* delay_buffer_front; //Intermediate pointer to store the address of first buffer
delay_buffer_front = delay_buffer1; //Store the address of the first buffer in the
//intermediate pointer.

return of malloc() function

malloc() function is said to return a null pointer or a pointer to the allocated space. Suppose for a string we make the statement:
char* ptr = malloc(size)
Isn't ptr a pointer that would point to a pointer?
Isn't :
char** ptr = malloc(size)
supposed to be the correct way to declare the pointer to char?
The compiler however doesn't give a warning when we do either, the warning it does give is for the format specifier if used.
How should we declare this and why? Also, how would char** be used?
No, 'ptr' would contain the pointer returned by 'malloc'. You are assigning the returned pointer, not taking its address.
The char * denotes a char pointer. Malloc will return a void * pointer (that will be automatically converted to whatever pointer you're trying to assign).
The char ** denotes a char * pointer. This is a pointer to a pointer.
If you think of a pointer as a map you have that char * is a map to a char, void * is a map to something mysterious and char ** is a map to another map that leads to a char. So
char* ptr = malloc(size);
Is the correct one, because you want a map to something, not a map to a map.
*ptr is a pointer to a char, which is often used to manage an array
or a string.
**ptr is a pointer to a pointer to a char, which is often used to
manage a matrix (array of arrays) or a string array.

Pointer to array has the same value as array

The code below creates an array and a pointer that points to it. Then the program prints out the content of the two variables. The curious thing is that the memory addresses printed out are the same, even though they shouldn't. ptr should contain the address of array, not array itself. Can anybody explain this please?
#include <stdio.h>
int main() {
char array[] = "abcdefg";
char (*ptr)[] = &array;
printf("%p\n", array);
printf("%p\n", ptr);
}
For any array named array, array and &array has the same value - the address of the first element of the array. Just their types are different - array here has type char *, where are &array has type char(*)[].
For an example consider the array as char a[10];
when we are assigning to the pointer variable we assign as char *ptr=a
we can also assign like ptr=&a[0]; so the both statements are same the two will refer the starting address of the array
According to Pointers to arrays in C by Eli Bendersky:
Consider this code:
void test(int** p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
return 0;
}
gcc isn't very happy about it, and issues a warning: passing arg 1
of test from incompatible pointer type. C++ has stricter type
checking, so let's try running the same code through g++. As
expected, we get an error: cannot convert int (*)[4] to int** for
argument 1 to void test(int**).
So what's the problem here? What's wrong with the code above? Well,
everything. It's simply invalid, and it makes no sense. Some would
think it should work because this works:
void test(int* p)
{
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(arr);
return 0;
}
But this one works specifically because the C compilers should follow
the C standard, which mandates that arrays "decay" into pointers when
used as lvalues. Thus, a pointer to the array's first element is
actually passed to test and everything works.
However, the first code snippet is different. While an array name may
decay into a pointer, the address of the array does not decay into a
pointer to a pointer. And why should it? What sense does it make to
treat an array so?
Pointers to pointers are sometimes passed to modify the pointers
(simple pointer arguments don't work here because C passes by value,
which would only allow to modify what's pointed, not the pointer
itself). Here's some imaginary code (won't compile):
void test(int** p)
{
*p = malloc ... /* retarget '*p' */
}
int main()
{
int arr[] = {30, 450, 14, 5};
int* ptr;
/* Fine!
** test will retarget ptr, and its new value
** will appear after this call.
*/
test(&ptr);
/* Makes no sense!
** You cannot retarget 'arr', since it's a
** constant label created by the compiler.
*/
test(&arr);
return 0;
}
Pointers to arrays
Note that the original code could be modified a little to make it
work:
void test(int (*p)[4])
{
(*p)[2] = 10;
}
int main()
{
int arr[] = {30, 450, 14, 5};
test(&arr);
printf("%d\n", arr[2]);
return 0;
}
What is that weird type test accepts now? Say hello to a "pointer to
array", one of the useless features of C. This is what the C FAQ has
to say about it:
2.12: How do I declare a pointer to an array?
Usually, you don't want to. When people speak casually of a pointer to
an array, they usually mean a pointer to its first element.
While the test function from the previous snippet compiles and works,
it isn't of much use, since it's much clearer to write:
void test(int* p)
{
p[2] = 10;
}
...
...
/* then call */
test(arr);
The main use of pointers as function arguments is to either avoid
passing whole structures by value, or to modify the object pointed by
the pointers. Both are irrelevant needs for pointers to array. Here's
a clarifying snippet:
int joe[] = {1, 2, 3, 4};
void test(int (*p)[4])
{
/* Fine: assign to an element through the
** pointer.
*/
(*p)[2] = 10;
/* Works, but won't be reflected in the
** caller since p was passed by value.
*/
p = &joe;
/* Error: arrays can't be assigned.
*/
*p = joe;
}
Arrays are not passed by value anyway, so a pointer to an array is
useless for this purpose. Neither can arrays be modified, so that
kills the second reason.
To answer the question, the reason for &array to be equal to array is because array is a "constant label created by the compiler," not a pointer variable. So it actually makes no sense to "dereference" array and the compiler happens to simply return the value of array itself whenever this happens.
array doesn't have an address, in the way that, say, ptr has an address. Because an array always points to the same memory location, there's no need for that memory location to be stored in some other memory location. There's no way to take array and get a temporary char** such that (*char)[0] == 'a'.
So &array has type char(*)[], and returns the location of the first char in the array. Likewise, array, when used in a pointer context (that is to say, pretty much everywhere, with a couple of exceptions), has the same effect as &array but with different type. This is known as "array decay".
More information at What is array decaying?.

difference between &array[0] and &array when passed to a C function

Is there a difference between &array[0] and &array when passed to a C Function. This array is a void* array which currently takes integer as data.
Added the test code
#include <iostream>
#include <conio.h>
using namespace std;
int read_buffer[10] = {0,0,0,0,0,0,0,0,0,0};
int write_buffer[10] = {0,1,2,3,4,5,6,7,8,9};
void WriteBlock(void* SrcPtr)
{
//WriteBlock will use SrcPtr and store the data to a common memory block which ReadBlock will access.
}
void ReadBlock(void* DstPtr)
{
//ReadBlock function will fetch data from readBuffer and put the data back into the *DstPtr.
}
void main()
{
WriteBlock((int*)&write_buffer);
//Is there a difference between these two below calls.
ReadBlock(&read_buffer[0]);
ReadBlock(&read_buffer);
}
Yes, there's a big difference, and it depends on context.
Consider this:-
char arrayA[10];
char *arrayB;
&arrayA[0] and &arrayB[0] both have type char *.
But &arrayA has type char (*)[10] while &arrayB has type char ** - the address of the pointer.
For arrayA, these point to the same address - but for arrayB, they do not! There's a common C misconception that "pointers and arrays are the same". This is a great example of where they are absoluelty not,
See this : http://ideone.com/OcbuXZ
Assuming array is declared
void *array[N];
then the expressions &array[0] and &array will yield the same value (the address of the first element of the array is the same as the address of the array itself), but will have different types.
Expression Type
---------- ----
&array void *(*)[10] -- pointer to 10-element array of `void *`
&array[0] void ** -- pointer to pointer to void
Your function prototype will need to match up with whichever expression you pass. If you call the function as
func(&array);
then the function prototype needs to be
void func(void *(*arrp)[10]) {...}
If you call the function as
func(&array[0]);
then the function prototype needs to be
void func(void **arrp) {...}
although in that case you should pass the size of the array as a separate parameter.
Now, assuming array is declared
void **array = malloc(sizeof *array * N);
then the expressions &array and &array[0] will yield different values and different types.
Expression Type
---------- ----
&array void ***
&array[0] void **
&array will give you the address of the array variable itself, which is different from the address of the heap memory that's been allocated for the array. Again, your function prototype will need to match up with the type of the expression you use.
If array is really an array, then
&array[0] is the pointer to element 0 of array[]
&array is the pointer to the entire array[]
So, these two expressions are of different types. And that's the main difference that may cause your code to fail to compile if you pass the wrong one of the two.
At the low level, however, the two pointers are going to hold the same address.
Yes there is a big different
&array[0]==>void**
AND
&array==>void***
This won't compile, you are using a void * and try to get the first element of it. But what size does it have? The compiler doesn't know. Using int * may compile, if you are not trying something like this:
int main (void) {
int *arr = malloc( 10 );
arr = &arr[0]; // this is ok
arr = &arr; // wrong data type
}
&array returns an int **, &array[0] returns int *. These are different data types.

When are values implicitly converted to pointers?

I have many functions like:
void write(char* param, int len)
{
//
}
And I notice that I almost never use the & operator for arguments. When I pass an array:
char in[20];
write(in, 20);
I dont need it, but when I pass a single value:
write(5, 1);
I don't seem to need it, and when I pass a pointer:
char* in = malloc(20);
write(in, 20);
I also dont need it. So in which circumstances do I actually need to call:
write(&in, 1);
Because I'm confused :D
Are you sure about your second case? It doesn't compile for me and should be
char in = 5;
write(&in, 1);
When are values implicitly converted to pointers?
In practice, integer types may be converted to pointers implicitly by the compiler. In theory, this is illegal and compilers that accept it will usually issue a warning:
example.c:2:6: warning: incompatible integer to pointer conversion initializing
'void *' with an expression of type 'int'
In your above example:
char in = 5;
write(in, 20);
char is an integer type, so if your compiler allows it, it may be implicitly converted to a pointer type, although it is not part of the C standard and is completely compiler-specific.
Note that converting an integer type to a pointer type using a cast is allowed by the standard, although results are implementation-defined:
char in = 5;
write((char *)in, 20);
The only allowed case of implicit conversion is when integer constant 0, which denotes a null pointer:
write(0, 20); // allowed
Note that the integer constant is itself allowed, but a variable of integer type with the value 0 is not:
char in = 0;
write(in, 20); // not allowed
As for the others, when you pass a pointer, you don't need the &, obviously, because it's already a pointer. When you pass an array, it decays to a pointer so you don't need & there either. In both these cases it would be actually illegal to use it, as your function above expects a char * and be fed with a char ** and a char (*)[20] respectively.
If you copy somehow the prototype of function 'write' to the file where you call this function, as follows.
void write(char *in, int len);
void foo(int bar){
char in=5;
write(in, 1);
}
You will probably get a warning. Because in is not a pointer, though 5 can be an address.
I guess if your program is compiled and linked successfully, it will crash at run-time.
with using;
return_type function_name(prim_data_type* param...)
param is a pointer that pointing an address in the memory and *param is the value in that address.
Answer is about what you want to do with this param.
char in[20];
by saying that "in" is the first element's address. So at the function call:
write(in, 20);
you are sending the first element's address so in the function implementation, you can access the first element by *param, second element with *(param+1) or param[1] etc.
The place that you are confused is here:
char in = 5;
write(in, 1);
Because in is the address 5 (00000005), so in the implementation of the function you are accessing that place whichever value is there. You must be careful with using like this.
In the malloc operation:
char* in = malloc(20);
write(in, 20);
in is a pointer to an address (first element's address) holding up 20 elements of char can be take space. In the function you can access to all elements with param pointer(*param is the first element, *(param+7) or param[7] is the 8. element)
In the conclusion, when you want to play with an primary data typed variable (int, float, char..) in another function, you must use;
write(&in);
By doing that, in the implementation of that write function, you can access that variable, change the value by *param with no confusion.
Note:Some explanations were simplified here for better understanding. Extra warnings would be welcomed here.
Functions and arrays decay into pointers in some contexts. Functions can decay into pointers to functions, and arrays can decay into a pointer to the first element of the array. No other types behave this way.
This example:
char in = 5;
write(in, 1);
Is wrong though. You definitely need the & in that case. Are you sure it worked like that?

Resources