&gt; Use `signed char` for strings<p>If you&#x27;re dealing with POSIX &#x2F; the C stdlib, mirror it and use char* . (The string version of &quot;Respect the integer types used by each API.&quot;; if you&#x27;re coding for Windows you&#x27;ll likely need to use LPWSTR or whatever they call it now.) But: if you&#x27;re storing UTF-8 string data, you _want_ unsigned char (and maybe uint8_t[2]): if start trying to inspect the code units, esp. to decode them to code points, you&#x27;re going to need to do comparisons and bit manipulations on them, and its too easy to write `code_unit &lt; 0x80` or something similarly silly (e.g., while masking bits to see if it&#x27;s a continuation byte). It&#x27;s like the article early today called &quot;Should I use Signed or Unsigned&quot;[1] states: &quot;Prefer unsigned when using bitwise operators&quot;.<p>&gt; Limit recursion<p>Recursion is fine; you simply need to be aware of your worst case stack depth. You&#x27;re looking, really, for the complexity of your stack usage, or the big-oh of your stack size. If you&#x27;re doing something like recursing down an in-memory <i>balanced</i> binary tree, it&#x27;s O(log(n)) in the worst case: ~64 stack frames on a 64-bit CPU. Can you fit that many on the stack? Certainly that&#x27;s heavier than a normal function call, but it&#x27;s still a finite, computable size.<p>If you can&#x27;t compute that &#x2F; prove an upper bound, then I agree.<p>&gt; Aside: any language that uses keywords like public and private to determine visibility instead of placement&#x2F;scoping is bad<p>If not with keywords, how should visibility be determined? (How does &quot;placement&#x2F;scoping&quot; determine visibility?)<p>&gt; Use get&#x2F;init or create&#x2F;copy&#x2F;alloc in function names to indicate ownership versus borrowing for return values<p>Inevitable, I feel like you end up creating some structure, let&#x27;s call it a Foo. So you then have a Foo * Foo_create(), a Foo_destroy(Foo * ). Some action performable on Foo? Foo_reticulate_splines(Foo* , …). Combined with,<p>&gt; You should generally track used and unused space in dynamic arrays,<p>and the overhead of writing functionality to deal with dynamic arrays in C, the entire section about managing strings, and you&#x27;ve come to the very reason I left C: I&#x27;m already writing C++. Foo_create is a ctor; Foo_destroy a dtor; Foo_reticulate_splines a member function. Combined with vectors &amp; strings taking care of day-to-day memory management, and I&#x27;m left with little reason to use C.[3] RAII adds some degree of object lifetime management that simply isn&#x27;t present in C (but does not add the compile-time checks that I&#x27;m starting to love Rust for.)<p>[1]: <a href="http:&#x2F;&#x2F;blog.robertelder.org&#x2F;signed-or-unsigned-part-2&#x2F;" rel="nofollow">http:&#x2F;&#x2F;blog.robertelder.org&#x2F;signed-or-unsigned-part-2&#x2F;</a><p>[2]: I know C++ got some decent types for Unicode _very_ recently; I&#x27;m not aware if C got those.<p>[3]: I am <i>not</i> suggesting C++ to be the language you _should_ be using. I simply cannot justify ever using C over it.