C/C++ Int[] VS Int* (Pointers Vs. Array Notation). What Is the Difference

C/C++ int[] vs int* (pointers vs. array notation). What is the difference?

According to the C99 standard:

An array type describes a contiguously allocated nonempty set of
objects with a particular member object type, called the element
type.


  1. Array types are characterized by their element type and by
    the number of elements in the array. An array type is said to be
    derived from its element type, and if its element type is T, the array
    type is sometimes called array of T. The construction of an array
    type from an element type is called array type derivation.

A pointer type may be derived from a function type, an object type, or
an incomplete type, called the referenced type. A pointer type
describes an object whose value provides a reference to an entity of
the referenced type. A pointer type derived from the referenced type T
is sometimes referred to as a pointer to T. The construction of a pointer
type from a referenced type is called pointer type derivation.

According to the standard declarations…

char s[] = "abc", t[3] = "abc";
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };

…are identical. The contents of the arrays are modifiable. On the other hand, the declaration…

const char *p = "abc";

…defines p with the type as pointer to constant char and initializes it to point to an object with type constant array of char (in C++) with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

According to 6.3.2.1 Array subscripting dereferencing and array subscripting are identical:

The definition of the subscript operator [] is that E1[E2] is
identical to (*((E1)+(E2))).

The differences of arrays vs. pointers are:

  • pointer has no information of the memory size behind it (there is no portable way to get it)
  • an array of incomplete type cannot be constructed
  • a pointer type may be derived from a an incomplete type
  • a pointer can define a recursive structure (this one is the consequence of the previous two)

More helpful information on the subject can be found at http://www.cplusplus.com/forum/articles/9/

C++ pointer vs array notation

No, 'foo' is an array type in both cases but when a pointer is expected in expression with 'foo', it's implicitly converted to one (which points to the array first element). All arrays have this behavior. In the case, as addition can be done via pointer types, but not with arrays, 'foo' is converted to 'int *'.

*(foo+2) // 'foo' is implicitly converted into 'int *', pointing to 'foo' first element

foo + 1 //same as above

But now you may ask, what are the properties of the 'array' type and why we should ever use it, instead of the implicit pointer to first element cast. The things is that they are not much. You can tell the size of an object with type array like this:

sizeof(foo) //returns the size which array 'foo' occupies 

And get it's address by using the '&' operator:

&foo // '&foo' has type of 'int (*)[5]'

You can also create functions with parameters of 'array' reference (or pointer) type in order to accept only ones with specified size (which is not possible if they are just pointers and expect arrays passed to decay into such). Example:

void func(int (&)[5]);

void func1(int (*arg)[5]); // should be accessed by '*arg', allow the use of null-pointers

void func2(int *); //same as the misleading 'void func2(int [5])' or 'void func2(int [6])' etc.

int foo[5];

int foo1[6];

func(foo); // 'foo' type is ('int [5]') - ok

func1(&foo); // '&foo' type is ('int (*)[5]') - ok

func(foo1); // 'foo1' type is ('int [6]') - not allowed, param type is 'int (&)[5]' !

func1(&foo1); // '&foo1' type is ('int (*)[6]') - not allowed, param type is 'int (*)[5]' !

func2(foo); // 'foo' is implicitly converted to 'int *' - ok

func2(foo1); // 'foo1' is implicitly converted to 'int *' - ok

In the second case when the array is 2D - the same properties are applied. It's declaration means this: 'an array of 3 elements with type array of 4 elements with type int' So it's actually just an array of arrays and nothing more. It's implicit pointer to first element conversion is not of type 'int **' but instead of 'int (*)[4]', as each element of it is another array.

The declaration can be written this way too:

int (foo[3])[4];

Also note 'arrays' cannot be assigned, so they can't be passed by value or returned by functions. What I mean is:

int funcReturningArray()[2]; //not allowed

int funcAcceptingArray(int [2]); //just converted into pointer

int funcAcceptingArray(int *); //same as above

Although array parameters are syntactically accepted because of legacy reasons (or because something else ?), their real meaning is never tolerated and they are just 'adjusted' to pointers.

Note: The implicit conversion of array type to a pointer of it's first element is sometimes called 'Array to pointer decay'.

C pointer notation compared to array notation: When passing to function

There is no real functional difference between the two notations. In C, when you pass an array variable to a function, it decays to a pointer regardless of the notation. However, in my opinion, the pointer notation is preferable. The problem with [] notation in function definitions is that, in my opinion, it is somewhat misleading:

void foo(int array[])
{

}

A ubiquitous mistake among novice C programmers is to assume that sizeof(array) will give you the number of elements in the array multiplied by sizeof(int), like it would if array were an array variable declared on the stack. But the reality is that array has been decayed to a pointer, despite the misleading [] notation, and so sizeof(array) is going to be sizeof(int*). array is really just a pointer to the first element, or possibly a pointer to a single integer allocated anywhere.

