Why is there output of ping after it has been terminated?

Ctrl+C makes the terminal send SIGINT to the foreground process group. A process that receives SIGINT can do anything, it can even ignore the signal. A common reaction to SIGINT is to exit gracefully, i.e. after cleaning up etc.

Your ping is simply designed to print statistics upon SIGINT and then to exit.

Other tools may not exit upon SIGINT at all. E.g. a usual behavior of an interactive shell (while not running a command) is to clear its command line and redraw the prompt.

SIGINT is not the only signal designed to terminate commands. See the manual (man 7 signal), there are many signals whose default action is to terminate the process. kill sends SIGTERM by default. SIGTERM is not SIGINT. Both can be ignored. SIGKILL cannot be caught, blocked, or ignored, but it should be your last choice.


Additional to the accepted answer - here's ping running in one session, and in another I ran different kill commands.

server~ $ ping google.com
PING google.com (172.217.5.110) 56(84) bytes of data.
64 bytes from google.com(172.217.5.110): icmp_seq=1 ttl=111 time=1.68 ms
64 bytes from google.com(172.217.5.110): icmp_seq=2 ttl=111 time=1.73 ms
Terminated

The above was a SIGTERM, which is signal 15. The exit code was 143.

server ~ $ ping google.com
PING google.com (172.217.5.110) 56(84) bytes of data.
64 bytes from google.com(172.217.5.110): icmp_seq=1 ttl=111 time=1.71 ms
64 bytes from google.com(172.217.5.110): icmp_seq=2 ttl=111 time=1.71 ms
Killed

This was a SIGKILL, which is signal 9. Visually it looks the same, but with a different text, and the exit code is 137 this time.

server~ $ ping google.com
PING google.com (172.217.5.110) 56(84) bytes of data.
64 bytes from google.com(172.217.5.110): icmp_seq=1 ttl=111 time=1.69 ms
64 bytes from google.com(172.217.5.110): icmp_seq=2 ttl=111 time=1.70 ms
           **signal sent here**
--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 1.697/1.701/1.705/0.004 ms

This was a SIGINT which is signal 2. So functionally the same as a ^C Curiously the exit code is 0 which to most tests will be a success, as opposed to a failure.

The upshot of this is that ping does different things for different signals.

You can see a source file for ping at https://gist.github.com/kbaribeau/4495181 which references https://ftp.arl.army.mil/~mike/ping.html as the original.

line
408     signal( SIGINT, finish );
409     signal(SIGALRM, catcher);

457     *           C A T C H E R
459     * This routine causes another PING to be transmitted, and then
460     * schedules another SIGALRM for 1 second from now.

See the link for the full code.