0 in the child, and the new child's PID in the parent
fork() returns twice, once in each process. The child gets 0. The parent gets the new child's PID. On failure, fork() returns -1 and no child is created.
"Nothing in the child, because the child starts again from main()" is wrong. The child does not restart from main(). It continues from the same point as the parent, with a copy of the parent's memory. So the return value is the only way each side knows whether it is the parent or the child. "0 in the parent, and the parent's PID in the child" has the values the wrong way round.
If the child wants to run a different program, it then calls execve().