Yes, the file descriptor of the child process has indeed been released, but the biggest reason for closing the file descriptor is because of the existence of the buffering mechanism. If it is not closed, incomplete data will be written. Of course, there are other reasons. After the exec function, it can be considered a new process. Everything is new except the process identifier. The file descriptor is maintained by the process, but the process descriptor is just a pointer-like thing. What it really points to is maintained by the kernel. In the file table, only the file descriptors are recycled. If the file table entries are not recycled, it is the same as a memory leak.
Yes, the file descriptor of the child process has indeed been released, but the biggest reason for closing the file descriptor is because of the existence of the buffering mechanism. If it is not closed, incomplete data will be written. Of course, there are other reasons. After the exec function, it can be considered a new process. Everything is new except the process identifier. The file descriptor is maintained by the process, but the process descriptor is just a pointer-like thing. What it really points to is maintained by the kernel. In the file table, only the file descriptors are recycled. If the file table entries are not recycled, it is the same as a memory leak.
Please refer to close_on_exec
As you said, if the child process does not close the file descriptor, it can still be used after exec, such as 0, 1, 2