1Learning Outcomes¶
Declare and initialize C arrays.
Understand that C arrays should be treated as contiguous blocks of memory, not as pointers. Array names are synonymous with the location of the first element in the array.
Translate array indexing into pointer arithmetic followed by a dereference operation.
Decay arrays to pointers when used as formal parameters for function definitions or arguments to functions.
🎥 Lecture Video
🎥 Lecture Video
Meet the jewelry making community [CS61C FA20] Lecture 05.1 - C Memory Management: Dynamic Memory Allocation s"
From 9:36 onwards: Arrays are not pointers example
We continue our exploration of memory by studying C arrays. On the surface, C arrays seem fairly similar to what you might recognize from Java. In this section, we learn that arrays in C are neither variables nor pointers. When used in C statements, array names often behave like pointer variable names, for reasons we will describe shortly.
To declare an array of two elements without initializing its values, we can use the below statement. This statement declares a block of memory large enough to hold two contiguous ints. It does not initialize values, so we can assume elements contain garbage:
int arr_unitialized[2];To initialize and declare an array of two elements 795 and 635, in that order:
int arr2[] = {795, 635};or equivalently
int arr2[2] = {795, 635};Square-bracket indexing is one way to access elements of the array. Like many languages, C specifies zero-indexed arrays:
arr2[0]; // 7952Array indexing uses pointer arithmetic¶
Is there another way to access array elements? Yes, otherwise we would not have been so cryptic earlier.
Square-bracket indexing for C arrays is what we call “syntactic sugar”–meaning, it exists for human readability, but the C compiler will translate it to two operations: pointer arithmetic followed by dereference:
The expression arr[i] is equivalent to the expression *(arr+i). The latter treats the array name arr as a pointer, increments it, then dereferences.
2.1Example¶
Suppose that when compiled, Program 1 below produces the memory layout in Figure 1. q is a pointer to a 32-bit unsigned integer, while arr is an array, i.e., a 24-byte contiguous block of 32-bit unsigned integers.
1 2 3 4 5 6 7 8 9 10#include <stdio.h> int main () { uint32_t arr[] = {50, 60, 70}; // 32-bit unsigned array uint32_t *q = arr; printf(" *q: %d is %d\n", *q, q[0]); printf("*(q+1): %d is %d\n", *(q+1), q[1]); printf("*(q-1): %d is %d\n", *(q-1), q[-1]); }