For example, we could call foo like this:

int x = 10;
foo(&x);

In which case the [] notation in the definition of foo is kind of misleading.

Array and pointers in c++

I often hear that the name of an array is constant pointer to a block of memory

You've often been mislead - or you've simply misunderstood. An array is not a constant pointer to a block of memory. Array is an object that contains a sequence of sub-objects. All objects are a block of memory. A pointer is an object that contains an address of an object i.e. it points to the object.

So in the following quote, a is an array, p points to the first sub-object within a.

int a[10];

and

int * const p= a;

must be equal in a sense that p is pointer that points to the same block of memory as array a[] and also it may not be changed to point to another location in memory.

If that is your definition of equal, then that holds for non-array objects as well:

char c;
int * const p = &c;

Here p "points to the same memory as c" and may not be changed to point to another location in memory. Does that mean that char objects are "equal" to pointers? No. And arrays aren't either.

But isn't a (the name of the array), a constant pointer that points to the same element of the array?

No, the name of the array isn't a constant pointer. Just like name of the char isn't a constant pointer.

the name of an array holds the address of the first element in the array, right?

Let's be more general, this is not specific to arrays. The name of a variable "holds the address" of the object that the variable names. The address is not "held" in the memory at run time. It's "held" by the compiler at compile time. When you operate on a variable, the compiler makes sure that operations are done to the object at the correct address.

The address of the array is always the same address as where the first element (sub-object) of the array is. Therefore, the name indeed does - at least conceptually - hold the same address.

And if i use *(a+1), this is the same as a[1], right? [typo fixed]

Right. I'll elaborate: One is just another way of writing another in the case of pointers. Oh, but a isn't a pointer! Here is the catch: The array operand is implicitly converted to a pointer to first element. This implicit conversion is called decaying. This is special feature of array types - and it is the special feature which probably makes understanding the difference between pointers and arrays difficult the most.

So, even though the name of the array isn't a pointer, it can decay into a pointer. The name doesn't always decay into a pointer, just in certain contexts. It decays when you use operator[], and it decays when you use operator+. It decays when you pass the array to a function that accepts a pointer to the type of the sub-object. It doesn't decay when you use sizeof and it doesn't decay when you pass it to a function that accepts an array by reference.

Difference between pointer and array in C

The first one the array is fully controlled by the scope. It will allocate the needed memory correctly and when the variable goes out of escope the memory will be freely automatically.

The second one you have to control the memory by yourself. It does not have a defined scope, although if you do not destroy it when it gets out of reach, it will leave a memory leak.

To help you more about the dead cycle, I need more info about what you are doing with the array or array-pointer.

What's the difference between the types - int * and int *[100] in C?

  1. This is a pointer to an int:

    int *p;
    ┌────┐
    │int*│
    └────┘

    It should point at an int, something like this:

    ┌────┐
    │int*│
    └─┃──┘

    ┌───┐
    │int│
    └───┘
  2. This is an array of 100 pointers to int:

    int *p[100];

    That is, it gives you 100 pointers.

    ┌────┬────┬────┬────┬────┬────┬┄
    │int*│int*│int*│int*│int*│int*│
    └────┴────┴────┴────┴────┴────┴┄

    Each pointer should point an int, perhaps like this:

    ┌────┬────┬────┬────┬────┬────┬┄
    │int*│int*│int*│int*│int*│int*│
    └─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴─┃──┴┄
    ▼ ▼ ▼ ▼ ▼ ▼
    ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐┌┄
    │int││int││int││int││int││int││
    └───┘└───┘└───┘└───┘└───┘└───┘└┄

    Of course, there's no reason they can't all point at the same int, or whatever.

    You may want to use an array of pointers if you want many pointers that you can easily
    iterate over. You may, for example, dynamically allocate objects and have each pointer point at a different object:

    p[0] = new int(0);
    p[1] = new int(0);
    // ...

    Perhaps dynamically allocating ints isn't the best example, but I think the point is clear.

  3. This is a pointer to an array of 100 int:

    int (*p)[100];

    That is, it gives you just 1 pointer:

    ┌───────────┐
    │int(*)[100]│
    └───────────┘

    It should point at an array that contains 100 ints:

    ┌───────────┐
    │int(*)[100]│
    └─┃─────────┘

    ┌───┬───┬───┬───┬───┬───┬┄
    │int│int│int│int│int│int│
    └───┴───┴───┴───┴───┴───┴┄

    You will get a pointer to an array when you use the address-of operator (&) on the name of an array. For example:

    int arr[100] = { /* some initial values */ };
    int (*p)[100] = &arr;

    Here, I've taken the address of the arr array, which gives me a pointer to that array. If you then want to access an element of the array, you have to dereference the pointer first: (*p)[3] will access element 3.



