Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C & C++: What is the difference between pointer-to and address-of array?

C++11 code:

int a[3];
auto b = a;       // b is of type int*
auto c = &a;      // c is of type int(*)[1]

C code:

int a[3];
int *b = a;
int (*c)[3] = &a;

The values of b and c are the same.

What is the difference between b and c? Why are they not the same type?

UPDATE: I changed the array size from 1 to 3.

like image 803
Domi Avatar asked Dec 08 '13 14:12

Domi


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.


3 Answers

The sizeof operator should behave differently, for one, especially if you change the declaration of a to a different number of integers, such as int a[7]:

int main()
{
    int a[7];

    auto b = a;
    auto c = &a;

    std::cout << sizeof(*b) << std::endl;  // outputs sizeof(int)
    std::cout << sizeof(*c) << std::endl;  // outputs sizeof(int[7])

    return 0;
}

For me, this prints:

4
28

That's because the two pointers are very different types. One is a pointer to integer, and the other is a pointer to an array of 7 integers.

The second one really does have pointer-to-array type. If you dereference it, sure, it'll decay to a pointer in most cases, but it's not actually a pointer to pointer to int. The first one is pointer-to-int because the decay happened at the assignment.

Other places it would show up is if you really did have two variables of pointer-to-array type, and tried to assign one to the other:

int main()
{
    int a[7];
    int b[9];

    auto aa = &a;
    auto bb = &b;

    aa = bb;

    return 0;
}

This earns me the error message:

xx.cpp: In function ‘int main()’:
xx.cpp:14:8: error: cannot convert ‘int (*)[9]’ to ‘int (*)[7]’ in assignment
     aa = bb;

This example, however, works, because dereferencing bb allows it to decay to pointer-to-int:

int main()
{
    int a;
    int b[9];

    auto aa = &a;
    auto bb = &b;

    aa = *bb;

    return 0;
}

Note that the decay doesn't happen on the left side of an assignment. This doesn't work:

int main()
{
    int a[7];
    int b[9];

    auto aa = &a;
    auto bb = &b;

    *aa = *bb;

    return 0;
}

It earns you this:

xx2.cpp: In function ‘int main()’:
xx2.cpp:14:9: error: incompatible types in assignment of ‘int [9]’ to ‘int [7]’
     *aa = *bb;
like image 76
Joe Z Avatar answered Nov 03 '22 08:11

Joe Z


The identity of any object in C++ is determined by the pair of its type and its address.

There are two distinct objects with the same address in your example: The array itself, and the first element of the array. The first has type int[1], the second has type int. Two distinct objects can have the same address if one is a subobject of the other, as is the case for array elements, class members, and class base subobjects.

Your example would be clearer if you wrote:

int a[5];
int (*ptr_to_array)[5] = &a;
int * ptr_to_array_element = &a[0];

But you have taken advantage of the fact that the id-expression a for the array decays to a pointer to the array's first element, so a has the same value as &a[0] in your context.

like image 20
Kerrek SB Avatar answered Nov 03 '22 08:11

Kerrek SB


Consider this example:

#include<stdio.h>

int main()
{
    int myArray[10][10][10][10]; //A 4 Dimentional array;

    //THESE WILL ALL PRINT THE SAME VALUE
    printf("%d, %d, %d, %d, %d\n",
            myArray,
            myArray[0],
            myArray[0][0],
            myArray[0][0][0],
            &myArray[0][0][0][0]
          );

    //NOW SEE WHAT VALUES YOU GET AFTER ADDING 1 TO EACH OF THESE POINTERS
    printf("%d, %d, %d, %d, %d\n",
            myArray+1,
            myArray[0]+1,
            myArray[0][0]+1,
            myArray[0][0][0]+1,
            &myArray[0][0][0][0]+1
          );
}

You will find that all the 5 values printed in first case are all equal. Because they point to the same initial location.

But just when you increment them by 1 you see that different pointers now jump (point) to different locations. This is because myArray[0][0][0] + 1 will jump by 10 integer values that is 40 bytes, while myArray[0][0] + 1 will jump by 100 integer values i.e by 400 bytes. Similarly myArray[0] + 1 jumps by 1000 integer values or 4000 bytes.

So the values depend on what level of pointer you are referring to.

But now, if I use pointers to refer all of them:

#include<stdio.h>

int main()
{
    int myArray[10][10][10][10]; //A 4 Dimentional array;

            int * ptr1 = myArray[10][10][10];
            int ** ptr2 = myArray[10][10];
            int *** ptr3 = myArray[10];
            int **** ptr4 = myArray;

    //THESE WILL ALL PRINT THE SAME VALUE
    printf("%u, %u, %u, %u\n", ptr1, ptr2, ptr3, ptr4);

    //THESE ALSO PRINT SAME VALUES!!
    printf("%d, %d, %d, %d\n",ptr1+1,ptr2+1,ptr3+1,ptr4+1);
}

So you see, different levels of pointer variables do not behave the way the array variable does.

like image 1
Ashis Kumar Sahoo Avatar answered Nov 03 '22 08:11

Ashis Kumar Sahoo