Names specified here
Name Description Notes Source Availability
__STDC_NO_VLA__ Indicator of lack of support for variable-length arrays L ? M Predefined C99 C11
atomic_ptrdiff_t Atomic integer type ? T <stdatomic.h> C11
PTRDIFF_MAX Maximum value of ptrdiff_t H M <stdint.h> C99 C11
PTRDIFF_MIN Minimum value of ptrdiff_t H M <stdint.h> C99 C11
ptrdiff_t Implementation-defined pointer-difference type H T <stddef.h> C89 C90 C95 C99 C11
static Specifier for minimum array length L Keyword C99 C11

An array is an object consisting of a sequence of adjacent objects all of the same type, which is the array's element type. For every complete type T, and for every array length n of unsigned integer type, there is an array type T [n], which is also complete. To declare an array, place the array name between the type and the length. For example, an array of 10 ints is declared:

int my_arr[10];

After an array has been declared, its length cannot change. Before C99, or if __STDC_NO_VLA__ is defined as 1, the length must also be a constant expression, whereby this is illegal:

int x = 10;
int my_arr[x];

Any element of the array can be accessed by specifying its index. For example, to set the example array to a sequence of square numbers:

int my_arr[10];
int i;
for (i = 0; i < 10; i++)
  my_arr[i] = i * i;

To print the current values:

int my_arr[10];
int i;
for (i = 0; i < 10; i++)
  printf("elem %d = %d\n", i, my_arr[i]);

The index in [ ] can be any integer expression, and the expression my_arr[i] is an object just like any other. It has a size sizeof my_arr[i], an address &my_arr[i], and type int.

The size of an array is the size of the element type times the length of the array. Therefore, the length of an array can be computed with an expression such as:

size_t len = sizeof arr / sizeof arr[0];

If you have the address of an array element, you can find the address of the next element by adding 1, or the address of the previous element by subtracting 1. You can get the address of any element from any other by adding or subtracting the difference between their indices:

int my_arr[10];
assert(&my_arr[4] + 2 == &my_arr[6]);

You don't have to multiply by the size of the element type; this will be quietly done for you.

Pointer arithmetic

The name of an array, except in expressions such as sizeof my_arr and &my_arr, yields the address of its first element, so my_arr == &my_arr[0], and my_arr + 3 == &my_arr[3]. It is said that the array name decays into a pointer to its first element. The construct [] is in fact a binary operator. One of its operands must be an object pointer, and the other an integer, and it simply adds them together, regardless of order, then dereferences. This means that the two expressions my_addr[3] and 3[my_addr] are equivalent!

Given the addresses of two elements of the same array, the address of one can be subtracted from the address of the other, yielding the difference of their indices:

int my_arr[10];
assert(&my_arr[6] - &my_arr[4] == 2);

The result is of a signed integer type called ptrdiff_t, defined in <stddef.h>, and having the range from PTRDIFF_MIN to PTRDIFF_MAX, which is at least ±65535. Use the type modifier t on integer conversion specifiers with printf and scanf to convert a ptrdiff_t to and from characters (for example, "%td").

atomic_ptrdiff_t is an alias for _Atomic ptrdiff_t.

Array initialization

An array can be initialized by listing the element values in braces:

int my_arr[10] = {
  4, 8, 23, 4, 3,
  7, 3, -3, 12, -7
};

If the length can be inferred from the initializer, it doesn't need to be explicit:

int my_arr[] = {
  4, 8, 23, 4, 3,
  7, 3, -3, 12, -7
};

If the length is greater than the initializer, the remaining elements are assumed to be zero:

int my_arr[10] = {
  4, 8, 23, 4, 3,
};

From C99, you can initialize non-sequentially. For example:

int my_arr[] = {
  [2] = 23,
  [8] = 12,
};

Again, unspecified elements are taken as zero. Values without an explicit index are assigned to the next non-explicitly indexed element. [Statement to be checked.]

Arrays as function parameters

A function parameter can be declared as an array, but it is treated as a pointer to the element type. Also, if an array length is given, it is usually ignored. These three prototypes are therefore equivalent:

int array_sum(int arr[], size_t len);
int array_sum(int arr[20], size_t len);
int array_sum(int *arr, size_t len);

Note that, with the length in the prototype being ignored anyway, the array's actual length must be inferred some other way, e.g., by passing it as a separate parameter len.

Whether a parameter was declared as an array or a pointer, the function can use it as if it were an array:

int array_sum(int *arr, size_t len)
{
  int sum = 0, i;
  for (i = 0; i < len; i++)
    sum += arr[i];
  return sum;
}

The expression arr[i] is equivalent to *(arr + i). Due to pointer arithmetic, this then accesses the intended element. The caller may pass a whole array to the function, or just a part of it:

int arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < 10; i++) {
  for (int j = i; j < 10; j++) {
    printf("Sum from %d to %d: %d\n",
           i, j, array_sum(&arr[i], j - i));
  }
}

The function remains unaware that the supplied pointer isn't necessarily the start of the array. It will even work when passed a pointer to an object which is not part of an array, provided you specify a length of one.

From C99, the keyword static can be used to indicate a minimum size for any provided argument:

int array_sum(int arr[static 20], size_t len);

The behaviour is undefined if an array of at least 20 elements is not provided.

Multidimensional arrays

As an array type such as int[10] is a complete type, it can also be the element type of another array type. For example, this declares four arrays of ten ints:

int my_arr[4][10];

As before, to access an element, each index may be any integer expression. To print all elements in a grid:

int i, j;
for (i = 0; i < 4; i++) {
  for (j = 0; i < 10; j++) {
    printf(" %3d", my_arr[i][j]);
  }
  printf("\n");
}

Such arrays of arrays are often referred to as multidimensional arrays, which is what they can usually be used as, even though it's not technically accurate. They can be passed to functions, but only the first dimension length can be omitted:

void print_array(size_t d1len, int arr[][10]);

The other dimensions must match exactly:

int my_arr1[4][10];
int my_arr2[4][20];

print_array(4, my_arr1); // okay
print_array(4, my_arr2); // error

From C99, and if __STDC_NO_VLA__ is not defined, the lengths of the other dimensions can be passed as separate parameters:

void print_array_2d(size_t d1len, size_t d2len, int arr[][d2len])
{
  for (size_t i = 0; i < d1len; i++) {
    for (size_t j = 0; i < d2len; j++) {
      printf(" %3d", my_arr[i][j]);
    }
    printf("\n");
  }
}

For the sake of self-documentation, the first dimension can be listed too:

void print_array2d(size_t d1len, size_t d2len, int arr[d1len][d2len]);

Array type aliases

Aliases can be declared for array types. As with all aliases, consider a declaration of an object of the type you intend to alias, change its name to the alias, and add typedef:

typedef int ai10[10];
int array_sum(ai10 arr, size_t len);

When used in a declaration, the alias is expanded to the type it represents before other array-related transformations occur, so the declaration of array_sum first transforms into this:

int array_sum(int arr[10], size_t len);

…and then this:

int array_sum(int *arr, size_t len);

CHaR
Sitemap Supported
Site format updated 2024-06-05T22:37:07.391+0000
Data updated 1970-01-01T00:00:00.000+0000
Page updated 2022-06-17T21:43:05.000+0000