summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--build.zig10
-rw-r--r--exercises/076_sentinels.zig46
-rw-r--r--exercises/077_sentinels2.zig66
-rw-r--r--exercises/078_sentinels3.zig27
-rw-r--r--patches/patches/076_sentinels.patch4
-rw-r--r--patches/patches/077_sentinels2.patch4
-rw-r--r--patches/patches/078_sentinels3.patch4
7 files changed, 126 insertions, 35 deletions
diff --git a/build.zig b/build.zig
index 2489e2a..391da47 100644
--- a/build.zig
+++ b/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!",
},
};
diff --git a/exercises/076_sentinels.zig b/exercises/076_sentinels.zig
index 4cd25e9..4c16e7c 100644
--- a/exercises/076_sentinels.zig
+++ b/exercises/076_sentinels.zig
@@ -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
-// ------------------------------------------------------------
diff --git a/exercises/077_sentinels2.zig b/exercises/077_sentinels2.zig
new file mode 100644
index 0000000..7a03dcd
--- /dev/null
+++ b/exercises/077_sentinels2.zig
@@ -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});
+}
diff --git a/exercises/078_sentinels3.zig b/exercises/078_sentinels3.zig
new file mode 100644
index 0000000..bad4810
--- /dev/null
+++ b/exercises/078_sentinels3.zig
@@ -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});
+}
diff --git a/patches/patches/076_sentinels.patch b/patches/patches/076_sentinels.patch
index 52a5424..33e4483 100644
--- a/patches/patches/076_sentinels.patch
+++ b/patches/patches/076_sentinels.patch
@@ -1,8 +1,8 @@
-82c82
+83c83
< for (???) |s| {
---
> for (my_seq) |s| {
-94c94
+95c95
< while (??? != my_sentinel) {
---
> while (my_seq[i] != my_sentinel) {
diff --git a/patches/patches/077_sentinels2.patch b/patches/patches/077_sentinels2.patch
new file mode 100644
index 0000000..4fef677
--- /dev/null
+++ b/patches/patches/077_sentinels2.patch
@@ -0,0 +1,4 @@
+63c63
+< const printable = ???;
+---
+> const printable = foo.data[0..foo.length];
diff --git a/patches/patches/078_sentinels3.patch b/patches/patches/078_sentinels3.patch
new file mode 100644
index 0000000..94257b0
--- /dev/null
+++ b/patches/patches/078_sentinels3.patch
@@ -0,0 +1,4 @@
+24c24
+< const printable: [*:0]const u8 = ???;
+---
+> const printable: [*:0]const u8 = @ptrCast([*:0]const u8, data);