Prototypes are not strictly necessary. Functions must be declared before they are used, and defined (somewhere) if they are used.
Separate declarations allows header files to announce the existence of a function, while another file actually defines it (.c, .cpp, or even a library).
However, if you simply implement a function without a prototype, then the definition is also its own declaration. If it shares the same name as another existing function with a different signature, it simply adds to the overload set (from that point onward) for that name.
Finally, it is not an error to define a function that isn't called. Think about how many functions are declared when you include <iostream>
that you haven't called! Unused functions will not appear in the final resulting artifact being produced.
Problems that can arise occur when you provide multiple definitions for the same function (linker error), or different translation units provide different definitions of inline functions (One Definition Rule (ODR) violation).