Variable-length arrays#

Activity 37 (Array causes segmentation fault)

Left code causes a segmentation error, but the right one runs fine.

  1. What is different between two programs?

  2. What could be the problem?

💻💥😵‍💫
#include <stdio.h>
#define SIZE 1024 * 1024 * 8 // ~8 MiB

int main() {
  char arr[SIZE];
  arr[SIZE - 1] = '@';
  printf("%c", arr[SIZE - 1]);
}

Output:

segmentation fault (core dumped)
😌
#include <stdio.h>
#define SIZE 1024 * 1024 * 8 // ~8 MiB
char arr[SIZE];

int main() {
  arr[SIZE - 1] = '@';
  printf("%c", arr[SIZE - 1]);
}

Output:

@

Static- and stack-based memory#

Activity 38 (🤔 Question to ponder)

capitalize_and_print() capitalizes a string and prints it. The following implementation uses a separate memory for output and input. The two examples use static- and stack-based memory.

Look at the outputs of programs below.

  1. Programs’ outputs are not correct. What could be the reason?

  2. Where could the difference between the static and stack version come from?

static
// Static array demonstration
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

//
#define MAX_LENGTH 100
#define ASCII_LOWER_TO_UPPER -32
#define FUNC_CALLING_COUNT 2

char str_input_mem[MAX_LENGTH];
char str_output_mem[MAX_LENGTH];

void capitalize_and_print(char str[]) {
  //
  //
  for (size_t i = 0; i < strlen(str); ++i) {
    if (islower(str[i]))
      str_output_mem[i] = str[i] + ASCII_LOWER_TO_UPPER;
    else
      str_output_mem[i] = str[i];
  }
  printf("%12s => %s\n", str, str_output_mem);
  //
}
int main() {
  for (int i = 0; i < FUNC_CALLING_COUNT; ++i) {
    scanf("%s", str_input_mem);
    capitalize_and_print(str_input_mem);
  }
}
$ printf "l3v3rP05tej\nhello" | code-wi/array_static.exe
 l3v3rP05tej => L3V3RP05TEJ
       hello => HELLOP05TEJ
stack
// Stack-based array demonstration
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

//
#define MAX_LENGTH 100
#define ASCII_LOWER_TO_UPPER -32
#define FUNC_CALLING_COUNT 2

char str_input_mem[MAX_LENGTH];

//
void capitalize_and_print(char str[]) {
  char str_output_mem[strlen(str)];

  for (size_t i = 0; i < strlen(str); ++i) {
    if (islower(str[i]))
      str_output_mem[i] = str[i] + ASCII_LOWER_TO_UPPER;
    else
      str_output_mem[i] = str[i];
  }
  printf("%12s => %s\n", str, str_output_mem);
  //
}
int main() {
  for (int i = 0; i < FUNC_CALLING_COUNT; ++i) {
    scanf("%s", str_input_mem);
    capitalize_and_print(str_input_mem);
  }
}
$ printf "l3v3rP05tej\nhello" | code-wi/array_stack.exe
 l3v3rP05tej => L3V3RP05TEJ,YU
       hello => HELLOP05��,YU
https://upload.wikimedia.org/wikipedia/commons/a/ac/ProgramCallStack2_en.svg

Fig. 19 A representation of the stack memory. Whenever a function is called, then a new frame is created with arguments, data, and return address, which returns back to the place where the function was called – FRAME N-1 for example.
Public domain. By Vectorization: Alhadis. Source: Wikimedia Commons
#

static variable

a variable that lives for the entire time of a program.

stack

regions of memory where data is added or removed in last-in-first-out manner.

Stack-based memory is automatically allocated and released as shown in Fig. 19. To allocate simply means to reserve.

Initializing variable-length arrays#

void f(size_t size) {
    int arr[size] = {};  // {} initializes to zero
    
    // Has the same effect:
    for (size_t i = 0; i < size; ++i)
      arr[i] = 0;
}
🤔 Question to ponder

Where can the initialization help in the stack-based code above?

⚡ Live programming

We will write a function that marks the squares on a board where a knight can move and prints it void print_knights_moves(size_t x, size_t y, size_t board_size);