A parent process can suspend its execution to wait for termination of a child process with wait or waitpid. More often, the parent wants to wait for the child to terminate before continuing itself as follows:
if (fork() == 0) execl( ... ); wait(&status);
The previous code fragment avoids handling any abnormal conditions, such as a failure of the execl or fork, or the possibility that there might be more than one child running simultaneously. (The function wait returns the process-id of the terminated child, which can be checked against the value returned by fork.) In addition, this fragment avoids dealing with any funny behavior on the part of the child (which is reported in status).
The low-order eight bits of the value returned by wait encodes the termination status of the child process; 0 signifies normal termination and non-zero to signify various kinds of abnormalities. The next higher eight bits are taken from the argument of the call to exit which caused a normal termination of the child process. It is good coding practice for all programs to return meaningful status.
When a program is called by the shell, the three file-descriptors are available for use. When this program calls another one, correct etiquette suggest making sure the same conditions hold. Neither fork nor the exec calls affects open files in any way. If the parent is buffering output that must come out before output from the child, the parent must flush its buffers before the execl. Conversely, if a caller buffers an input stream, the called program loses any information that has been read by the caller.