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 => L3V3RP05TEJTW
hello => HELLOP05���TW
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#
- automatic variable
a local variable which is allocated and deallocated automatically when program flow enters and leaves the variable’s scope.
Automatic variables are typically allocated in the stack memory.
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);