0

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

4 Answers4

1

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(*)[].

Arjun Sreedharan
  • 11,003
  • 2
  • 26
  • 34
0

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

Bhuvanesh
  • 1,269
  • 1
  • 15
  • 25
0

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.

-1

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

Community
  • 1
  • 1
Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • "array doesn't have an address" Every variable has an address. Its value is not an address. "Because an array always points to the same memory location" An array is a sequence of elements; it doesn't "point". "There's no way to take array and get a temporary char**" Right, because that's a pointer to pointer, not pointer to array. "So &array has type char(*)[], and returns the location of the first char in the array." No, it returns a pointer to the array. – newacct Mar 20 '15 at 22:05