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.
- 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 isT
, the array
type is sometimes called array ofT
. 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 typeT
is sometimes referred to as a pointer toT
. 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 thatE1[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 asa[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?
This is a pointer to an
int
:int *p;
┌────┐
│int*│
└────┘It should point at an
int
, something like this:┌────┐
│int*│
└─┃──┘
▼
┌───┐
│int│
└───┘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
int
s isn't the best example, but I think the point is clear.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
int
s:┌───────────┐
│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 char
s 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 char
s, 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
assumingstring
andstring1Ptr
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
How to Easily Format My Data Table in C++
How to Get Console Output in C++ With a Windows Program
How to Calculate the Week Number Given a Date
What Does Opencv'S Cvwaitkey( ) Function Do
Functions With Const Arguments and Overloading
Rand() % 14 Only Generates the Values 6 or 13
Non-Blocking Worker - Interrupt File Copy
When Passing an Array to a Function in C++, Why Won't Sizeof() Work the Same as in the Main Function
What Techniques Can Be Used to Speed Up C++ Compilation Times
How Many and Which Are the Uses of "Const" in C++
Should I Use an Exception Specifier in C++
Looking For C++ Stl-Like Vector Class But Using Stack Storage
How to Detect Unnecessary #Include Files in a Large C++ Project
C++ Custom Stream Manipulator That Changes Next Item on Stream