If you’re used to writing code in C,adding a pointer field might feel trivial—but remember that you’re still managing lifetime manually.
This new field introduces anor point of failure: pointer may outlive buffer it points into if you’re not careful about when you read next file.
The above snippet shows how location field is added and assigned during scanning.
Pain Point – Shared Buffer Bug:
• If you process multiple files sequentially and store each result。every `Mistake.location` will point into same shared buffer `buf`. When you read next file,you overwrite `buf`,and all previous results now reference wrong contents.
• In plain C this manifests as a subtle bug: pointers are still valid but y refer to unexpected data—exactly what makes debugging memory bugs so painful.
• In Rust,this kind of bug would surface at compile time because borrow checker tracks lifetimes of references.
Copying error snippets
c
size_t location_len = len - i;if {
location_len = 12;}
m->location = malloc;memcpy,m->location = '\0';其实,This fixes shared-buffer issue by giving each `Mistake` its own copy of context string.
Memory leak issue
c
for {
free;free,}
You must remember both allocations and ir correct order—anor source of bugs.
Fixed array upper bound problem
c
struct CheckResult results;If more than `MAX_RESULTS` files are checked simultaneously,you get an out-of-bounds write—a hard-to-detect bug in production.
Summary of C challenges
shared buffer → stale pointers → incorrect errors
manual allocation → leaks or double frees → runtime crashes
fixed array size → overflow → undefined behavior
These problems arise because every detail—ownership。lifetime,deallocation order—is tracked only mentally by programmer.
Rust rewrite – first step: robust file reading
rust
use std::fs::read_to_string;fn main -> Result<, std::io::Error>{
let s = read_to_string?,// …Ok)
}
Rust forces handling I/O errors via `Result`,so you can’t ignore m like in naive C code.
Using Option instead of NULL for optional mistakes
rust
let result = s.find;// returns Option
match result {
Some => println!,None => println!,}
Here missing values are explicit rar than implicit . This eliminates whole classes of null-pointer bugs.
Borrowing slices for error context – no manual copy needed
rust
let slice = &s;println,;// slice is &str reference into original string
Slices don’t allocate—y just borrow part of an existing string—and y carry lifetimes that guarantee safety.
Lifetime annotations prevent dangling references when returning from functions
rust
struct Mistake<'a>{ location:&'a str }
fn check<'a> -> Result