Best practices & idioms for getting user terminal input?

Hey y’all!

I’m trying to take user input from the terminal and I’m just wondering if there are good idioms for doing this in a robust & more flexible way…

Context:

  • I’ve been programming for about a decade and I’m quite comfortable working in higher level languages such as Python, Java, JS etc…
  • I’m new to systems programming in general but I’ve been dabbling in C and Rust on and off for a few years.
  • I’ve been learning Zig for just a few weeks now but already really like it & things are coming together.
  • – I’m still trying to grasp the idioms and concepts of manual memory management, in particular I feel quite shaky on the inner workings of the heap and memory pages and allocators in general.

What I’m focusing on here is trying to reconcile several examples I’ve seen online from the official docs and other random sources concerning needing to assign an input to a []u8 where the size of the []u8 is known at compile time.


const stdin = std.io.getStdIn().reader();
var input: [100]u8 = undefined; // <- this is the line my post is about
    // how do I do this with []u8 instead of [100]u8
    // or how can I dynamically size this variable

std.debug.print("enter something :) {s}", .{""});
_ = try stdin.readUntilDelimiter(&input, '\n');
std.debug.print("The user entered: {s}\n", .{input});

What I’m wondering is…

  1. Is it possible to assign a result of a reader to a variable who’s size is determined by the size of the string deposited by the reader? In other words, to dynamically size the variable being mutated by the reader.

  2. If it is possible, how and what considerations should I be making and are there good idioms / best practices / examples for how I can implement a dynamically sized input variable.

  3. Is it a bad idea? If so, why? Is there a strong case to not do things this way and just commit to a fixed size and try to anticipate the size of the input up front?

Please feel free to include any recommend reading that may help me understand this, especially where memory management is concerned.

Thanks in advance! :nerd_face: :heart: :zap:

Hi @heartbeast42 Welcome to ziggit :slight_smile:

Yes, it is possible.

You don’t preallocate a buffer because the size is not known before calling the reading function.
The reading function must return a newly allocated buffer that fits the entire line.

No, it is not. Usually a fixed buffer can be used when there is an upper bound for reading, or it is not necessary to have the entire line for processing.


The reading function does not know the length of the line, it starts by allocating a fixed buffer (for example of 100 bytes) and reading until either the buffer is full or there is a newline. When the buffer is full it resizes the buffer by expanding it (for example to its double size 200, 400, 800, etc bytes). When the reading or the line is done it returns the allocated buffer with its size as a slice and the caller is responsible for freeing the memory.

The main requirement is to have an allocator, and the allocator job is to allocate, reallocate and free memory.

2 Likes