Array

Introduction

One of the great things about C is that from a single data structure, like an array, you can create much more — such as hash maps, lists, sets, and more. It is up to the developer to model the data from scratch.

In this article, we will focus on mastering arrays.

What is an array?

An array is a linear chunk of memory, for example:

0x001 - array start
...
0x003 - array end

Because an array is continuous, we can instantly jump to any place inside it — we just need to know any address inside the array and an offset:

0x001 - array start
...
0x003 - array end = array start + 3

To determine where each element starts and ends, all elements in an array have the same type. Thanks to this, if the type of the array elements is int16_t, we can access the third element by doing:

start + sizeof(uint16_t) * 3

We like arrays because they are blazingly fast.

Simple array example

Declaring a two-element array:

int array[2];

Declaring and assigning values:

int array[2] = {13, 24};

When you initialize elements immediately, you can skip writing the size:

int array[] = {13, 24};

To get the size of the array in bytes:

printf("%d\n", sizeof(array)); // prints 8

To get the number of elements:

int array[2] = {13, 24};
printf("%d\n", sizeof(array) / sizeof(array[0])); // prints 2

Bonus: Empty initialization

When declaring an array, you can use empty initialization to set all values to 0:

int array[2] = {0};
printf("%d\n", sizeof(array) / sizeof(array[0])); // prints 2

Arrays and pointers

The difficulty with arrays comes from their dual nature. When used as arrays, their size can be measured as shown above. But when they are converted to pointers, you can no longer measure the size of the array — only the size of the pointer:

int array[2] = {13, 24};
int *arrp = array;
printf("sizeof(array)=%d vs sizeof(arrp)=%d\n", sizeof(array), sizeof(arrp));

This gets tricky because the conversion happens automatically. A common example is when passing an array to a function:

#include <stdio.h>

int print_array(int *array, size_t array_len) {
  printf("Array {\n");
  printf("      size: %d", sizeof(array)); // Prints pointer size (e.g., 8), not array size
  printf("      values: ");
  for (size_t i = 0; i < array_len; i++) {
    printf("%d, ", array[i]);
  }
  puts("\n}");

  return 0;
}

int main() {
  int array[32] = {0};
  printf("sizeof(array)=%lu\n", sizeof(array));        // prints 128
  printf("sizeof(array + 0)=%lu\n", sizeof(array + 0)); // prints 8
  print_array(array, sizeof(array) / sizeof(int));
}

An array usually decays to a pointer to its first element. Once it decays, its size is fixed to the pointer size (e.g., 8 bytes on a 64-bit system).

Assigning arrays

Arrays are not directly assignable:

int main() {
  int array[32];
  array = {0}; // Error
}

Also not allowed:

int main() {
  int array[32];
  array = (int[32]){0}; // Error
}

Get Number of elements in array

I know two methods for obtaining number of elements in the array, both are equally good:

size_t arr_size_0 = sizeof(array) / sizeof(int);      // Here we used type size explicitly.
size_t arr_size_1 = sizeof(array) / sizeof(array[0]); // Here we used type size implicitly.

Conclusions

An array is a must-have tool in every C developer’s toolbox. In this article, we went over the basics, laying the groundwork for more advanced array usage.

Published:

Category: C

Comments

Leave a comment