With me it helped that I spent several years writing games in assembly language where the concept of an array doesn't really exist. Everything is just bytes in RAM. A pointer holds an address. From the CPU's point of view it is just the address of an area in memory. There is no concept of arrays at this level just a large number of bytes at sequential addresses. When you move into C though, the compiler needs to know things. If it's a pointer, what type of data is at the address that the pointer holds? If it's an an int e.g. int * ptr then the four bytes at address, address+1,address+2,address+3 are what *ptr refer to. An array is just a repeating length of bytes held at an address in memory. If you have an array of int e.g. int fred[10] is just a block of forty consecutive bytes. You can think as fred as being the address of this block, and ptr = fred just means set ptr = the address of fred. We can also set ptr to point to any of the 10 ints held in fred. ptr = &fred[0], or &freed[9]. The compiler just calculates the index offset say 9, multiplies it by the size of int (4) and adds it to the address of fred. So ptr now has the address fred + 36. *ptr is the int that is stored at addresses fred+36,37,38 and 39. All of the RAM that is not used by the stack or global variables is as you said the heap. You have to reserve a chunk of it with malloc which returns a pointer to your reserved block before you can use it and when you are finished with it, you must free it. Because malloc just returns a bare pointer, you have to tell the C compiler what type to use with it by casting. There's nothing magical about arrays and pointers. They are just 'structures' superimposed on RAM for the purpose of using them. Answer from davidhbolton on reddit.com
🌐
Eli Bendersky
eli.thegreenplace.net › 2009 › 10 › 21 › are-pointers-and-arrays-equivalent-in-c
Are pointers and arrays equivalent in C? - Eli Bendersky's website
When an array name is passed to a function, what is passed is the location of the initial element. Within the called function, this argument is a local variable, and so an array name parameter is a pointer, that is, a variable containing an address.
🌐
Reddit
reddit.com › r/c_programming › what exactly is the difference between a pointer and an array?
r/C_Programming on Reddit: What exactly is the difference between a pointer and an array?
July 16, 2020 -

Any video I watch, or any article I read, I always see arrays being referred to as "pointers", or the phrase, "an array is a pointer in itself". I know that we can represent arrays in a pointer-like fashion and that &array-name[0] is the address of the 0th element or in essence, the starting address of the array. But can we call an array a pointer? If my memory serves right, whenever we create pointers, the are allocated memory from the heap memory instead of the stack memory and it is exactly opposite for static arrays.

If so, then why do people refer to arrays as pointers many times? I read this answer on StackOverflow and it seemed pretty valid to me yet I do not get it why are the above phrases/jargon used by people?

Could I please get some explanation on this and some clarification on this topic? It would be of much help. This whole thing is bugging me for the last 4-5 days.

Thank you :)

