Programming in C

C-Arrays

Gerald Senarclens de Grancy

Purpose of C-Arrays

Which Problems do C-Arrays solve?

  • Arrays allow storing many elements of the same type
  • These elements can be passed to a function together
  • The number of elements does not have to be known upfront (only C99)

Which Problems do C-Arrays Cause?

  • Arrays only store the memory address of their beginning
  • Passing arrays to functions requires passing their size as well
  • The memory address an array variable references cannot be changed
  • Not all C compilers support dynamically sized arrays on the stack
  • Arrays cannot be directly returned from functions

What is a C-Array?

A reference to the beginning of consecutive memory of a given type

int numbers[] = {32, 45, 12, 39, 7, 15};
Index 0 1 2 3 4 5
Value 32 45 12 39 7 15
Address 0x7fc8c013e0 0x7fc8c013e4 0x...e8 0x...ec 0x...f0 0x...f4

The index is the offset of the referenced memory.

The first element has index 0.

0 means that there is no offset from the beginning of the referenced memory.

Array Subscription

Subscription is the selection of an element using its index.

int points[] = {32, 45, 12, 39, 7, 15};
int value = points[2]; // access third element with the subscript operator
points[0] = 50; // write to first element with the subscript operator

Working with C-Arrays

Creating an Array of Constant Size

#include <stdio.h>

int main() {
unsigned int numbers[3]; // number of elements known at compile time
numbers[0] = 15;
numbers[2] = 5;
numbers[1] = 10;
printf("{ %d, %d, %d }", numbers[0], numbers[1], numbers[2]);
return 0;
}

Visualize execution

Create Dynamically Sized Array

... supported by compilers that fully implement the C99 standard.

Other compilers require the use of dynamic memory management.

#include <stdio.h>

int main() {
size_t count = 5; // entered by the user
unsigned int squares[count];
for (size_t i = 0; i < count; ++i) {
squares[i] = i * i;
}
for (size_t i = 0; i < count; ++i) printf("%u\n", squares[i]);
return 0;
}

Visualize execution

Determine the Number of Elements

The compiler can determine the number of elements if the array was declared in the current scope.

The sizeof operator returns the total memory in bytes.

#include <stdio.h>

int main() {
int values[] = {-5, 39, 13, -21}; // compiler determines number of elements
printf("used memory: %ld\n", sizeof(values));
printf("number of elements: %ld\n", sizeof(values) / sizeof(int));
return 0;
}

Visualize execution

Pass the Number of Elements When Passing an Array to a Function

#include <stdio.h>

void print_info(int values[], size_t count) { // values is actually a pointer
// sizeof returns the size of the pointer (64 bits on modern systems)
printf("sizeof(values): %ld\n", sizeof(values));
printf("sizeof(values) / sizeof(int): %ld\n", sizeof(values) / sizeof(int));
// only way to know the number of elements is a separate argument
printf("number of elements: %ld\n", count);
}

int main() {
int values[] = {-5, 39, 13, -21}; // compiler determines number of elements
printf("sizeof(values): %ld\n", sizeof(values));
printf("sizeof(values) / sizeof(int): %ld\n", sizeof(values) / sizeof(int));
print_info(values, sizeof(values) / sizeof(int));
return 0;
}

Visualize execution

Arrays Are Not Assignable

#include <stdio.h>

int main() {
int first[] = {1, 2, 3};
int second[] = {4, 5, 6};
first = second; // compiler error: array type is not assignable
first = {7, 8, 9}; // also a compiler error
printf("{ %d, %d, %d }", first[0], first[1], first[2]);
return 0;
}
Download not_assignable.c

Returning an Array from a Function

It is not possible to directly return an array from a function.

Its memory would be on the stack and the returned reference invalid.

There are three possible approaches

  • Workaround: pass array as argument (use caller's stack memory)
  • Workaround: create static array (preserve memory between calls)
    (requires pointers)
  • Solution: return pointer to array on the free store
    (requires pointers and dynamic memory management)

Pass Array as an Argument

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

void read_values(int values[], size_t count) {
srand(time(NULL)); // Initialize random number generator
for (size_t i = 0; i < count; ++i) {
values[i] = rand(); // assume the values are read from user input
}
}

int main() {
int values[3]; // number of elements known at compile time
read_values(values, 3);
printf("{ %d, %d, %d }\n", values[0], values[1], values[2]);
return 0;
}

Visualize execution

Questions
and feedback...