If you really want / need a boolean type, use
<stdbool.h>. If you don’t, just use an
int as much prior code enshrines.
But for the love of all, don’t define your own
TRUE. Remember that only null and zero are falsey, all else being truthy. Defining a constant invites comparison against it, which violates this convention imbued into the language itself.
FALSE while also worrying at least won’t lead to compiling code which is logically wrong. But that is all it has going for itself.
If you have a boolean value to return, return it directly, don’t branch on it and return literals. Unless you are paid by LoC, it’s a pointless obfuscation.
Unless you have a good reason, use boolean operators for boolean logic. Avoiding the short-circuiting is rarely important enough to use bitwise operators instead. And if you use it, remember it doesn’t short-curcuit.
Eliminate dead code to avoid confusing or irritating readers.
return, and the like, additional code in the block without intervening jump-label (in general,
goto is to be avoided, as you do) or
case-label is unreachable.
Initialize on declaration
Unless you want to run under strict C89, (just about) all compilers support mixing declarations and statements, and if you ask for any optimization, the result is generally the same.
Enhancing readability and just about eliminating the chance for a whole class of bugs for no cost is a bargain, right?
See “Is declaration of variables expensive?”.
Help finding bugs
itoa() is out-of-range, that is a programming-error which should be found and fixed in development, never to be seen in release-mode.
assert() is designed for that.
If you really want, you might kill the program in release too, trading efficiency for defense in depth, but don’t ever silently swallow the error. Doing so makes debugging a nightmare.
Doing so enables the compiler to help you find bugs, and makes functions more self-documenting.
restrict where appropriate
Doing so allows the compiler to assume memory is not aliased, eliminating potential dependencies and increasing efficiency, in addition to making functions more self-documenting.
Long lines are hard to read, especially if they lead to wrapping by the editor or horizontal scrolling.
172 is really a bit much, below 80 would be best.
String-literals are easily wrapped, as consecutive ones are merged by the compiler.
What is a string
A string is a sequence of non-nul elements including and terminated by the first nul element.
str@@-functions are expected to handle strings, though there are infamous exceptions.
Single source of truth
The outer dimension of an array is sized according to the initializer if omitted. And you can get it back using
(sizeof *array / sizeof array).
Unless there is a good reason to do otherwise, instead of an array of arrays of fixed length for storing string-literals, consider an array of pointers. It might be more efficient, and eliminates the forced fixed length.
switch and single label
An if-statements seems much more appropriate, as it is simpler.
size_t is the designated type for object-sizes and array-indices. Unless you have a compelling reason, use it.
Don’t blindly assume strings are a minimum number of characters long. Empty strings exist, and out-of-bounds access is generally Undefined Behavior.
Additional comments for specific code
itoa() only supply the minus-sign if the base is 10?
That doesn’t seem to make any sense.
strr() is just bad.
- It looks more like a
mem-function, as it doesn’t treat the input as a string, nor outputs a string.
reverse is very cryptic. Just spell it out.
- Copying elements x to y both exclusive is a very surprising contract. If you don’t use a single length-parameter as expected (the caller can adjust the source-pointer appropriately), I would expect the first to be inclusive.
equstr() is also an acquired taste.
- It is not quite a string-function as it doesn’t terminate the target.
- It really threw me for a loop that it modifies one argument, instead of comparing them, with the semantics of
- nulling out all of a strings elements is rarely needed. Generally, just truncating it by setting the first element to zero is sufficient.
Are you sure anything starting with and ending with
" is a string according to your grammar?
- What about embedded
- What about the length one string
- What about escape-sequences?
- Ramp up the warning level. Your compiler should warn about the path without
- Are you sure only the first character should be tested?
- Are you sure a signed integer must not be negative?
When fixing that, don’t screw up the empty string.
- Where is the dynamic memory allocated freed again?
MAX_STRING_LENGTH seems wasteful.