Top answer
1 of 3
12
With me it helped that I spent several years writing games in assembly language where the concept of an array doesn't really exist. Everything is just bytes in RAM. A pointer holds an address. From the CPU's point of view it is just the address of an area in memory. There is no concept of arrays at this level just a large number of bytes at sequential addresses. When you move into C though, the compiler needs to know things. If it's a pointer, what type of data is at the address that the pointer holds? If it's an an int e.g. int * ptr then the four bytes at address, address+1,address+2,address+3 are what *ptr refer to. An array is just a repeating length of bytes held at an address in memory. If you have an array of int e.g. int fred[10] is just a block of forty consecutive bytes. You can think as fred as being the address of this block, and ptr = fred just means set ptr = the address of fred. We can also set ptr to point to any of the 10 ints held in fred. ptr = &fred[0], or &freed[9]. The compiler just calculates the index offset say 9, multiplies it by the size of int (4) and adds it to the address of fred. So ptr now has the address fred + 36. *ptr is the int that is stored at addresses fred+36,37,38 and 39. All of the RAM that is not used by the stack or global variables is as you said the heap. You have to reserve a chunk of it with malloc which returns a pointer to your reserved block before you can use it and when you are finished with it, you must free it. Because malloc just returns a bare pointer, you have to tell the C compiler what type to use with it by casting. There's nothing magical about arrays and pointers. They are just 'structures' superimposed on RAM for the purpose of using them.
2 of 3
3
An array is different from a pointer mainly due to the fact that its size is encoded in its type. If you write, int foo[5]; printf("%d", sizeof(foo)); it will print 20 on most modern systems, where ints are 4 bytes. The confusion about the duality of arrays and pointers mostly arises due to something called array/pointer decay, which is a property of C that causes arrays to "decay" (i.e. something is lost, in this case information about its length) to a pointer. Whenever you pass an array to a function or return one (which you should never do anyway), this is what happens. It decays to a pointer, meaning the callee has no information about its size. void print_size(int* array) { printf("argument size: %d", sizeof(array)); } int foo[5] = { 1, 2, 3, 4, 5 }; printf("\nsize: %d ", sizeof(foo)); print_size(foo); // decay to pointer This will print, size: 20 argument size: 8 8 is the size of a pointer on any modern, 64-bit system. The function has no way of determining how many elements the array has. Since, as you said, the identifier of an array merely points to its first element, you could also do, int a = 123; // not an array print_size(&a); and it would work perfectly fine. The general solution for this issue is to add another parameter that asks for the number of elements in the array you passed as a pointer. void print_array(int* array, size_t size) { for (size_t i = 0; i < size; ++i) { printf("%d ", array[i]); } } int foo[] = { 1, 2, 3, 4, 5 }; print_array(foo, 5); // decay to pointer // or, without hardcoding the size argument print_array(foo, sizeof(foo) / sizeof(int));// again, decay to pointer You might be wondering how print_array can use its array parameter as if it were an array, even though it's a pointer. This is where pointer arithmetic comes in. Remember, in array decay, the array becomes a pointer to its first element. The authors of the language thought of this and allowed using pointers as arrays. If you say, pointer[index] = 234; the product of index and the size of the type of the data pointer points to is added to the address pointer represents, and the whole result is dereferenced. This may sound complicated, but in a simplified way, it means that working with pointers is the same as working with arrays. It's as if you had written, *(pointer + index) = 234; The two aren't just similar, they're exactly equivalent. Since addition is commutative, i.e. the order of the operands doesn't matter, you could also swap them, like this, 4[array] = 234; instead of, array[4] = 234; This compiles, and it is legal, but it looks silly, so no one does it. I hope this provides some insight.
Discussions

C: differences between char pointer and array - Stack Overflow
Consider: char amessage[] = "now is the time"; char *pmessage = "now is the time"; I read from The C Programming Language, 2nd Edition that the above two statements don't do the same thing. I alw... More on stackoverflow.com
🌐 stackoverflow.com
C strings pointer vs. arrays - Stack Overflow
Possible Duplicate: What is the difference between char s[] and char *s in C? Why is: char *ptr = "Hello!" different than: char ptr[] = "Hello!" Specifically, I don't see why you can use (*pt... More on stackoverflow.com
🌐 stackoverflow.com
In C, are arrays pointers or used as pointers? - Stack Overflow
My understanding was that arrays were simply constant pointers to a sequence of values, and when you declared an array in C, you were declaring a pointer and allocating space for the sequence it po... More on stackoverflow.com
🌐 stackoverflow.com
What is the difference between an array and a pointer in C, and when should I use one over the other? - Stack Overflow
I am a first-year CSE student, and I’m currently learning C programming. I understand the basics of arrays and pointers, but I’m still a bit confused about the key differences between them and when... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Programiz
programiz.com › c-programming › c-pointers-arrays
Relationship Between Arrays and Pointers in C Programming (With Examples)
To access elements of the array, we have used pointers. In most contexts, array names decay to pointers. In simple words, array names are converted to pointers. That's the reason why you can use pointers to access elements of arrays.
🌐
GeeksforGeeks
geeksforgeeks.org › c language › difference-between-array-and-pointers
Difference between Arrays and Pointers - GeeksforGeeks
July 23, 2025 - The array is one of the most used data types in many programming languages due to its simplicity and capability. A pointer is a variable that holds the memory address of another variable.
Top answer
1 of 14
176

