Pointer to array has the same value as array - c

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?.

Related

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

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);

C - In my book, it says arrays always use pass by reference. But the code that accompanies it doesn't make sense to me

int sum(int a[], int n)
{
int i, s = 0;
for (i = 0; i < n; i++)
s = s + a[i];
return s;
}
I've learned that when passing by reference there are "*" next to the int on the functions header and there is also no return statement. But this code above which passes an array has no * and has a return statement. Can someone please tell when i am misunderstanding this.
Your book is misleading. Arrays are not passed by reference; rather, arrays cannot be passed as arguments in function calls, or defined as parameters in function declarations, at all.
All parameters in C are passed by value (though you can simulate the effect of pass-by-reference by passing a pointer value).
There are two special-case rules at play here.
First, a parameter of array type is adjusted at compile time to a pointer to the array's element type. So this:
int sum(int a[], int n)
really means:
int sum(int *a, int n)
Second, an expression of array type, in most contexts, is implicitly converted to a pointer to the array's first element. The exceptions are:
When the array expression is the operand of sizeof (sizeof arr yields the size of the array, not the size of a pointer);
When the array expression is the operand of unary & (&arr yields the address of the entire array, not the address of a pointer); and
When the array is a string literal in an initializer used to initialize an array object (char s[] = "hello"; copies the string; it doesn't decay to a char* pointer).
In addition to that, the array indexing operator [] requires a pointer as one of its operands. arr[i] is, by definition, equivalent to *(arr+i).
Some people, even some book authors, will tell you that arrays and pointers are really the same thing. They are not; they are entirely distinct concepts. It happens that the language rules are set up in such a way that (a) we manipulate pointers to refer to elements of arrays rather than manipulating arrays as a while, and (b) the language syntax (unfortunately) makes it easy to be confused.
Section 6 of the comp.lang.c FAQ does a good job of explaining the relationship between arrays and pointers in C. Read it.
I think the first thing we need here is some clarification on parameter passing; because based on what you're saying, I'm under the impression your book is leading you astray.
parameter passing in general:
"passing by reference" doesn't exist in C. Using the star in the function parameter list is detonating something is a pointer. When you pass a pointer, then value that the pointer is pointing at can be updated.
ie:
void foo(int a){ // a is a local copy, the initial value is set by the calling
a = 5; // function, this assignment to 5 will have no effect outside of this
return; // scope
}
so this makes sense if you think about it called as:
foo(10);
Would it make sense that after this call 10 is now set to the value of 5? No. 10 is still 10.
When you pass a pointer to something, you adjust the value that is being pointed at, not the value of the pointer:
void foo(int *a){ // a is a local copy of the pointer, but it's pointing at whatever
*a = 5; // the original pointer was, so adjustments here effect the original
return; // value
}
such that:
int z = 4;
foo(&z);
printf("%d\n", z); // 5 would now be printed
You also mentioned there would be no return statement. The return statement has nothing to do with what is being passed. If you pass a single pointer and all you're going to do is update the value it's pointing at then you don't need to return a value, but just because you're doing that doesn't mean you can't return a value. Frequently you'll see a function update the values of the parameter list, but it still returns a "0" (for success) or a "-1" (for failure) to let you know the outcome of the operation.
Passing an array
Now that the basics are out of the way, passing an array is a special case. When you write code using an array in the parameter list, as you did here:
int sum(int a[], int n)
The array is implicitly converted to a pointer of the array's type. So in this case it reads int a[] but it's compiled as int *a. When you use the array in the function:
a[i]
The compiler knows this is an int and it will take the address of a add to it i*sizeof(int) and dereference the result to give you the correct value stored in that location.
In this case (but not always), int a[] is equivalent to int *a.
And, you can have a return statement when you pass some argument by reference. The type of the value that you return from the function has nothing to do with the type of the argument a: sum() is a function returning an integer, and s is the integer that you return.
I have come accross books and teachers that say that arrays are always passed by reference, both are wrong. you dont actually pass arrays you pass pointers (the compiler switches [] with * at compile time) and in pointers case they are not pass by reference (as you would expect) what happens is that you can change the value of whatever it is the pointer points to and it will remain changed outside the function. But you cannot change what the pointer points to unless you pass it via reference. i.e
void do_something (int * &ptr);
Edit: Sample code and output for example
#include <iostream>
using namespace std;
int x1 = 10;
int x2 = 20;
int x3 = 30;
int x4 = 40;
int x5 = 50;
void do_something(int * ptr)
{
*ptr = x2;
ptr = &x3;
}
void do_something_again(int * &ptr)
{
*ptr = x4;
ptr = &x5;
}
int main()
{
int * ptr = &x1;
cout << *ptr << endl;
do_something(ptr);
cout << *ptr << endl;
do_something_again(ptr);
cout << *ptr << endl;
return 0;
}
Output as Expected is:
10 (x1)
20 (x2)
50 (x5)

Dereferencing array pointer in a function

How do you deference a pointer to an array to get the value stored in it? For example:
void testFunction(int **test){
printf("%d", *test[1]);
}
int main()
{ int test[10];
test[1] = 5;
testFunction(&test);
return 0;
}
I get an error. Anyone could explain?
How do you deference a pointer to an array to get the value stored in it?
You use the * operator, as for every pointer. (Oh, and pay attention to operator precedence!)
void foo(int (*arr)[5])
{
printf("%d\n", (*arr)[0]);
}
int main()
{
int arr[5] = { 0, 1, 2, 3, 4 };
foo(&arr);
return 0;
}
Your code would have generated a diagnostic about an incompatible type being passed to the function. For example, GCC complains:
prog.c: In function 'main':
prog.c:9: warning: passing argument 1 of 'testFunction' from incompatible pointer type
You should pay attention to all diagnostics issued by your compiler, and make sure you understand them, and take the appropriate measures to address them. For this particular one, if you intend to pass in a pointer to an array, you need to write your function to accept such a thing. Then, when you dereference the pointer, you have an array. So, you access it like one.
void testFunction(int (*test)[10]){
printf("%d", (*test)[1]);
}
The [] has higher precedence that *, so the parentheses are required both for the function parameter argument, and for accessing the value in the printf(). When the pointer to int[10] is derferenced, the resulting value is the address of the first element of the array test defined in main. The [] operation then access the 2nd element of the array, and you get the value you expected.
You may be more convinced that your use of int **test is wrong for a pointer to an array if you note that the assertion below will always be true:
int test[10];
assert(&test == (void *)test);
As the compiler warning indicates, a pointer to a pointer to int is not the same as a pointer to an int[10]. The type being pointed to determines the type that results from a dereference.
So:
int test[10] = { [1] = 5 };
testFunction(&test);
This passes the address of test to testFunction. The address of a variable corresponds to its location in memory. This is not so different for an array, but the location in memory for an array variable is the address of its first element. So, the address returned by &test above is the same address returned by test alone.
This gives a disastrous consequence when you treat this pointer value as a pointer to a pointer to int in your testFunction. First, note that you ignore proper operator precedence, so the first dereference is:
test[1]
Since you declare the test parameter to be a pointer to a pointer to int, this increments the address in test by sizeof(int *) and treats the result as an int *. Then, you dereference again:
*test[1]
This now takes the value of test[1] and dereferences it again in an attempt to get an int. However, the address returned by test[1] has no relationship with the array test defined in main, and you are accessing a totally nonsensical memory location.
Even if you paid attention to the precedence with your pointer to pointer to int parameter type, a similar problem would have resulted.
(*test)[1]
Now, the pointer to int[10] is treated as a pointer to pointer to int is derferenced first. This results in the first sizeof(int **) bytes of the test array in main to be treated as a pointer to int. This is already a nonsensical value at this point, but the array dereference now increments this value by sizeof(int) bytes and dereferences that value in an attempt to obtain an int.
The other user gave an example of how it is usually done already, but if you insist on passing an int ** then because of operator precedence the syntax would be like:
void testFunction(int **test){
printf("%d", (*test)[1]);
}
int main()
{ int test[10];
test[1] = 5;
int *testptr= &test[0]; // or int *testptr= test;
testFunction(&testptr); // this passes an int **
return 0;
}
But in c the name of an array is a pointer to the array elements, so int *ptrtest and ptrtest[1] is more commonly used.

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.

Pointer-array-extern question

File 1.c
int a[10];
File main.c:
extern int *a;
int main()
{
printf("%d\n", a[0]);
return 0;
}
Gives me a segfault! What's going wrong?
Arrays decompose, or are implicitly converted to pointers when passed to a function as an argument, or when converted to an r-value on the right-hand-side of the assignment operator. So something like:
int array[10];
int* a = array; //implicit conversion to pointer to type int
void function(int* a);
function(array); //implicit conversion to pointer to type int
works just fine. But that does not mean that arrays themselves are pointers. So if you treat an array like a pointer as you've done, you're actually treating the array type as-if it was a pointer that held the address to an int object. Since your array is actually a sequence of int objects, and not pointers to int objects, you're actually trying to dereference to some memory location that isn't pointing to anywhere valid (i.e., the first slot in array is a numerical integer value like 0 which would be like dereferencing a NULL). So that is why you're segfaulting. Note that if you had done something like this:
int array[] = { 1, 2, 3, 4, 5};
int b = *array;
That still works, since array is again implicitly converted to a pointer to the memory block that is holding a sequence of integer values and is then dereferenced to get the value in the first sequence. But in your case, by declaring your array to the current code module as an externally defined pointer, and not an array, it will skip over the implicit conversion to a pointer that is normally done, and just use the array object as-if it were a pointer to an object itself, not an array of objects.
Well explained in the C FAQ. And there is a followup. The picture in the second link is worth a million bucks.
char a[] = "hello";
char *p = "world";
Short answer: use extern int a[].
A bit late, a duplicate of this problem was just entered (and closed). The answers here don't mention header files...
The problem would be caught at compile time if you put the declaration of array a in a header file, where it belongs, instead of putting it in the .c file. The header file should then be included into both .c files and the compiler can see that what you have declared is wrong.
Your header file would contain:
extern int myarray[];
You will get something like "error: conflicting types for a" if you declare a as a pointer instead.
Basically you'd need to write your main.c like this:
extern int a[];
int main()
{
printf("%d\n", a[0]);
return 0;
}
Check out the output of the following code.
File1.c
#include <stdio.h>
extern int* my_arr;
void my_print()
{
printf("%d", my_arr);
}
main.c
#include <stdio.h>
int my_arr[2] = {1,2};
extern void my_print();
void main()
{
my_print();
}
output
1
inside File1.c my_arr is a pointer variable that has the value of 1. meaning the 1st element of my_arr[] was assigned to it. Then if you use *my_arr to access memory location ox1, you get seg fault because you are not allowed to access ox01.
Why my_arr pointer was assigned 1 (the first element of my_arr[])?
Has to do with how assembler works. Read this article
Why your code can't access 0x01 ?
I know it has to do with the operating system not allowing some address space to be accessed by user code. Thats all I know. google it if you want more info.

Resources