Because square-indexing is syntactic sugar for pointer arithmetic and dereference:
Line 4: The pointer
qpoints to an unsigned 32-bit integer at address0x100, which is50. Print*q: 50 is 50.Line 5: Incrementing
qpoints to the next 32-bit unsigned integer. Ifqpoints to the unsigned 32-bit integer at address0x100, then incrementingqpoints to the next 32-bit unsigned integer at address0x104, which is60. Print*(q+1): 60 is 60.Line 6: Because square-bracket indexing is syntactic sugar, negative indexing does not produce any error. Instead, decrementing
qpoints to the previous 32-bit unsigned integer at address0x9c, which is an unknown value. This line would likely print garbage, e.g.,*(q-1): 32490 is 32490.
3Arrays are not pointers¶
From K&R:
There is one difference between an array name [(such as
a)] and a pointer [(such aspa)] that must be kept in mind. A pointer is a variable, sopa=aandpa++are legal. But an array name is not a variable; constructions likea=paanda++are illegal.
Also from K&R:
The name of an array is a synonym for the location of the initial element.
Pointers and arrays therefore differ in how they behave with the address operator, &. Consider Program 2:[1]
1 2 3 4 5 6 7 8 9 10 11 12 13int *p, *q, x; int a[4]; p = &x; q = a + 1; *p = 1; printf("*p:%d, p:%x, &p:%x\n", *p, p, &p); *q = 2; printf("*q:%d, q:%x, &q:%x\n", *q, q, &q); *a = 3; printf("*a:%d, a:%x, &a:%x\n", *a, a, &a);
With the memory layout in Figure 2, the output is:
*p:1, p:108, &p:100
*q:2, q:110, &q:104
*a:3, a:10c, &a:10c
The address of the array a is the address of the array itself, i.e., the address of the large contiguous memory block of ints!
Show Explanation
We discuss multiple declaration in a previous section.
Line 3: The
intpointer,p, is initialized to the address of theintvariablex.Line 6: Take the value
ppoints to; set it to 1.*pdereferencespand gets the value at address0x108, which is1.pis a pointer variable;p’s value is an address, which is0x108.&pis the address of the variablep, which is0x100.
Line 4: The
intpointerqis initialized to the result ofa + 1, which is pointer arithmetic! In the expression, the array nameais the address of the first element ina; incrementing by one yields the address of the second element ofa, at0x110.Line 9: Take the value
qpoints to; set it to 2.*qdereferencesqand gets the value at address0x110, which is2.qis a pointer variable;q’s value is an address, which is0x110.&qis the address of the variableq, which is0x104.
Line 2: The array
ais a memory block of 4ints. The array starts at address0x10c, which is also the address of its first element.Line 12: The array name
ais the address of the first element ina; the statement*a = 3;gets this value and sets it to 3.*ais pointer arithmetic followed by a dereference. The array nameais the address of the first element ina; dereferencing gets the element itself, which is3.ais the address of the first element inaby definition, which is0x10c.&agets the address of the arraya, which is0x10c.[2]
4Array names “decay” with functions¶
When used with functions, arrays decay to pointers in two ways. We use Program 3 below as an example.
1 2 3 4 5 6 7 8 9int bar(int arr[], size_t nelems){ … arr[…] … } int main(void) { int a[5], b[10]; … bar(a, 5); … }
1. When used as formal parameters for function definitions. On Line 2 of Program 3, the definition int arr[] is syntactic sugar for the definition int *arr. We recommend using the latter where possible to avoid confusion.
2. When passed in as arguments to function calls. On Line 7 of Program 3, the argument a is an array but decays to a pointer when the function is called. This decay effectively passes in the address of a as the first argument of bar.
5sizeof with arrays¶
We’ve discussed sizeof many times. For arrays, the compile-time operator will evaluate to the size of the array, in bytes.[2] This observation informs the behavior of Program 4:
1 2 3 4 5 6 7 8 9 10 11void mystery(short arr[], int len) { printf("%d ", len); printf("%d\n", sizeof(arr)); } int main() { short nums[] = {1, 2, 3, 99, 100}; printf("%d ", sizeof(nums)); mystery(nums, sizeof(nums)/sizeof(short)); return 0; }
Show Answer
Print output: 0 5 8
In Line 10,
sizeof(nums)is in array’s declared scope. Evaluate to the total array size of fiveshorts, i.e., 10.In Line 4, the value
lenis the result of evaluatingsizeof(nums)/sizeof(short)inmain, i.e., 10/2 = 5.In Line 8,
arris a function parameter. The formal declarationshort arr[]is syntactic sugar forshort *arr, soarris a pointer. The size of a pointer is 64 bits, sosizeof(arr)is 8.
In practice, C programmers will commonly use sizeof(nums)/sizeof(short) to count the number of elements in the array nums. Note that nums must be declared in the same scope, otherwise it decays to a pointer.
6Arrays are primitive! Reminders¶
Hopefully this section has convinced you that arrays are relatively primitive constructs:
Array declarations set aside contiguous blocks in memory.
Array names are synonymous with the location of the first element in the array.
Arrays decay to pointers when used as function parameters or function arguments.
We close with a few final reminders of how this primitive nature begets responsible C practices.
We thought long and hard about how to explain
&aandsizeof(a)(it involved sitting in a dark room with loud music). Both operations likely boil down to reasonable C design. After all, there must be some way to refer to the address and the size of an array. Instead of erroring, these two expressions are likely the only exception to treating array names as synonymous with the address of the first element. If you, the reader, have a better explanation, we’d love to use it. Submit a pull request!