Conflating pointers with arrays.
I don’t mean them using the same syntax, or the implicit conversion of arrays to pointers. I mean the inability to pass an array to a function as an array, even if it is declared to be an array. C will silently convert the array to be a pointer, and will rewrite the function declaration so it is semantically a pointer:
[...]
This seemingly innocuous convenience feature is the root of endless evil. It means that once arrays leave the scope in which they are defined, they become pointers, and lose the information which gives the extent of the array — the array dimension. What are the consequences of losing this information?
An alternative must be used.
For strings, it’s the whole reason for the 0 terminator.
For other arrays, it is inferred programmatically from the context. Naturally, every situation is different, and so an endless array (!) of bugs ensues.
The trainwreck just unfolds in slow motion from there.
The galaxy of C string functions, from the unsafe strcpy() to sprintf() onwards, is a direct result. There are various attempts at fixing this, such as the Safe C Library. Then there are all the buffer overflows, because functions handed a pointer have no idea what the limits are, and no array bounds checking is possible."
PDS: The root of all of this -- is that C, being a low-level, close-to-the-hardware, designed in the 1970's programming language (some in academia pejoratively call it a "glorified assembler"), was not designed with a proper string storage class as we know them in programming languages today; instead, arrays of characters were substituted for this purpose, and those arrays were not implemented containing total size (length) and dimensionality information.
Basically an array in C -- is a set of contiguous memory, which has a starting address (the pointer passed), and a stated element size that the compiler knows about, but not the length (aka, total size, element count, etc.) of that array, nor its dimensionality.
Observation: C's arrays need length information signalled in an out-of-band fashion (that is, this information cannot exist as a zero (0) -- somewhere in the array).
The irony of all of this is that C was invented at AT&T, and AT&T for the longest time had difficulty with phreakers exploiting 2600hz signals to gain access to its long distance trunk lines, from which they could call to anywhere in AT&T's system for free.
But, that's what the engineering error of in-band signaling generates...
C, by using arrays to implement strings, and letting the zero terminator (information about string length) exist in the memory space of the string, made exactly the same engineering mistake -- just in software -- and that is the mistake of in-band signaling.
Now, that being said, hindsight is 2020, and it couldn't be expected that Dennis Ritchie, who invented C in the 1970's would have foreseen the consequences of that engineering "mistake" (AKA, "act which generated quite the education for a future populace". ).
Such is the price of being an innovator.
On the one hand, he advanced computer technology greatly -- far beyond the technology advancements created by most of his contemporaries of his day...
On the other, that advancement gave us this highly educational engineering "mistake" -- that we can all learn from!
Such is the price of being an innovator -- and pressing the "bleeding edge" of what is possible...
Humanity could not be advanced without such innovators, and the occasional future flaws (and the wisdom that comes from examining them in hindsight!) that their innovations generate...