Here's a hypothetical memory map, showing the results of the two declarations:

                0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07
    0x00008000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00008008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
        ...
amessage:
    0x00500000:  'n'   'o'   'w'   ' '   'i'   's'   ' '   't'
    0x00500008:  'h'   'e'   ' '   't'   'i'   'm'   'e'  '\0'
pmessage:
    0x00500010:  0x00  0x00  0x80  0x00

The string literal "now is the time" is stored as a 16-element array of char at memory address 0x00008000. This memory may not be writable; it's best to assume that it's not. You should never attempt to modify the contents of a string literal.

The declaration

char amessage[] = "now is the time";

allocates a 16-element array of char at memory address 0x00500000 and copies the contents of the string literal to it. This memory is writable; you can change the contents of amessage to your heart's content:

strcpy(amessage, "the time is now");

The declaration

char *pmessage = "now is the time";

allocates a single pointer to char at memory address 0x00500010 and copies the address of the string literal to it.

Since pmessage points to the string literal, it should not be used as an argument to functions that need to modify the string contents:

strcpy(amessage, pmessage); /* OKAY */
strcpy(pmessage, amessage); /* NOT OKAY */
strtok(amessage, " ");      /* OKAY */
strtok(pmessage, " ");      /* NOT OKAY */
scanf("%15s", amessage);    /* OKAY */
scanf("%15s", pmessage);    /* NOT OKAY */

and so on. If you changed pmessage to point to amessage:

pmessage = amessage;

then it can be used everywhere amessage can be used.

2 of 14
120

True, but it's a subtle difference. Essentially, the former:

char amessage[] = "now is the time";

Defines an array whose members live in the current scope's stack space, whereas:

char *pmessage = "now is the time";

Defines a pointer that lives in the current scope's stack space, but that references memory elsewhere (in this one, "now is the time" is stored elsewhere in memory, commonly a string table).

Also, note that because the data belonging to the second definition (the explicit pointer) is not stored in the current scope's stack space, it is unspecified exactly where it will be stored and should not be modified.

As pointed out by Mark, GMan, and Pavel, there is also a difference when the address-of operator is used on either of these variables. For instance, &pmessage returns a pointer of type char**, or a pointer to a pointer to chars, whereas &amessage returns a pointer of type char(*)[16], or a pointer to an array of 16 chars (which, like a char**, needs to be dereferenced twice as litb points out).

🌐
W3Schools
w3schools.com › c › c_pointers_arrays.php
C Pointers and Arrays
Well, in C, the name of an array, is actually a pointer to the first element of the array.
🌐
TutorialsPoint
tutorialspoint.com › cprogramming › c_pointer_vs_array.htm
Pointer vs Array in C
To differentiate from the target ... its pointer is declared as "int *". ... Note: In case of an array, the address of its 0th element is assigned to the pointer....
Find elsewhere
🌐
TutorialsPoint
tutorialspoint.com › cprogramming › c_array_of_pointers.htm
Array of Pointers in C
Just like an integer array holds a collection of integer variables, an array of pointers would hold variables of pointer type. It means each variable in an array of pointers is a pointer that points to another address.
🌐
GeeksforGeeks
geeksforgeeks.org › c language › pointer-vs-array-in-c
Pointer vs Array in C - GeeksforGeeks
char array[] = “abc” sets the first four elements in array to ‘a’, ‘b’, ‘c’, and ‘\0’ · char *pointer = “abc” sets the pointer to the address of the “abc” string (which may be stored in read-only memory and thus unchangeable)
Published   July 23, 2025
🌐
Carleton University
people.scs.carleton.ca › ~mjhinek › W13 › COMP2401 › notes › Arrays_and_Pointers.pdf pdf
T h e G r o u p o f T h r e e 2013 Arrays and Pointers Class Notes
In C , name of the array always points to the first element of an array. Here, address of first element of · an array is &age[0]. Also, age represents the address of the pointer where it is pointing.
🌐
tutorialpedia
tutorialpedia.org › blog › difference-between-passing-array-and-array-pointer-into-function-in-c
Difference Between Passing Array vs. Array Pointer to a Function in C: Behavior and Stack Space Comparison — tutorialpedia.org
Size Information is Lost: Since arr is a pointer to an int (not the array), sizeof(arr) returns the size of the pointer (e.g., 8 bytes on 64-bit systems), not the array. Thus, you must pass the array size explicitly as a separate parameter. Modifying Elements: The function can modify the original array’s elements via arr[i] because arr points to the first element of the original array.
Top answer
1 of 5
44

