// // A sentinel value indicates the end of data. Let's imagine a // sequence of lowercase letters where uppercase 'S' is the // sentinel, indicating the end of the sequence: // // abcdefS // // If our sequence also allows for uppercase letters, 'S' would // make a terrible sentinel since it could no longer be a regular // value in the sequence: // // abcdQRST // ^-- Oops! The last letter in the sequence is R! // // A popular choice for indicating the end of a string is the // value 0. ASCII and Unicode call this the "Null Character". // // Zig supports sentinel-terminated arrays, slices, and pointers: // // const a: [4:0]u32 = [4:0]u32{1, 2, 3, 4}; // const b: [:0]const u32 = &[4:0]u32{1, 2, 3, 4}; // const c: [*:0]const u32 = &[4:0]u32{1, 2, 3, 4}; // // Array 'a' stores 5 u32 values, the last of which is 0. // However the compiler takes care of this housekeeping detail // for you. You can treat 'a' as a normal array with just 4 // items. // // Slice 'b' is only allowed to point to zero-terminated arrays // but otherwise works just like a normal slice. // // Pointer 'c' is exactly like the many-pointers we learned about // in exercise 054, but it is guaranteed to end in 0. Because of // this guarantee, we can safely find the end of this // many-pointer without knowing its length. (We CAN'T do that // with regular many-pointers!). // const print = @import("std").debug.print; pub fn main() void { // Here's a zero-terminated array of u32 values: var nums = [_:0]u32{ 1, 2, 3, 4, 5, 6 }; // And here's a zero-terminated many-pointer: var ptr: [*:0]u32 = &nums; // For fun, let's replace the value at position 3 with the // sentinel value 0. This seems kind of naughty. nums[3] = 0; // So now we have a zero-terminated array and a many-pointer // that reference the same data: a sequence of numbers that // both ends in and CONTAINS the sentinal value. // // Attempting to loop through and print both of these should // demonstrate how they are similar and different. // // (It turns out that the array prints completely, including // the sentinel 0 in the middle. The many-pointer must stop // at the first sentinel value. The difference is simply that // arrays have a known length and many-pointers don't.) printSequence(nums); printSequence(ptr); print("\n", .{}); } // Here's our generic sequence printing function. It's nearly // complete, but there are a couple missing bits. Please fix // them! fn printSequence(my_seq: anytype) void { const my_type = @typeInfo(@TypeOf(my_seq)); // The TypeInfo contained in my_type is a union. We use a // switch to handle printing the Array or Pointer fields, // depending on which type of my_seq was passed in: switch (my_type) { .Array => { print("Array:", .{}); // Loop through the items in my_seq. for (???) |s| { print("{}", .{s}); } }, .Pointer => { // Check this out - it's pretty cool: const my_sentinel = my_type.Pointer.sentinel; print("Many-pointer:", .{}); // Loop through the items in my_seq until we hit the // sentinel value. var i: usize = 0; while (??? != my_sentinel) { print("{}", .{my_seq[i]}); i += 1; } }, else => unreachable, } print(". ", .{}); } // // ------------------------------------------------------------ // TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET // ------------------------------------------------------------ // // Are you ready for the THE TRUTH about Zig string literals? // // You've earned it. Here it is: // // @TypeOf("foo") == *const [3:0]u8 // // Zig's string literals are constant pointers to zero-terminated // (or "null-terminated") arrays of u8. // // Now you know. Welcome to the secret club! // // ------------------------------------------------------------ // TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET // ------------------------------------------------------------