Поскольку указатели позволяют вам фактически обращаться к ОЗУ вручную (это невозможно в Java или в «безопасном» C #), и они позволяют вам контролировать распределение объектов.
Переменные, которые «хранят» объекты в C # и Java, действительно содержат указатели (также слабо называемые ссылки ) на объекты в памяти, поэтому классы называются «ссылочными типами». Структуры, напротив, являются «типами значений», поэтому структурные переменные в действительности содержат сами данные. Указатели позволяют динамически выделять и получать доступ к памяти без каких-либо проверок безопасности со стороны компилятора - они дают вам некоторое потенциальное повышение производительности, но они обременяют вас проверкой кода и обеспечением его правильности.
Причина этого немного неуловима: вам нужны указатели, поскольку для использования памяти вам нужно знать размер памяти, который вам нужен во время компиляции. Но, конечно, вы никогда не можете быть уверены, что пользователь не будет пытаться загрузить файл размером 100 МБ в вашу программу, которая была рассчитана только на обработку 20 МБ, и, с другой стороны, вы не можете зарезервировать так много с самого начала (подумайте о том, что произойдет, если все зарезервируют все ресурсы). Таким образом, вы просите операционную систему выделить для вас блок памяти и указать адрес его первого байта, и поэтому нужны указатели. (Существуют и другие способы использования указателей, например отображаемые в памяти файлы и устройства, но это сделает публикацию более длинной.)
В приложениях, критичных к производительности, а также в приложениях, в которых много ошибок, часто используются указатели. :)