Добавить в цитаты Настройки чтения

Страница 273 из 371



    ars[i] += i.ToString()+1;

    Console.WriteLine("ard[" +i + "]=" +ard[i] + "; ars[" +i + "]=" +ars[i]);

}

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

Еще раз о семантике присваивания

Подводя итоги рассмотрения присваивания х=е, следует отметить, что семантика присваивания далеко не столь проста, как может показаться с первого взгляда. Напомню, что деление типов на значимые и ссылочные приводит к двум семантикам присваивания. Будет ли семантика значимой или ссылочной — определяется типом левой части присваивания. Переменные значимых типов являются единоличными владельцами памяти, в которой хранятся их значения. При значимом присваивании память для хранения значений остается той же — меняются лишь сами значения, хранимые в ней. Переменные ссылочных типов (объекты) являются ссылками на реальные объекты динамической памяти. Ссылки могут разделять одну и ту же область памяти — ссылаться на один и тот же объект. Ссылочное присваивание — это операция над ссылками. В результате ссылочного присваивания ссылка начинает указывать на другой объект.

Рассмотрим объявления:

int x=3, y=5;

object obj1, obj 2;

Здесь объявлены четыре сущности: две переменные значимого типа и две — объектного. Значимые переменные х и у проинициализированы и имеют значения, объектные переменные obj1 и obj2 являются пустыми ссылками со значением void. Рассмотрим присваивания:

obj1 = х; obj2 = у;

Эти присваивания ссылочные (из-за типа левой части), поэтому правая часть приводится к ссылочному типу. В результате неявного преобразования — операции boxing — в динамической памяти создаются два объекта, обертывающие соответственно значения переменных х и у. Сущности obj1 и obj2 получают значения ссылок на эти объекты.

Класс Math и его функции

Кроме переменных и констант, первичным материалом для построения выражений являются функции. Большинство их в проекте будут созданы самим программистом, но не обойтись и без встроенных функций. Умение работать в среде Visual Studio.Net предполагает знание встроенных возможностей этой среды, знание возможностей каркаса Framework.Net, пространств имен, доступных при программировании на языке С#, а также соответствующих встроенных классов и функций этих классов. Продолжим знакомство с возможностями, предоставляемыми пространством имен System. Мы уже познакомились с классом Convert этого пространства и частично с классом Console. Давайте рассмотрим еще один класс — класс Math, содержащий стандартные математические функции, без которых трудно обойтись при построении многих выражений. Этот класс содержит два статических поля, задающих константы E и PI, а также 23 статических метода. Методы задают:

• тригонометрические функции — Sin, Cos, Tan;

• обратные тригонометрические функции — ASin, ACcos, ATan, ATan2 (sinx, cosx);

• гиперболические функции — Tanh, Sinh, Cosh;

• экспоненту и логарифмические функции — Exp, Log, Log10;

• модуль, корень, знак — Abs, Sqrt, Sign;

• функции округления — Ceiling, Floor, Round;

• минимум, максимум, степень, остаток — Min, Max, Pow, IEEERemainder.

В особых пояснениях эти функции не нуждаются. Приведу пример:

/// <summary>

/// работа с функциями класса Math

/// </summary>

public void MathFunctions()

{

    double a, b,t,t0,dt,y;

    string NameFunction;

    Console.WriteLine("Введите имя F(t)исследуемой функции

           a*F(b*t)" + " (sin, cos, tan, cotan)");

    NameFunction = Console.ReadLine();

    Console.WriteLine("Введите параметр a (double)");

    a= double.Parse(Console.ReadLine ());

    Console.WriteLine("Введите параметр b (double)");

    b= double.Parse(Console.ReadLine());

    Console.WriteLine("Введите начальное время t0(double)");

    t0= double.Parse(Console.ReadLine());

    const int points = 10;

    dt = 0.2;

    for(int i = 1; i<=points; i++)

    {

         t = t0 + (i-1)* dt;

         switch (NameFunction)





     {

          case ("sin"):

               у = a*Math.Sin(b*t);

               break;

          case ("cos"):

              у = a*Math.Cos(b*t);

              break;

           case ("tan"):

               у = a*Math.Tan(b*t);

               break;

           case ("cotan"):

               у = a/Math.Tan(b*t);

               break;

            case ("In"):

               у = a*Math.Log(b*t);

               break;

            case ("tanh"):

                у = a*Math.Tanh(b*t);

                break;

            default:

                y= 1;

                break;

         }//switch

         Console.WriteLine ("t = " + t +"; " + a +"*" +

                NameFunction +"(" + b + "*t)= " + у +";");

}//for

double u = 2.5, v = 1.5, p,w;

p= Math.Pow(u,v);

w = Math.IEEERemainder(u,v);

Console.WriteLine ("u = " + u +"; v= " + v +

     "; power(u,v)= " + p +"; reminder(u,v)= " + w);

}//MathFunctions

Заметьте, в примерах программного кода я постепенно расширяю диапазон используемых средств.

Часть из этих средств уже описана, а часть (например, оператор цикла for и оператор выбора switch) будут описаны позже. Те, у кого чтение примеров вызывает затруднение, смогут вернуться к ним при повторном чтении книги.

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

Функция, заданная пользователем, вычисляется в операторе switch. Здесь реализован выбор из 6 стандартных функций, входящих в джентльменский набор класса Math.

Вызов еще двух функций из класса Math содержится в двух последних строчках этой процедуры. На рис. 7.1 можно видеть результаты ее работы.

Рис. 7.1. Результаты работы процедуры MathFunctions

Класс Random и его функции

Умение генерировать случайные числа требуется во многих приложениях. Класс Random содержит все необходимые для этого средства. Класс Random имеет конструктор класса: для того, чтобы вызывать методы класса, нужно вначале создавать экземпляр класса. Этим Random отличается от класса Math, у которого все поля и методы — статические, что позволяет обойтись без создания экземпляров класса Math.

Как и всякий "настоящий" класс, класс Random является наследником класса object, а, следовательно, имеет в своем составе и методы родителя. Рассмотрим только оригинальные методы класса Random со статусом public, необходимые для генерирования последовательностей случайных чисел. Класс имеет защищенные методы, знание которых полезно при необходимости создания собственных потомков класса Random, но этим мы заниматься не будем.