Learning Zig

Hello guys, this is my first time learning Zig and programming. Why I am getting stuck at while loop in this code below if I typing let say “Jack”, sorry If my question doesn’t make sense and sorry my English is not that good.

const std = @import("std");
const File = std.Io.File;

pub fn main(init: std.process.Init) !void {
    const io = init.io;

    var stdout_buffer: [4096]u8 = undefined;
    var stdout_writer = File.stdout().writer(io, &stdout_buffer);
    const stdout = &stdout_writer.interface;

    var stdin_buffer: [4096]u8 = undefined;
    var stdin_reader = File.stdin().reader(io, &stdin_buffer);
    const stdin = &stdin_reader.interface;

    while (true) {
        try stdout.print("Enter your name: ", .{});
        try stdout.flush();

        const line = try stdin.takeDelimiterExclusive('\n');
        const name = std.mem.trim(u8, line, "\r\n");

        if (std.mem.eql(u8, name, "John")) {
            try stdout.print("My name is {s}\n", .{name});
            try stdout.flush();
            break;
        }
    }
}

1 Like

You’re using takeDelimiterExclusive, so what you’re taking never includes the delimiter (it’s excluded, per the name of the method). So, your reading never progresses past the first delimiter: it is never “taken”.

You’ll want to use takeDelimiterInclusive (depending on Zig version these may be named differently, such as takeDelimiter). This also renders doing the trimming sensible.

2 Likes

Whoa, okay that’s work really well.

I have question if you don’t mind. The delimiter is “\n” right? so, let say I typing “Jack” if I’m using takeDelimiterInclusiveI should get the value “Jack\n” right? but why if I’m using takeDelimiterExclusive I got the value of empty string ““?

Thank you for the reply!

2 Likes

You’re getting that on the second call because the data to be read next, that is, the data not yet taken, is still \n. It must be taken to read the data that follows.

1 Like

takeDelimiterExclusive takes everything before the \n.
take the data "jack\n", the first time you will get "jack".
Now the abstract reader state is (where | is the “cursor” of the reader), "jack|\n".
You can see that next time it will immediate find the \n, and since there is nothing between the cursor and the delimiter, it returns an empty slice.
It will also cause an infinite loop as the delimiters are never read.

3 Likes

There are 3 functions:

takeDelimiter is exactly behavior you need. It skips delimited and doesn’t include it in returned slice.
takeDelimiterInclusive will include delimiter in returned slice but advances past delimiter.
takeDelimiterExclusive will not advance past delimiter and wont include it in slice.

5 Likes

In your code, after reading, you can use stdin.toss(1), but it’s better to use stdin.takeDelimiter, as AndrewKraevskii advised above.