Держу пари, что если быть кратким, то это было просто дизайнерское решение.Более конкретно, если вы действительно хотите знать почему, вам нужно работать с нуля.
Давайте сначала подумаем о C.В языке C существует четкое различие между «передачей по ссылке» и «передачей по значению».Проще говоря, имя массива в C на самом деле просто указатель.Для всех намерений и целей разница (как правило) сводится к распределению.Код
int array[n];
создаст 4 * n байтов памяти (в 32-битной системе) в стеке, что соответствует объему любого блока кода, который делает объявление.В свою очередь,
int* array = (int*) malloc(sizeof(int)*n);
создаст такой же объем памяти, но в куче.В этом случае то, что находится в этой памяти, не связано с областью, только ссылка на память ограничена областью.Здесь происходит передача по значению и передача по ссылке. Как вы, вероятно, знаете, передача по значению означает, что когда что-то передается или возвращается из функции, то «вещь», которая передается, является результатом вычисления переменной.Другими словами,
int n = 4;
printf("%d", n);
напечатает число 4, потому что конструкция n
оценивается как 4 (извините, если это элементарно, я просто хочу охватить все основания).Эта четверка не имеет абсолютно никакого отношения к пространству памяти вашей программы и не имеет отношения к ней, это всего лишь литерал, и поэтому, как только вы покинете область, в которой эта четверка имеет контекст, вы потеряете ее.Как насчет передачи по ссылке?Передача по ссылке ничем не отличается в контексте функции;Вы просто оцениваете конструкцию, которая передается.Единственное отличие состоит в том, что после оценки переданной «вещи» вы используете результат оценки в качестве адреса памяти.У меня когда-то был один циничный инструктор по CS, который любил утверждать, что нет такой вещи, как передача по ссылке, просто способ передать умные значения.На самом деле он прав.Итак, теперь мы думаем о сфере с точки зрения функции.Представьте, что у вас может быть тип возвращаемого массива:
int[] foo(args){
result[n];
// Some code
return result;
}
Проблема здесь в том, что результат оценивается по адресу 0-го элемента массива.Но когда вы пытаетесь получить доступ к этой памяти извне этой функции (через возвращаемое значение), у вас возникает проблема, потому что вы пытаетесь получить доступ к памяти, которая находится вне области действия, с которой вы работаете (стек вызова функции).Таким образом, мы можем обойти это с помощью стандартной jiggery-pokery «передачи по ссылке»:
int* foo(args){
int* result = (int*) malloc(sizeof(int)*n));
// Some code
return result;
}
Мы все еще получаем адрес памяти, указывающий на 0-й элемент массива, но теперь у нас есть доступ кэто воспоминание.
Что я имею в виду?В Java принято утверждать, что «все передается по значению».Это правда.Тот же самый циничный инструктор из вышеупомянутого также говорил о Java и ООП в целом: все является лишь указателем.И он тоже прав.Хотя все в Java фактически передается по значению, почти все эти значения на самом деле являются адресами памяти.Таким образом, в Java язык позволяет вам возвращать массив или строку, но он делает это, превращая его в версию с указателями для вас.Он также управляет вашей памятью для вас.А автоматическое управление памятью, хотя и полезно, но неэффективно.
Это приводит нас к C ++. Единственная причина, по которой был изобретен С ++, заключалась в том, что Бьярн Страуструп экспериментировал с Симулой (в основном оригинальным OOPL) во время своей докторской работы и думал, что это было фантастически концептуально, но он заметил, что он работал довольно ужасно. И поэтому он начал работать над тем, что называлось C с классами, которое было переименовано в C ++. При этом его целью было создать язык программирования, который бы использовал НЕКОТОРЫЕ из лучших функций Simula, но оставался мощным и быстрым. Он решил расширить C из-за его и без того легендарной производительности, и одним из компромиссов было то, что он решил не реализовывать автоматическое управление памятью или сборку мусора в таком большом масштабе, как другие OOPL. Возврат массива из одного из шаблонных классов работает, потому что, ну, вы используете класс. Но если вы хотите вернуть массив C, вы должны сделать это способом C. Другими словами, C ++ поддерживает возврат массива ТОЧНО так же, как Java; он просто не делает всю работу за вас. Потому что датский чувак думал, что это будет слишком медленно.