Указатель - это явный адрес в памяти. С которым ты можешь производить арифметическое действия. Можешь присвоить переменной-указателю другой адрес. И для доступа к значению по этому адресу ты должен явно же использовать операцию разыменования (унарный *).
Проблема указателей в C/C++ именно в возможности выполнения арифметических действий над указателями и в возможности присваивания переменной-указателю любого целочисленного значения. В результате получаем абсолютно бесконтрольный механизм, обеспечивающий произвольный доступ к любой ячейке адресного пространства программы. И любая описка в коде, работающем с указателями, приводит к непредсказуемым трудно обнаруживаемым ошибкам.
Ссылка - тот же указатель, но скрытый. Адрес переменной-ссылке присваивается в момент инициализации и изменён быть не может. Работа с переменной-ссылкой выглядит так же, как с переменной-значением и компилятор сам выполняет разыменование при запросе значения.
Ссылки, в отличие от указателей, контролируются компилятором и допустить ошибку, которая останется компилятором незамеченной, намного сложнее.
Основное использование ссылок - передача параметров в функции.