You can (in general) use the expression (*ptr)++ to change the value that ptr points to when ptr is a pointer and not an array (ie., if ptr is declared as char* ptr).

However, in your first example:

Copychar *ptr = "Hello!"

ptr is pointing to a literal string, and literal strings are not permitted to be modified (they may actually be stored in memory area which are not writable, such as ROM or memory pages marked as read-only).

In your second example,

Copychar ptr[] = "Hello!";

The array is declared and the initialization actually copies the data in the string literal into the allocated array memory. That array memory is modifiable, so (*ptr)++ works.

Note: for your second declaration, the ptr identifier itself is an array identifier, not a pointer and is not an 'lvalue' so it can't be modified (even though it converts readily to a pointer in most situations). For example, the expression ++ptr would be invalid. I think this is the point that some other answers are trying to make.

2 of 5
2

When pointing to a string literal, you should not declare the chars to be modifiable, and some compilers will warn you for this:

Copychar *ptr = "Hello!"    /* WRONG, missing const! */

The reason is as noted by others that string literals may be stored in an immutable part of the program's memory.

The correct "annotation" for you is to make sure you have a pointer to constant char:

Copyconst char *ptr = "Hello!"

And now you see directly that you can't modify the text stored at the pointer.

🌐
C-faq
c-faq.com › aryptr
6. Arrays and Pointers
6.12 Since array references decay into pointers, if arr is an array, what's the difference between arr and &arr?
Top answer
1 of 6
96

Here's the exact language from the C standard (n1256):

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

The important thing to remember here is that there is a difference between an object (in C terms, meaning something that takes up memory) and the expression used to refer to that object.

When you declare an array such as

int a[10];

the object designated by the expression a is an array (i.e., a contiguous block of memory large enough to hold 10 int values), and the type of the expression a is "10-element array of int", or int [10]. If the expression a appears in a context other than as the operand of the sizeof or & operators, then its type is implicitly converted to int *, and its value is the address of the first element.

In the case of the sizeof operator, if the operand is an expression of type T [N], then the result is the number of bytes in the array object, not in a pointer to that object: N * sizeof T.

In the case of the & operator, the value is the address of the array, which is the same as the address of the first element of the array, but the type of the expression is different: given the declaration T a[N];, the type of the expression &a is T (*)[N], or pointer to N-element array of T. The value is the same as a or &a[0] (the address of the array is the same as the address of the first element in the array), but the difference in types matters. For example, given the code

int a[10];
int *p = a;
int (*ap)[10] = &a;

printf("p = %p, ap = %p\n", (void *) p, (void *) ap);
p++;
ap++;
printf("p = %p, ap = %p\n", (void *) p, (void *) ap);

you'll see output on the order of

p = 0xbff11e58, ap = 0xbff11e58
p = 0xbff11e5c, ap = 0xbff11e80

