A hádáte se zbytečně. C totiž je těžké. Nejde jen o různé pasti s undefined behavior. Popravdě jste tu zatím všechny ukázky založili na jediné oblasti, čísla se znaménkem.
Hlavní důvod proč je C těžké, je neexistence knihovny standardních datových struktur a masivní použití (často netypovaných void) pointerů.
- C nemá strukturu pro asociativní pole (ať už hash nebo strom)
- C neumí pohlídat přetečení bufferu
- C neumí pohlídat use-after-free
Takže aby programátor neudělal logickou chybu, musí držet v hlavě celý datový model aplikace a vědět, komu patří který pointer, kdo je zodpovědný za uvolnění atd.
Proto vznikají články jako už zmíněný
https://floooh.github.io/2018/06/17/handles-vs-pointers.html , proto máme valgrind (a taky glib nebo Qt/QML pro C++).
Ano, možnost toto všechno řídit ručně umožní vyždímat i poslední kousek výkonu. Tedy možná, protože dnešní procesory jsou tak složité, že optimalizace programátorem naopak stav často zhorší.
Naprostá většina aplikací toto nepotřebuje. Naprostá většina aplikací potřebuje spolehlivou logiku a datový model víc, než optimalizaci na HPC nebo absolutně nejnižší možnou latenci.
C je jen o malý schůdek nad assemblerem. A kolik kódu jste za poslední dekádu napsali v ASM? Obojí se hodí, až když uděláte profiling a zjistíte, že Vás opravdu omezuje funkce na násobení matice nebo něco podobného (
https://www.laws-of-software.com/laws/knuth/ ).
Ale na zbytek aplikace je mnohem vhodnější použít něco, kde se můžete soustředit na to CO to má dělat místo na to, JAK to je implementované na nízké úrovni.
C++ má spoustu podobných pastí, ale alespoň má STL, takže máte smart pointery a nemusíte si psát věci jako Vector nebo iterátory pořád dokola. Rust zase vyžaduje pochopení lifetimes pro jakoukoliv složitější strukturu a je přísný při překladu.