Смекни!
smekni.com

Основы алгоритмизации и программирования 2 (стр. 17 из 32)

Например:

static double getVal() { double checkVal;

// присваивание переменной checkVal некоторого значения, // полученного в результате некоторых вычислений.

if (checkVal < 5) return 4.7; return 3.2; }

В данном случае будет возвращено одно из двух значений – в зависимости от значения переменной checkVal.

Имеется единственное ограничение: оператор return должен выполняться до того, как будет достигнута закрывающая фигурная скобка } данной функции. Следующий код не является допустимым:

static double getVal() { double checkVal;

// присваивание переменной checkVal значения, // полученного в результате некоторых вычислений. if (checkVal < 5) return 4.7;

Если checkVal >= 5, то не встретится ни одного оператора return, а это запрещено. Все ветви должны оканчиваться этим оператором.

И последнее замечание: оператор retum может применяться в функциях, объявленных с использованием ключевого слова void (у них отсутствует какое-либо возвращаемое значение). В таких случаях функция просто прекращает работу. Поэтому при использовании оператора return будет ошибкой размещать возвращаемое значение между ключевым словом return и следующей за ним точкой с запятой.

4.3.Параметры

Если функция должна получать параметры, то необходимо задать:

- список принимаемых функцией параметров в ее описании, а также типы этих параметров; - совпадающий список параметров при каждом вызове функции. Это предполагает использование следующего кода:

static <возвращаемьйТип> <имяФункции>(<типПараметра> <имяПараметра>, . . .) {
return <возвращаемоеЗначение>; }

Здесь может быть произвольное число параметров, для каждого из которых указываются тип и имя. В качестве разделителя между параметрами ставятся запятые. Каждый из параметров доступен внутри данной функции в качестве переменной.

Например, следующая простая функция принимает два параметра типа double и возвращает их произведение:

static double product(double param1, double param2) { return param1 * param2; )

4.3.1.Соответствие параметров

При вызове функции ее параметры должны в точности соответствовать ее описанию. Необходимо совпадение типов параметров, их количества и порядка их следования. Это означает, что, например, функция static void myFunction(string myString, double myDouble)

не может быть вызвана с использованием строки myFunction(2.6, "Hello") ;

В данном случае пытаются передать значение типа double в качестве первого параметра, а значение типа string – в качестве второго, что не соответствует порядку, в котором эти параметры содержатся в описании функции. Нельзя использовать и такую строку:

myFunction("Hello");

поскольку в ней передается только один параметр типа string вместо двух обязательных параметров.

Попытка воспользоваться любой из этих двух строк для вызова функции приведет к ошибке при компиляции, так как компилятор налагает требование точного соответствия сигнатурам вызываемых функций.

static void Main(string[] args) {
double[] myArray = {1.3, 8.9, 3.3, 6.5, 2.7, 5.3};
double maxVal = MaxValue(myArray};
Console.WriteLine("The maximum value in myArray is {0}",maxVal);

Возвращаясь к предыдущему примеру, такое требование означает, что функция MaxValue() может использоваться только для получения максимального целого из массива целых чисел. Если мы изменим код в Mаin()следующим образом: то такой код не пройдет процедуру компиляции из-за неверного типа параметра.

Ниже, в разделе, посвященном перегрузке операторов, описан способ, позволяющий решить эту проблему.

4.3.2.Массивы параметров

В C# предусмотрена возможность задания одного (и только одного) специального параметра функции. Этот параметр, который обязательно должен располагаться последним, известен под названием массива параметров. Он позволяет при обращении к функциям использовать переменное количество параметров. Массив параметров описывается посредством ключевого слова params.

Массивы параметров служат одним из способов упрощения кода, поскольку благодаря им не приходится передавать массивы из вызывающего кода. Напротив, можно передать несколько параметров одного и того же типа, которые помещаются в массив для последующего использования внутри функции.

При описании функции с массивом параметров применяется следующий код:

static <возвращаемьйТип <имяФункции>(<п1тип> <п1Имя>, . . . ,
params <тип>[] <имя>)
return <возвращаемоеЗначение>; }

Для того чтобы вызвать эту функцию, потребуется следующий код: ... , <значение1>, <значение2>, ...);

В данном случае <значение1>, <значение2> и т.д.– это значения типа <тип>. Они используются для инициализации массива с именем <имя>. Никаких ограничений на количество параметров, которые могут быть здесь заданы, не существует; единственное предъявляемое к ним требование – они все должны быть одного типа <тип>. Можно вообще не задавать ни одного параметра.

