Страницы

Поиск по вопросам

суббота, 13 октября 2018 г.

Сколько есть способов передачи аргументов в функцию?

Как по мне, то в С есть передача аргументов в функцию только по значению, а в С++ по факту тоже только передача по значению. То есть, передачи по указателю не может быть, потому что указатель содержит адрес, а это тоже значение. Так что правильней говорить, что передача по значению. Ну а насчет ссылок, то это те же указатели с константным адресом и которые неявно преобразуются к указателю, так что тоже передача по значению. То есть, есть только передача по значению. А когда говорят о передаче по указателю и ссылке, то это скорей для того, чтобы внести ясность о том, будет ли переменная копирована или взят её адрес или так же неявно взят адрес с невозможностью заменить его на другой адрес. В общем, условно(для упрощения понимания) есть 2 способа передачи аргументов в функцию в Си : по значению, по указателю. И 3 способа в C++: по значению, по указателю, по ссылке. А по факту везде передается по значению и только. В тесте по Си были 2 ответа : по значению, и по указателю. Но вопрос там был другой "Какими способами можно передавать параметры в функцию?". То есть, не аргументы, а параметры. Не совсем понимаю этот момент, но если предположить, что аргументы передаются в параметры, а потом параметры в тело функции, то параметры вполне могут передаваться по значению или указателю или по ссылке( в C++). И будет выглядеть как - void func1 ( int arg ); void func2 ( int * arg ); void func3 ( int & arg ); Из кода видно, что сами параметры могут быть и ссылкой и указателем, но тем не менее во всех трех случаях инициализированы они будут аргументами, которые передаются только по значению. Что-то мне кажется, что скорей всего не правильно был сформулирован вопрос теста и параметры не передаются в функцию, так как они и так в её сигнатуре, а передаются аргументы, ну а параметры просто инициализируются где-то между сигнатурой и телом в области видимости под которую попадает тело функции.


Ответ

Насколько я понимаю, в C ровно один способ передачи аргументов: по значению. Передаёте ли вы по значению число или указатель, вы получаете с той стороны копию этого числа/указателя: если вы меняете число внутри функции, с его «внешним прообразом» (который может, кстати, быть и выражением) ничего не случается; если внешний прообраз меняется в течение выполнения функции, на значении аргумента это никак не отражается. Иногда говорят, что передавая указатель на объект в функцию, вы как бы тем самым неявно передаёте сам объект в функцию «по указателю». Это на самом деле не вполне верный подход. Давайте я приведу пример: представьте себе, что вам передали число. Вы использовали это число как индекс в глобальном массиве, и изменили элемент этого массива. Можно ли сказать, что вам был передан этот элемент? Нет, вы получили лишь число. Точно так же можно смотреть на указатель как на индекс в памяти, рассматриваемой как массив байт. Доступ к объекту через указатель ничем не лучше и не хуже доступа к ячейке массива по индексу. В C++ появился новый вид передачи параметров: по ссылке. По существу, передача «по ссылке» ничем не отличается от передачи указателя кроме того, что (1) ссылка не может соответствовать NULL-указателю в корректной программе, (2) ссылка синтаксически ведёт себя как разыменованный указатель. Однако, разработчики C++ советуют всё же видеть в передачу по ссылке другую семантику: ссылка является «алиасом», другими именем объекта. Хотя такая семантика и более привлекательна с точки зрения ясности программ, всё же ссылка на объект и сам объект — не одно и то же. В частности, ссылка может пережить объект, и вы получите при попытке обратиться к ней undefined behaviour. Если бы ссылка была самим объектом (как это часто пытаются подать), такого произойти бы не смогло. Следовать ли совету разработчиков или думать о передаче по ссылке как о синтаксическом сахаре для передачи по указателю — личное дело каждого. Я бы всё же советовал думать так, как советуют разработчики, но не упускать из виду, что эта абстракция «протекает». ЗЫ: Пример кода без явных ошибок (наподобие возврата ссылки на локальную переменную), в котором ссылка на объект переживает сам объект: class X { struct C { int x; }; C* pc;
void f(int& x) { g(); cout << x << endl; } void g() { delete pc; }
public: X() : pc(new C()) {} void run() { f(pc->x); } };

Комментариев нет:

Отправить комментарий