IOW, advancing p adds sizeof int (4) to the original value, whereas advancing ap adds 10 * sizeof int (40).

More standard language:

6.5.2.1 Array subscripting

Constraints

1 One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

Semantics

2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th element of E1 (counting from zero).

Thus, when you subscript an array expression, what happens under the hood is that the offset from the address of the first element in the array is computed and the result is dereferenced. The expression

a[i] = 10;

is equivalent to

*((a)+(i)) = 10;

which is equivalent to

*((i)+(a)) = 10;

which is equivalent to

 i[a] = 10;

Yes, array subscripting in C is commutative; for the love of God, never do this in production code.

Since array subscripting is defined in terms of pointer operations, you can apply the subscript operator to expressions of pointer type as well as array type:

int *p = malloc(sizeof *p * 10);
int i;
for (i = 0; i < 10; i++)
  p[i] = some_initial_value(); 

Here's a handy table to remember some of these concepts:

Declaration: T a[N];

Expression    Type    Converts to     Value
----------    ----    ------------    -----
         a    T [N]   T *             Address of the first element in a;
                                        identical to writing &a[0]
        &a    T (*)[N]                Address of the array; value is the same
                                        as above, but the type is different
  sizeof a    size_t                  Number of bytes contained in the array
                                        object (N * sizeof T)
        *a    T                       Value at a[0]
      a[i]    T                       Value at a[i]
     &a[i]    T *                     Address of a[i] 

Declaration: T a[N][M];

Expression     Type        Converts to     Value
----------     ----        ------------    -----
          a    T [N][M]    T (*)[M]        Address of the first subarray (&a[0])
         &a    T (*)[N][M]                 Address of the array (same value as
                                             above, but different type)
   sizeof a    size_t                      Number of bytes contained in the
                                             array object (N * M * sizeof T)
         *a    T [M]      T *              Value of a[0], which is the address
                                             of the first element of the first subarray
                                             (same as &a[0][0])
       a[i]    T [M]      T *              Value of a[i], which is the address
                                             of the first element of the i'th subarray
      &a[i]    T (*)[M]                    Address of the i-th subarray; same value as
                                             above, but different type
sizeof a[i]    size_t                      Number of bytes contained in the i'th subarray
                                             object (M * sizeof T)
      *a[i]    T                           Value of the first element of the i'th 
                                             subarray (a[i][0])
    a[i][j]    T                           Value at a[i][j]
   &a[i][j]    T *                         Address of a[i][j]

Declaration: T a[N][M][O];

Expression        Type             Converts to
----------        ----             -----------
         a        T [N][M][O]      T (*)[M][O]
        &a        T (*)[N][M][O]
        *a        T [M][O]         T (*)[O]
      a[i]        T [M][O]         T (*)[O]
     &a[i]        T (*)[M][O]
     *a[i]        T [O]            T *
   a[i][j]        T [O]            T *
  &a[i][j]        T (*)[O]
  *a[i][j]        T 
a[i][j][k]        T

From here, the pattern for higher-dimensional arrays should be clear.

So, in summary: arrays are not pointers. In most contexts, array expressions are converted to pointer types.

2 of 6
26

Arrays are not pointers, though in most expressions an array name evaluates to a pointer to the first element of the array. So it is very, very easy to use an array name as a pointer. You will often see the term 'decay' used to describe this, as in "the array decayed to a pointer".

One exception is as the operand to the sizeof operator, where the result is the size of the array (in bytes, not elements).

A couple additional of issues related to this:

