- an integrated build system that doesn't use multiple separate arcane tools and languages
- slices with known length in Zig vs arrays in C (buffer overflows)
- an explicit optional type that you're forced to check, null pointers aren't* allowed (*when they are, for integrating with C code, the type makes that obviously clear)
- enums, tagged unions and enforced exhaustive checks on "switch" expressions
- error handling is explicit, functions return an error (an enum value) that the caller must handle in some way. In C the function might return some integer to indicate an error which you're allowed to completely ignore. What is missing is a standard way of returning some data with an error that's built into the language (the error-struct-passed-through-parameters pattern feels bolted on, there should be special syntax for it)
- "defer", "errdefer" blocks for cleanup after function returns or errors
- comptime code generation (in Zig) instead of macros, type reflection (@typeInfo and friends)
- caller typically makes decisions about how and where memory is allocated by passing an allocator to libraries
- easier (at least for a noob) to find memory leaks by just using GeneralPurposeAllocator
As someone who's always used higher level languages since I started programming and strongly disliked many of the arcane, counterintuitive things about C and surrounding ecosystem whenever I tried it, Zig finally got me into systems programming in a way that I find enjoyable.