Ctrl-C sends the SIGINT signal instead. It can be handled, too, and by default it will terminate the program. Semantics are a little different: you use Ctrl-D when the app expects input, and Ctrl-C when it's actively doing something and you want to interrupt it.
For example, in Python REPL, you can press ^C to interrupt a running piece of code:
>>> while True:
... pass
...
^CTraceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
You can't however exit the REPL with ^C:
>>> (^C)
KeyboardInterrupt
But if you press ^D it exits just fine.
Ruby's irb works the same (and of course Bash/zsh do, too). In Node.js, ^D works right away, and ^C first triggers a warning but you can press it the second time to exit.