An array parameter to a function is a fiction - the compiler really passes a plain pointer (this doesn't apply to reference-to-array parameters in C++), so you cannot determine the actual size of an array passed to a function - you must pass that information some other way (maybe using an explicit additional parameter, or using a sentinel element - like C strings do)

Also, a common idiom to get the number of elements in an array is to use a macro like:

#define ARRAY_SIZE(arr) ((sizeof(arr))/sizeof(arr[0]))

This has the problem of accepting either an array name, where it will work, or a pointer, where it will give a nonsense result without warning from the compiler. There exist safer versions of the macro (particularly for C++) that will generate a warning or error when it's used with a pointer instead of an array. See the following SO items:

  • C++ version
  • a better (though still not perfectly safe) C version

Note: C99 VLAs (variable length arrays) might not follow all of these rules (in particular, they can be passed as parameters with the array size known by the called function). I have little experience with VLAs, and as far as I know they're not widely used. However, I do want to point out that the above discussion might apply differently to VLAs.

🌐
Cornell Computer Science
cs.cornell.edu › courses › cs3410 › 2024fa › notes › pointer.html
Arrays & Pointers - CS 3410
The difference in C is that there is no magic: we get reference behavior out of the “raw materials” of bits, by treating some 64-bit values as addresses in memory. Under the hood, this is how references in other languages are implemented too—but in C, we get direct access to the underlying bits. Now that we know about pointers, let’s revisit arrays.
Top answer
1 of 1
5
  • An array is a contiguous block of memory that holds its elements.
  • A pointer is an object that stores the address of the first element of an array. The pointer does not hold any information about whether it points to a single object (which can be considered an array with just one element) or an actual array with multiple elements

When arrays are used in expressions they decay1 to pointers. In C, array-to-pointer decay refers to the automatic conversion of an array's name to a pointer to its first element. This decay happens in most contexts where an array is used, making the array's name behave like a pointer.

There are a few places when array do not decay to poointers:

  • when using the sizeof operator
  • when using the address-of operator (&)

Can you clarify how memory management works in both cases? I’ve heard that arrays have a fixed size in memory, whereas pointers can be used more flexibly, but I’m still not fully understanding when this flexibility is beneficial.

Aspect Arrays Dynamic Memory Allocation
Memory Lifetime Automatic (based on scope) Manual (requires free())
Size Determination Fixed at compile time (some compilers support Variable Length Arrays), the size cant be changed Flexible, decided at runtime, resizeable
Allocation Timing At declaration At runtime (malloc(), etc.)
Deallocation Automatic (when the scope ends) Manual (free())
Resizability Not resizable Resizable (realloc())
Initialization Can be initialized at declaration Must be initialized manually
Access Speed Typically faster (direct access) Potentially slower (indirect access)
Risk of Memory Leaks None (automatic management) Yes (if free() is missed)
Data Persistence Limited to the scope of declaration Can persist beyond function scope
Potential Issues Size limits based on declaration context, Cant be used when out of scope Risk of memory leaks, dangling and wild pointers etc

1 Decay: The term "decay" is a modern, informal term commonly used in the programming community to describe the process outlined in the C standard: "Except when it is the operand of the sizeof operator, the unary & operator, or is a string literal used to initialize an array, an expression of type 'array of T' is converted to an expression of type 'pointer to T' that points to the initial element of the array object."*

🌐
TutorialsPoint
tutorialspoint.com › cprogramming › c_pointer_to_an_array.htm
Pointer to an Array in C
In all the three cases, you get the same output − · Pointer 'ptr' points to the address: 647772240 Address of the first element: 647772240 Address of the first element: 647772240 · If you fetch the value stored at the address that ptr points to, that is *ptr, then it will return 1. It is legal to use array names as constant pointers and vice versa.
🌐
Medium
medium.com › @Dev_Frank › pointer-arrays-08100ef37ede
POINTER & ARRAYS. Understanding C Pointers and Arrays | by Dev Frank | Medium
February 17, 2024 - 2. Address Operators: array is synonymous with &array[0] and yields the address of the first array element. &pointer gives the address of the pointer variable itself. 3. String Literal Initialization: char array[ ] = “abc”` initializes the array with ‘a’, ‘b’, ‘c’, and ‘\0’. char *pointer = “abc”` sets the pointer to the address of the “abc” string (often stored in read-only memory).