diff --git a/build.zig b/build.zig index 36668b4..4f9f046 100644 --- a/build.zig +++ b/build.zig @@ -483,6 +483,10 @@ const exercises = [_]Exercise{ .main_file = "095_for_loops.zig", .output = "1 2 4 7 8 11 13 14 16 17 19", }, + .{ + .main_file = "096_memory_allocation.zig", + .output = "Running Average: 0.30 0.25 0.20 0.18 0.22", + }, .{ .main_file = "999_the_end.zig", .output = "\nThis is the end for now!\nWe hope you had fun and were able to learn a lot, so visit us again when the next exercises are available.", diff --git a/exercises/096_memory_allocation.zig b/exercises/096_memory_allocation.zig new file mode 100644 index 0000000..7843b93 --- /dev/null +++ b/exercises/096_memory_allocation.zig @@ -0,0 +1,75 @@ +// In most of the examples so far, the inputs are known at compile +// time, thus the amount of memory used by the program is fixed. +// However, if responding to input whose size is not known at compile +// time, such as: +// - user input via command-line arguments +// - inputs from another program +// +// You'll need to request memory for your program to be allocated by +// your operating system at runtime. +// +// Zig provides several different allocators. In the Zig +// documentation, it recommends the Arena allocator for simple +// programs which allocate once and then exit: +// +// const std = @import("std"); +// +// // memory allocation can fail, so the return type is !void +// pub fn main() !void { +// +// var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); +// defer arena.deinit(); +// +// const allocator = arena.allocator(); +// +// const ptr = try allocator.create(i32); +// std.debug.print("ptr={*}\n", .{ptr}); +// +// const slice_ptr = try allocator.alloc(f64, 5); +// std.debug.print("ptr={*}\n", .{ptr}); +// } + +// Instead of an simple integer or a constant sized slice, this +// program requires a slice to be allocated that is the same size as +// an input array. + +// Given a series of numbers, take the running average. In other +// words, each item N should contain the average of the last N +// elements. + +const std = @import("std"); + +fn runningAverage(arr: []const f64, avg: []f64) void { + var sum: f64 = 0; + + for (0.., arr) |index, val| { + sum += val; + avg[index] = sum / @intToFloat(f64, index + 1); + } +} + +pub fn main() !void { + // pretend this was defined by reading in user input + var arr: []const f64 = &[_]f64{ 0.3, 0.2, 0.1, 0.1, 0.4 }; + + // initialize the allocator + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + + // free the memory on exit + defer arena.deinit(); + + // initialize the allocator + const allocator = arena.allocator(); + + // allocate memory for this array + var avg: []f64 = ???; + + runningAverage(arr, avg); + std.debug.print("Running Average: ", .{}); + for (avg) |val| { + std.debug.print("{d:.2} ", .{val}); + } +} + +// For more details on memory allocation and the different types of +// memory allocators, see https://www.youtube.com/watch?v=vHWiDx_l4V0 diff --git a/patches/patches/096_memory_allocation.patch b/patches/patches/096_memory_allocation.patch new file mode 100644 index 0000000..5398ce5 --- /dev/null +++ b/patches/patches/096_memory_allocation.patch @@ -0,0 +1,4 @@ +65c65 +< var avg: []f64 = ???; +--- +> var avg: []f64 = try allocator.alloc(f64, arr.len);