mirror of
https://codeberg.org/andyscott/ziglings.git
synced 2024-12-22 06:03:09 -05:00
Fix 076, add 077,078 sentinels and many-item pointers
This commit is contained in:
parent
831ee03e32
commit
d4f5684450
7 changed files with 126 additions and 35 deletions
10
build.zig
10
build.zig
|
@ -381,7 +381,15 @@ const exercises = [_]Exercise{
|
|||
},
|
||||
.{
|
||||
.main_file = "076_sentinels.zig",
|
||||
.output = "Array:123056. Many-pointer:123.",
|
||||
.output = "Array:123056. Many-item pointer:123.",
|
||||
},
|
||||
.{
|
||||
.main_file = "077_sentinels2.zig",
|
||||
.output = "Weird Data!",
|
||||
},
|
||||
.{
|
||||
.main_file = "078_sentinels3.zig",
|
||||
.output = "Weird Data!",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
// 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!).
|
||||
// Pointer 'c' is exactly like the many-item 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-item pointer without knowing its length. (We CAN'T do
|
||||
// that with regular many-item pointers!).
|
||||
//
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
|
@ -41,24 +41,25 @@ 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:
|
||||
// And here's a zero-terminated many-item 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.
|
||||
// So now we have a zero-terminated array and a many-item
|
||||
// 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.)
|
||||
// the sentinel 0 in the middle. The many-item pointer must
|
||||
// stop at the first sentinel value. The difference is simply
|
||||
// that arrays have a known length and many-item pointers
|
||||
// don't.)
|
||||
printSequence(nums);
|
||||
printSequence(ptr);
|
||||
|
||||
|
@ -86,7 +87,7 @@ fn printSequence(my_seq: anytype) void {
|
|||
.Pointer => {
|
||||
// Check this out - it's pretty cool:
|
||||
const my_sentinel = my_type.Pointer.sentinel;
|
||||
print("Many-pointer:", .{});
|
||||
print("Many-item pointer:", .{});
|
||||
|
||||
// Loop through the items in my_seq until we hit the
|
||||
// sentinel value.
|
||||
|
@ -100,22 +101,3 @@ fn printSequence(my_seq: anytype) void {
|
|||
}
|
||||
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
|
||||
// ------------------------------------------------------------
|
||||
|
|
66
exercises/077_sentinels2.zig
Normal file
66
exercises/077_sentinels2.zig
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// ------------------------------------------------------------
|
||||
// TOP SECRET TOP SECRET TOP SECRET TOP SECRET TOP SECRET
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// Are you ready for the THE TRUTH about Zig string literals?
|
||||
//
|
||||
// Here it is:
|
||||
//
|
||||
// @TypeOf("foo") == *const [3:0]u8
|
||||
//
|
||||
// Which means a string literal is a "constant pointer to a
|
||||
// zero-terminated (null-terminated) fixed-size array of u8".
|
||||
//
|
||||
// Now you know. You've earned it. Welcome to the secret club!
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
//
|
||||
// Why do we bother using a zero/null sentinel to terminate
|
||||
// strings in Zig when we already have a known length?
|
||||
//
|
||||
// Versatility! Zig strings are compatible with C strings (which
|
||||
// are null-terminated) AND can be coerced to a variety of other
|
||||
// Zig types:
|
||||
//
|
||||
// const a: [5]u8 = "array".*;
|
||||
// const b: *const [16]u8 = "pointer to array";
|
||||
// const c: []const u8 = "slice";
|
||||
// const d: [:0]const u8 = "slice with sentinel";
|
||||
// const e: [*:0]const u8 = "many-item pointer with sentinel";
|
||||
// const f: [*]const u8 = "many-item pointer";
|
||||
//
|
||||
// All but 'f' may be printed. (A many-item pointer without a
|
||||
// sentinel is not safe to print because we don't know where it
|
||||
// ends!)
|
||||
//
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
const WeirdContainer = struct {
|
||||
data: [*]const u8,
|
||||
length: usize,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
// WeirdContainer is an awkward way to house a string.
|
||||
//
|
||||
// Being a many-item pointer (with no sentinel termination),
|
||||
// the 'data' field "loses" the length information AND the
|
||||
// sentinel termination of the string literal "Weird Data!".
|
||||
//
|
||||
// Luckily, the 'length' field makes it possible to still
|
||||
// work with this value.
|
||||
const foo = WeirdContainer {
|
||||
.data = "Weird Data!",
|
||||
.length = 11,
|
||||
};
|
||||
|
||||
// How do we get a printable value from 'foo'? One way is to
|
||||
// turn it into something with a known length. We do have a
|
||||
// length... You've actually solved this problem before!
|
||||
//
|
||||
// Here's a big hint: do you remember how to take a slice?
|
||||
const printable = ???;
|
||||
|
||||
print("{s}\n", .{printable});
|
||||
}
|
27
exercises/078_sentinels3.zig
Normal file
27
exercises/078_sentinels3.zig
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// We were able to get a printable string out of a many-item
|
||||
// pointer by using a slice to assert a specific length.
|
||||
//
|
||||
// But can we ever GO BACK to a sentinel-terminated pointer
|
||||
// after we've "lost" the sentinel in a coercion?
|
||||
//
|
||||
// Yes, we can. Zig's @ptrCast() builtin can do this. Check out
|
||||
// the signature:
|
||||
//
|
||||
// @ptrCast(comptime DestType: type, value: anytype) DestType
|
||||
//
|
||||
// See if you can use it to solve the same many-item pointer
|
||||
// problem, but without needing a length!
|
||||
//
|
||||
const print = @import("std").debug.print;
|
||||
|
||||
pub fn main() void {
|
||||
// Again, we've coerced the sentinel-terminated string to a
|
||||
// many-item pointer, which has no length or sentinel.
|
||||
const data: [*]const u8 = "Weird Data!";
|
||||
|
||||
// Please cast 'data' to 'printable':
|
||||
const printable: [*:0]const u8 = ???;
|
||||
|
||||
print("{s}\n", .{printable});
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
82c82
|
||||
83c83
|
||||
< for (???) |s| {
|
||||
---
|
||||
> for (my_seq) |s| {
|
||||
94c94
|
||||
95c95
|
||||
< while (??? != my_sentinel) {
|
||||
---
|
||||
> while (my_seq[i] != my_sentinel) {
|
||||
|
|
4
patches/patches/077_sentinels2.patch
Normal file
4
patches/patches/077_sentinels2.patch
Normal file
|
@ -0,0 +1,4 @@
|
|||
63c63
|
||||
< const printable = ???;
|
||||
---
|
||||
> const printable = foo.data[0..foo.length];
|
4
patches/patches/078_sentinels3.patch
Normal file
4
patches/patches/078_sentinels3.patch
Normal file
|
@ -0,0 +1,4 @@
|
|||
24c24
|
||||
< const printable: [*:0]const u8 = ???;
|
||||
---
|
||||
> const printable: [*:0]const u8 = @ptrCast([*:0]const u8, data);
|
Loading…
Reference in a new issue