Side note:

Always remember that arrays are not pointers. As we have just seen, we can take the address of an array to get a pointer to it, just like any other (non-temporary) object in C++. The only special connection between arrays and pointers is that the name of an array can be implicitly converted to a pointer to the array's first element. That means the following is valid:

int arr[100] = { /* some initial values */ };
int* p = arr;

The pointer p will point at the first element in arr. Note that p is not a pointer to the array, but a pointer to an element of the array.

(Also note that there is no such thing as an array type function argument. If you write something like int p[] as a function argument, it is transformed by the compiler to be a int*.)

Difference between array of pointers and pointer to array?

char string1[3][4]={"koo","kid","kav"}; //This is a 2D array

char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters

Besides the fact that string can point to strings of any size and
string1Ptr can only point to strings of size 4 only(otherwise
pointer arithmetic would go wrong), I don't any differences between
them.

They are absolutely, fundamentally different, but C goes to some trouble to hide the distinction from you.

string is an array. It identifies a block of contiguous memory wherein its elements are stored. Those elements happen to be of type char * in this example, but that's a relatively minor detail. One can draw an analogy here to a house containing several rooms -- the rooms are physically part of and exist inside the physical boundaries of the house. I can decorate the rooms however I want, but they always remain the rooms of that house.

string1Ptr is a pointer. It identifies a chunk of memory whose contents describe how to access another, different chunk of memory wherein an array of 4 chars resides. In our real estate analogy, this is like a piece of paper on which is written "42 C Street, master bedroom". Using that information, you can find the room and redecorate it as you like, just as in the other case. But you can also replace the paper with a locator for a different room, maybe in a different house, or with random text, or you can even burn the whole envelope, without any of that affecting the room on C Street.

string1, for its part, is an array of arrays. It identifies a block of contiguous memory where its elements are stored. Each of those elements is itself an array of 4 chars, which, incidentally, happens to be just the type of object to which string1Ptr can point.

For example,

printf("%s\n", string1[2]);   // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);

They all seem to perform the same pointer arithmetic.(My reason for
assuming string and string1Ptr are almost similar besides for the
difference I stated above)

... and that is where C hiding the distinction comes in. One of the essential things to understand about C arrays is that in nearly all expressions,* values of array type are silently and automatically converted to pointers [to the array's first element]. This is sometimes called pointer "decay". The indexing operator is thus an operator on pointers, not on arrays, and indeed it does have similar behavior in your three examples. In fact, the pointer type to which string1 decays is the same as the type of string1Ptr, which is why the initialization you present for the latter is permitted.

But you should understand that the logical sequence of operations is not the same in those three cases. First, consider

printf("%s\n", string1Ptr[2]);

Here, string1Ptr is a pointer, to which the indexing operator is directly applicable. The result is equivalent to *(string1Ptr + 2), which has type char[4]. As a value of array type, that is converted to a pointer to the first element (resulting in a char *).

Now consider

printf("%s\n", string1[2]);

string1 is an array, so first it is converted to a pointer to its first element, resulting in a value of type char(*)[4]. This is the same type as string1Ptr1, and evaluation proceeds accordingly, as described above.

But this one is a bit more different:

printf("%s\n", string[2]);

Here, string is a pointer, so the indexing operation applies directly to it. The result is equivalent to *(string + 2), which has type char *. No automatic conversions are performed.

Any reason to use one over the other?

Many, in both directions, depending on your particular needs at the time. Generally speaking, pointers are more flexible, especially in that they are required for working with dynamically allocated memory. But they suffer from the issues that

  • a pointer may be in scope, but not point to anything, and
  • declaring a pointer does not create anything for it to point to. Also,
  • even if a pointer points to something at one time during an execution of the program, and its value is not subsequently written by the program, it can nevertheless stop pointing to anything. (This most often is a result of the pointer outliving the object to which it points.)

Additionally, it can be be both an advantage and a disadvantage that

  • a pointer can freely be assigned to point to a new object, any number of times during its lifetime.

Generally speaking, arrays are easier to use for many purposes:

  • declaring an array allocates space for all its elements. You may optionally specify initial values for them at the point of declaration, or in some (but not all) cases avail yourself of default initialization.
  • the identifier of an array is valid and refers to the array wherever it is in scope.
  • Optionally, if an initializer is provided then an array declaration can use it to automatically determine the array dimension(s).

* But only nearly all. There are a few exceptions, with the most important being the operand of a sizeof operator.



Related Topics



Leave a reply



Submit