Created: 2023-01-11 12:48
Status: #concept
Subject: Programming
Tags: C C Data Type Aggregate Multidimensional Arrays

C Array

It is a derived data structure/type that holds values (also known as elements) of the same type found in different indices.

In C, Array names are const Pointers and their Memory Addresses cannot be edited.

  • we can assign the first element of the array to a pointer like *p = array.

An array of Characters in C turns into a C String with the Null Terminator as the last character.

Row-Major Order

For Example, here is a One-Dimensional Array named a:
One-Dimensional Array Illustration.png

int a[10]; // (data type) identifier[size]

#define STR_MAX 100
char string[MAX]; // we can also use expressions like Macro Definitions

int a[3] = {1, 2, 3}; // we can also use an Initializer List
int a[] = {1, 2, 3}; // or automatically derive the size
int a[3] = {[1] = 2, [2] = 3}; // we can also use Designators to initialize specific indices

Array Declaration in C.png

Accessing Elements

We can access arrays in two common ways; with a specific array[index] or by Dereferencing an array's address with Pointer Arithmetic like *(array + index).

Accessing the element of an array beyond its allocated range of Memory Addresses will result to a Segmentation Fault.

Array Subscripting (indexing)

The elements of an array are numbered from 0 to n - 1, where n is the array's length.

  • Expressions of the form array[index] are Lvalues, meaning they can be used the same way as ordinary Variables.
  • By extension of that, we can also use Characters to index arrays.

a[0] = 1; // to assign values to it
printf("%d\n", a[5]); // to use as a variable in expressions
++a[i]; // to increment or decrement
a['A']; // accesses position 65, the ASCII value of 'A'

Dereferencing Array Addresses

When we do arr[k], we are actually doing *(arr+k) with Pointer Arithmetic.

  • by extension of that, k[arr] is *(k+arr), meaning they are commutative.
  • meanwhile arr + 1 is equivalent to &arr[1].
  • therefore, the name of the array decays to a pointer to the first element of the array.

int a[10]; // given the address a, offset 10 elements (not bytes) from that address and then dereference the result.

*a = 7; // stores 7 in a[0], *a === a[0], a === &a[0]

*(a+1) = 12; // stores 12 in a[1]

sizeof Operator Behavior

Using the sizeof Operator helps us determine the number of elements in an array (the array length).

  • sizeof (array) returns the size of the array (in Bytes).

sizeof(arr) / sizeof(arr[0]) evaluates to the length of arr.

// sets the values of an array with unknown size to 0
for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) 
  a[i] = 0;

Copying Array Elements

Since arrays are just chunks of Memory Addresses, we can copy multiple addresses from one place to another with memcpy.

  • void *memcpy(void *dest, const void *src, size_t n)

#define MAX_LEN 3

int a[MAX_LEN] = {1,2,3};
int b[MAX_LEN] = {0,0,0};

memcpy(a, b, sizeof(a)); // copies the elements from b to a
memcpy(a, b, MAX_LEN * sizeof(a[0])); // equivalent

// or we can use a loop
for (int i = 0; i < MAX_LEN; i++) {
  a[i] = b[i];
}

References