Посимвольный ввод-вывод работает очень медленно. Это особенно заметно на больших файлах, поэтому, если есть возможность, надо считать как можно больший кусок в память и потом уже проводить с ним манипуляции.
Сами стандартные потоки ввода-вывода имеют внутри себя свой буфер. И по идее все должно быть весьма неплохо. Но когда начинаешь ставить опыты, обнаруживается, что между идеей и реальностью есть некоторые расхождения.
Сам вызов fgetc - это один PUSH в стек при подготовке вызова (если реализация использует передачу параметров через стек). Для fgets это будет уже 3 PUSH-а, но при этом за раз можно считать целую строку, т. е. в расчете на один символ выходит, в среднем, гораздо меньше времени.
Вообще, если интересно, попробуйте сделать программы для подсчета кол-ва символов в файле через fgetc, fgets и read с размером буфера в несколько Мб :) А потом измерьте время, за которое оно сосчитает количество символов в образе DVD или BR диска.