How do I identify which code is legal(meaning compiler will not
produce any errors)? I thought all three were illegal, but was proved
wrong by the compiler.
The compiler cannot decree what is "legal" and "illegal,"
because in most jurisdictions the compiler does not have the
force of law. The compiler cannot fine you, throw you in jail,
or lop off your right hand on account of any code you might
put before it.
That's a bit silly, of course, but it's intended to make a
more serious point: The definition of C is not written with
"thou shalt" and "thou shalt not," but more along the lines of
a contract or agreement: "If thou dost X, the implementation
shall respond as Y."
There are two parties to this contract, and each must keep
up his side of the bargain for the agreement to have meaning.
Your choices of X are restricted to things that the agreement
covers: If you do X' instead, where X' is not part of the agreed
universe of possibilities, the implementation is no longer bound
to keep up its side of the agreement you've abrogated.
Some kinds of out-of-bounds X' require the implementation to
issue a diagnostic message. The implementation may then reject
the program altogether, or may accept it and try to run it anyhow.
(Even if it runs, though, the agreement has been violated and no
longer governs what the program might do.) Some other kinds of
invalid X' produce "undefined behavior," meaning that they may
or may not elicit diagnostics, and they may or may not do what
you hoped they would. ABSENCE OF DIAGNOSTICS IS NOT CORRECTNESS.
To the point at hand: In a hosted environment, part of your
side of the agreement is to provide a main() function in one of
two prescribed styles. Your main() can take no arguments, or it
can take one int and one char** argument; in both cases, it must
be defined as returning an int value. If you fail to provide a
main(), or if you provide a main() of some other flavor, you have
provided an X' and the agreement no longer holds. The compiler
may complain and reject your code, or may complain and accept it,
or may accept it in silence -- but in the latter cases, C itself
does not define what your program may or may not do.