Variable-length arrays#
Activity 37 (Array causes segmentation fault)
Left code causes a segmentation error, but the right one runs fine.
- What is different between two programs? 
- 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.
- Programs’ outputs are not correct. What could be the reason? 
- Where could the difference between the static and stack version come from? 
// 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-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
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#
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;
}
Where can the initialization help in the stack-based code above?
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);