Эта последняя особенность делает массивы параметров полезными, в частности, при задании некоторой дополнительной информации, которая будет использоваться функцией. Например, допустим, что имеется функция getWord(), которая принимает значение типа string в качестве первого параметра и возвращает первое слово из этой строки:

string firstWord = getWord("This is a sentence."); Переменной firstord будет присвоена строка "This".

Мы можем добавить в функцию getWord() параметр params, который позволит выбирать и возвращать другое слово по его индексу:

string firstWord = getWord("This is a sentence.", 2);

Если исходить из предположения, что нумерация слов начинается с 1, то в результате такого вызова переменной firstWord будет присвоена строка "is".

Можно ограничить количество возвращаемых символов, введя третий параметр, что совершенно допустимо для параметра params:

string firstWord = getWord("This is a sentence.", 4, 3);

В этом случае переменной firstWord будет присвоена строка "sen". Давайте разберем пример полностью.

4.3.3.Передача параметров по ссылке и по значению

Во всех предыдущих функциях применялись параметры, передаваемые по значению. Другими словами, мы передавали значение в переменную, которая затем использовалась внутри функции Любые изменения, которые эта переменная претерпевала внутри функции, не оказывали никакого влияния на параметр, использованный при вызове функции В качестве примера рассмотрим функцию, которая удваивает передаваемый ей параметр и выводит результат на экран:

static void showDouble(int val) {
val *= 2;
Console.WriteLine("val doubled = {0}", val); }

В этой функции происходит удвоение передаваемого параметра. Если же вызовать эту функцию следующим образом:

int myNumber = 5;
Console.WriteLine("rayNumber = {0}", myNumber);
showDouble(myNumber);
Console.WriteLine("myNumber = {0}", myNumber)

;

то выходной поток, выведенный на консоль, будет таким:

myNumber = 5;
val double = 10; myNumber = 5;

Вызов функции showDouble() с переменной myNumber в качестве параметра не оказывает никакого влияния на переменную myNumber, описанную в Main (), несмотря на то, что параметр, которому присваивается ее значение, удваивается.

Однако, чтобы значение переменной myNumber было изменено, возникнет проблема. Конечно, можно воспользоваться функцией, которая возвращает новое значение переменной myNumber, и вызвать ее следующим образом:

int myNumber = 5;
Console.WriteLine("myNumber = {0}", myNumber);
myNumber = showDouble(myNumber);
Console.WriteLine("myNumber = {0}", myNumber);

Однако в таком коде довольно трудно разобраться; кроме того, такой способ не позволяет отразить изменения значений переменных, используемых в качестве параметров (поскольку функции всегда возвращают только одно значение).

Вместо этого следует передавать параметр по ссылке. Это означает, что функция будет работать именно с той переменной, которая использовалась при вызове функции, а не с переменной, которая имеет то же значение. Следовательно, любые изменения переменной, использовавшейся функцией, отразятся на значении переменной, использовавшейся в качестве параметра. Для этого при описании параметра необходимо воспользоваться ключевым словом ref:

static void showDouble(ref int val) { val *= 2;

Console.WriteLine("val doubled= {0)", val); }

Вторично ключевое слово ref необходимо использовать при вызове функции (это обязательное требование, поскольку тот факт, что параметр описан как ref, является неотъемлемой частью сигнатуры функции).

int myNumber = 5;
Console.WriteLine("myNumber = {0}", myNumber);
showDouble(ref myNumber);
Console.WriteLine("myNumber = {0}", myNumber);

В этом случае на консоль будет выведен следующий текст: myNumber = 5;

val double d = 10; myNumber = 10;

На этот раз переменная myNumber была изменена в функции showDouble ().

Для переменных, используемых в качестве параметров типа ref, имеются два ограничения. Во-первых, поскольку существует вероятность, что в результате вызова функции значение вызываемого по ссылке параметра будет изменено, то при вызове функции запрещается использовать переменные типа const. Отсюда следует, что следующий вызов является недопустимым:

const int myNumber = 5;
Console.WriteLine("myNumber = {0}", myNumber);
showDouble(ref myNumber);
Console.WriteLine("myNumber = {0}", myNumber);

Во-вторых, необходимо использовать заранее инициализированную переменную. C# не гарантирует, что параметр типа ref будет инициализирован той функцией, в которой он используется. Следующий код также является недопустимым: