Console.WriteLine(&quot

advertisement
Использование функций
Задание. На основании задания для каждой из задач разработать
иерархию функций, описать назначение и таблицу спецификаций для каждой
функции, составить алгоритмы каждой функции, программу на языке C#,
таблицы тестов.
Задачи А .
1. Описать функцию RectPS(x1, y1, x2, y2), вычисляющую площадь S
прямоугольника со сторонами, параллельными осям координат, по
координатам (x1, y1), (x2, y2) его противоположных вершин. С помощью этой
функции
найти
площади
трех
прямоугольников
с
данными
противоположными вершинами.
2. Описать функцию CircleSR вещественного типа, находящую площадь
круга радиуса R (R — вещественное). С помощью этой функции найти
площади трех кругов с данными радиусами. Площадь круга радиуса R
вычисляется по формуле S = р·R2.
Задачи В.
1. Найти k – количество нечетных чисел ниже побочной диагонали
матрицы T и m – количество нечетных чисел матрицы C.Если k>m, найти
H=(1/m)*T+C, иначе найти F=k*(C+T)+T.
2. Пусть сумма элементов обеих диагоналей матрицы С равна S1, а сумма
элементов обеих диагоналей матрицы T равна S2. Если S1 <S2, то найти
матрицу Н=А+S1Т, иначе матрицу Z=B+S2(C+T). Здесь A- матрица порядка
n, все элементы которой равны S1; B- матрица порядка n, все элементы
которой равны S2.
Функция. Схема иерархии функций задачи.
Довольно часто необходимо, чтобы некоторые подзадачи, например,
поиск максимального значения в массиве, выполнялись в нескольких точках
программы. Конечно, можно добавлять в приложение идентичные (или
почти идентичные) разделы кода всякий раз, когда в этом возникает
необходимость, но такой подход имеет свои недостатки. Изменение даже
одной небольшой детали алгоритма в таком случае означает, что
соответствующие изменения потребуется вносить во множество разделов
кода, которые могут быть разбросаны по всему приложению. Пропуск
одного из этих разделов может повлечь за собой серьезные последствия и
сделать неработоспособным все приложение. К тому же это еще и
существенно удлиняет приложение.
Решить эту проблему позволяют функции.
Функции в языке С# являются средствами предоставления блоков
кода, которые могут выполняться в любой точке приложения.
Например, можно создать функцию, вычисляющую максимальное
значение в массиве. Далее ее можно выполнять из любой точки в коде и в
каждом случае использовать для этого одинаковые строки кода. Поскольку
описывать этот код нужно только один раз, любые вносимые в него
изменения будут отражаться на данной операции вычисления при всяком ее
применении. Функции также могут применяться для создания
универсального кода, что позволяет им выполнять одни и те же операции над
варьирующимися данными. Предоставлять необходимую для работы
информацию функциям можно в виде параметров, а получать от них
результаты — в виде возвращаемых значений. В предыдущем примере в
роли параметра мог бы выступать подлежащий поиску массив, а в роли
возвращаемого значения — максимальная величина в этом массиве. Это
означает, что одну и ту же функцию можно было бы использовать для
работы каждый раз с другим массивом.
При решении любой, достаточно сложной задачи, как уже говорилось
ранее, первым этапом является внешнее проектирование – разбиение задачи
на подзадачи и составление таблицы спецификаций для каждой подзадачи.
Разбиение задачи на подзадачи оформляется в виде схемы иерархии,
причем подзадачи выделяются по общности выполняемых ими действий. К
одной и той же подзадаче, реализуемой в виде функции, может происходить
обращение несколько раз с различными параметрами. Важно только, чтобы
эти параметры всегда передавались в одном и том же порядке,
соответствующем их перечислению в заголовке функции.
Пример разбиения задачи на подзадачи:
Заданы две матрицы целых чисел A(m,m) и B(k,k) и два вектора из целых
чисел X(m) и Y(k), где 1<m10 1<k8. Вычисляются P – число нулевых
элементов на главной диагонали матрицы A и Q – число нулевых элементов
на главной диагонали матрицы B. Если P<Q, то необходимо получить вектор
C(m), а в противном случае - вектор D(k), где
m
Ci   Ai , j X j  max Ai , j
j 1
k
i=1..m
Di   Bi , jY j  max Bi , j
i=1..k
j 1
Проведя анализ задачи, можно построить следующую схему иерархии
подзадач данной задачи (Рис. ):
Рис. 3. Схема иерархии подзадач примера
Каждая подзадача изображается прямоугольником, поделенным на 3
части. В средней части указывается имя функции, в верхней части
перечисляются имена входных параметров, в нижней – возвращаемые
значения.
Здесь main - главная функция, выполняющая решение всей задачи;
inpmatr - функция ввода матрицы;
inpvect - функция ввода вектора;
chis0 - функция подсчета числа нулевых элементов на главной
диагонали матрицы;
sum
- функция вычисления суммы произведений строки
матрицы на вектор;
outrez - функция вывода результирующего вектора;
max
- функция нахождения максимального элемента матрицы.
Для каждой функции составим таблицу спецификаций и словесный
алгоритм
Проектирование функций. Тестирование задачи
Функция main:
Входные величины
Имя
Назначение
Диапазон
M
Число строк
и столбцов
матрицы A
Целое число
Выходные величины
Имя
и число
элементов
вектора X
Число строк
и столбцов
K
Целое число
матрицы B
и число
элементов
вектора Y
Алгоритм:
1.
Ввод m,k
2.
Вызов функции inpmatr(m,A)
3.
Вызов функции inpmatr(k,B)
4.
Вызов функции inpvect(m,X)
5.
Вызов функции inpvect(k,Y)
6.
P=chis0(m,A)
7.
Q=chis0(k,B)
8.
ЕСЛИ P<Q ТО
8.1. Z=max(m,A)
8.2. j=1
8.3. ПОКА jm ВЫПОЛНИТЬ
Назначение
Диапазон
8.3.1.CH=sum(j,m,A,X)
8.3.2. Cj=CH+Z
8.3.3. j=j+1
ПОКА ВСЕ
8.4. Вызов функции outrez(m,C)
ИНАЧЕ
8.5. Z=max(k,B)
8.6. j=1
8.7. ПОКА jk ВЫПОЛНИТЬ
8.7.1.CH=sum(j,k,B,Y)
8.7.2.Dj=CH-Z
8.7.3. j=j+1
ПОКА ВСЕ
8.8. Вызов функции outrez(k,D)
ЕСЛИ ВСЕ
Функция inpmatr:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
Имя
Назначение
Диапазон
a
Число строк
и столбцов
матрицы
Целое число
X
Матрица
Целые
числа
Алгоритм:
1.
i=1
2.
ПОКА ia ВЫПОЛНИТЬ
2.1. j=1
2.2. ПОКА ja ВЫПОЛНИТЬ
2.2.1. Ввод Xi,j
2.2.2. j=j+1
ПОКА ВСЕ
2.3. i=i+1
ПОКА ВСЕ
Функция inpvect:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
Имя
Назначение
Диапазон
a
Число
элементов
вектора
Целое число
V
Вектор
Целые
числа
Алгоритм:
1.
i=1
2.
ПОКА i<=a ВЫПОЛНИТЬ
2.1. Ввод Vi
2.2. i=i+1
ПОКА ВСЕ
Функция outrez:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
b
Число
элементов
вектора
Целое число
Имя
Назначение
Диапазон
Вектор
V
Целые числа
Алгоритм:
1.
i=1
2.
ПОКА i<=b ВЫПОЛНИТЬ
2.1. Вывод Vi
2.2. i=i+1
ПОКА ВСЕ
Функция chis0:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
A
Число строк Целое число
и число
столбцов
матрицы
T
Матрица
Целые числа
Алгоритм:
1. c=0
2. i=1
3. ПОКА i<=a ВЫПОЛНИТЬ
3.1. ЕСЛИ Ti,i=0 ТО
3.1.1. c=с+1
ЕСЛИ ВСЕ
3.2. i=i+1
ПОКА ВСЕ
Имя
Назначение Диапазон
c
Число
нулевых
элементов
на главной
диагонали
матрицы
Целое
4. Возврат c
Функция max:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
Имя
Назначение
Диапазон
A
Число строк
и число
столбцов
матрицы
Целое число
mx
Максимальный элемент
матрицы
Целое
число
X
Матрица
Целые числа
Алгоритм:
1. mx=X1,1
2. ii=1
3. ПОКА ii<=a ВЫПОЛНИТЬ
3.1. jj=1
3.2. ПОКА jj<=a ВЫПОЛНИТЬ
3.2.1.ЕСЛИ Xii,jj>mx ТО
3.2.1.1.mx= Xii,jj
ЕСЛИ ВСЕ
3.2.2.jj=jj+1
ПОКА ВСЕ
3.3. ii=ii+1
ПОКА ВСЕ
4. Возврат mx
Функция sum:
Входные величины
Выходные величины
Имя
Назначение
Диапазон
Имя
Назначение
Диапазон
a
Номер
строки
матрицы
Целое число
s
Сумма
произведений
строки
матрицы на
вектор
Целое
число
b
Число
столбцов
Целое число
матрицы
T
Матрица
Целые числа
V
Вектор
Целые числа
Алгоритм:
1. j=1
2. s=0
3. ПОКА jb ВЫПОЛНИТЬ
3.1. s=s+Ta,jVj
3.2. j=j+1
ПОКА ВСЕ
4. Возврат s
Тесты:
Номер теста
Назначение теста
1
Максимальный
элемент матрицы
равен нулю
Входные
данные
m=2
A=0 -4
-2 -7
X=(2,6)
Выходные
данные
C=(-24 -46)
2
Максимальный
элемент матрицы
не равен нулю
k=2
D=(67 104)
B=2 6
1.
8
Y=(7,8)
Функции в языке C#
Определение функции
Если записать код
static void Write ()
{Console.WriteLine("Текст из функции") ; }
static void Main(string[] args)
{Write () ; Console.ReadKey(); }
то он представляет собой две функции Main и Write.
Определение функции состоит из следующих элементов.

Два ключевых слова: static и void.

Имя функции, за которым следуют круглые скобки

Заключенный в фигурные скобки блок кода, который подлежит
выполнению.
При выполнении любого приложения С# первой вызывается та
содержащаяся в нем функция, которая выступает в роли точки входа, а при
завершении выполнения этой функции завершается и работа всего
приложения. Весь исполняемый код на С# должен обязательно иметь такую
точку входа. Это функция Main.
Ключевое слово void служит для обозначения того, что функция не
возвращает никакого значения.
Далее идет код, вызывающий функцию, который выглядит следующим
образом:
Write ();
Здесь просто вводится имя функции, а за ним — круглые скобки без
содержимого. При достижении программой во время выполнения этой точки,
будет запускаться код, содержащийся внутри функции Write ().
Использование круглых скобок как в определении, так и в вызове
функции, является обязательным.
Возвращаемые значения
Наиболее простым способом для обмена данными с функцией является
использование возвращаемого значения. Функции, имеющие возвращаемое
значение, при вызове выдают именно это значение. Как и переменные,
возвращаемые значения имеют тип.
Например, можно создать функцию GetString() с возвращаемым
значением типа string. Использовать такую функцию в коде можно
следующим образом:
string myString;
myString = GetString ();
Можно также создать функцию GetVal () с возвращаемым значением
типа float.
Такая функция может участвовать в математическом выражении:
float myVal,multiplier = 5.3;
myVal = GetVal()* multiplier;
Наличие у функции возвращаемого значения требует внесения двух
следующих изменений.

Указание в объявлении функции типа возвращаемого значения
вместо ключевого слова void.

Использование ключевого слова return для завершения
выполнения
функции и передачи возвращаемого значения в вызывающий код.
При достижении оператора return управление выполнением программы
сразу же возвращается вызывающему коду. Никакие строки кода после этого
оператора больше не выполняются, хотя это вовсе не означает, что
операторы return могут размещаться только в последней строке тела
функции. Оператор return можно использовать и ранее в коде, например,
после выполнения какой-то ветви алгоритма.
static float GetVal()
{ float checkVal;
if (checkVal < 5) return 4.7;
return 3.2; }
Здесь возвращаться может одно из двух значений, в зависимости от
значения checkVal. Единственным ограничением в данном случае является
то, что оператор return должен обрабатываться перед достижением
закрывающей фигурной скобки в функции. Следующий код недопустим:
static float GetValO
{float checkVal;
if (checkVal < 5) return 4.7; }
Здесь получается, что в случае, если значение checkVal ≥ 5, не будет
выполнено никакого оператора return, что является недопустимым. Все пути
обработки должны обязательно приводить к оператору return.
Параметры
Когда функция должна принимать параметры, следует указать
следующее:

список принимаемых функцией параметров вместе с их типами в
именами в определении этой функции;

соответствующий список параметров в каждом вызове этой
функции.
Это подразумевает использование показанного ниже кода, в котором
может присутствовать любое количество параметров, при этом для каждого
из них должен указываться тип и имя:
static <возвращаемый_тип>
<имя_параметра>, ...)
<имя_функции>
(
<тип_параметра>
{ return <возвращаемое_значение>; }
Параметры отделяются друг от друга запятыми, и каждый из них
доступен в коде функции через переменную. Например, простая функция
может принимать два параметра float и возвращать результат их умножения:
static float Product(float paraml, float param2)
{ return paraml * param2; }
Соответствие параметров
При вызове функции параметры должны указываться в точности как в
определении функции, то есть соответствующего типа, в соответствующем
количестве и соответствующем порядке. Например, функцию
static void MyFunction(string myString, float myFloat)
{
}
нельзя вызывать так: MyFunction(8.6, "Hello");
Здесь в качестве первого параметра передается значение float, а в
качестве второго — значение string, что не соответствует порядку, в котором
эти параметры были указаны в определении функции.
Эту функцию также нельзя вызывать и следующим образом:
MyFunction("Hello");
Здесь передается только один параметр string, а согласно определению
функции, параметров должно быть два. При попытке использовать любой из
двух приведенных выше вызовов функции компилятор будет сообщать об
ошибке, вынуждая соблюдать соответствие заголовку вызываемой функции
Пример параметра-массива
static int MaxValue (int [ ] intArray)
{ int maxVal = intArray[0];
for (int i = 1; i < intArray.Length; i++)
{ if (intArray[i] > maxVal) maxVal = intArray[i]; }
return maxVal;}
static void Main(string [ ] args)
{ int[] myArray = {1, 8, 3, 6, 2, 5, 9, 3, 0, 2};
int maxVal = MaxValue(myArray) ;
Console.WriteLine("Максимальное
maxVal);
значение
массива
равно
{0}",
Console.ReadKey ();
Во всех демонстрировавшихся до сих пор функциях использовались
параметры - значения. То есть при каждом применении параметров
используемой внутри функции переменной передавалось значение. Никакие
изменения, вносимые в эту переменную в функции, не оказывали влияние на
параметр, передаваемый в вызове функции.
Выходные параметры
Для изменения значения параметра можно указывать, что параметр
является выходным параметром, используя ключевое слово out, которое
применяется в виде модификатора перед параметром как в определении, так
и в вызове функции.
Две особенности выходных параметров:
 В
качестве
параметра
out
можно
применять
неинициализированную переменную.
 Параметр out должен трактоваться как неприсвоенное значение
функцией, которая его использует.
Это означает, что хотя использовать неинициализированную
переменную в качестве параметра out в вызывающем коде допускается,
хранящееся в этой переменной значение при выполнении функции будет
утрачиваться.
Для примера рассмотрим функцию MaxValue (), которая возвращает
максимальное значение в массиве. Изменим ее так, чтобы она позволяла
получать индекс того элемента, в котором находится максимальное значение.
Чтобы не усложнять пример, пусть это будет индекс только первого
вхождения этого значения при наличии множества элементов с таким же
максимальным значением.
Чтобы добиться такого поведения, достаточно добавить параметр out,
изменив функцию, как показано ниже:
static int MaxValue (int [] intArray, out int maxlndex)
{ int maxVal = intArray[0]; maxlndex = 0;
for (int i = 1; i < intArray.Length; i++)
{ if (intArray[i] > maxVal)
{ maxVal = intArray[i]; maxlndex = i; } }
return maxVal; }
Использовать эту функцию можно так:
int[] myArray = {1, 8, 3, 6, 2, 5, 9, 3, О, 2} ;
int maxIndex;
Console.WriteLine("Максимальное значение myArray равно {0}",
MaxValue(myArray, out maxlndex));
Console.WriteLine("Первое вхождение этого значения встречается в
элементе {0}", maxlndex + 1) ;
Область видимости переменных
У каждой переменной имеется так называемая область видимости, в
пределах которой к ней можно получать доступ.
Область видимости охватывает блок кода, в котором переменная
определяется, а также любые блоки, непосредственно вложенные в него.
Блоки кода в функциях идут отдельно от блоков кода, из которых они
вызываются.
static void Write ()
{ string myString = " Строка, определенная в функции Write () " ;
Console.WriteLine("Теперь в функции Write() ") ;
Console.WriteLine("myString = {0}", myString); }
static void Main(string[] args)
{ string myString = "Строка, определенная в MainO";
Write () ;
Console.WriteLine(“Теперь в Main()");
Console.WriteLine("myString = {0}", myString);
Console.ReadKey();
Переменные, область видимости которых распространяется только на
одну единственную функцию, называются локальными переменными.
Однако также допускается использовать и глобальные переменные, область
видимости которых распространяется на несколько функций. Объявление
таких переменных снабжается ключевым словом static.
Пример с использованием глобальной переменной:
class Program
{static string myString;
static void Write ()
{string myString = "String defined in Write()";
Console.WriteLine("Now in Write ()");
Console.WriteLine("Local myString = {0}", myString);
// Локальная переменная
Console.WriteLine ("Global myString = {0}", Program.myString) ;
// Глобальная переменная
}
static void Main(string[] args)
{ string myString = "String defined in MainO";
Program.myString = "Global string";
Write () ; Console. WriteLine ("\nNow in MainO") ;
Console.WriteLine ("Local myString = @)", myString) ;
Console.WriteLine ("Global myString = {0}", Program.myString) ;
Console.ReadKey() ; } }
Пример программы, алгоритм которой рассмотрен ранее.
Прежде всего отметим, что для определения размера матрицы можно
использовать запись вида переменная=массив.GetLength(номер измерения),
которое равно 0 для числа строк и равно 1 для числа столбцов
class Program
{static int m;
static void inpvect(int a,out int []V)
{int i;
V = new int[a];
for(i=0;i<a;i++)
V[i] = Convert.ToInt32(Console.ReadLine());
}
//-------------------static void outrez (int b,int [] V)
{int i;
for (i=0;i<b;i++)
Console.Write("{0} ",V[i]);
Console.WriteLine();
Console.ReadKey();
}
//------------------static void inpmatr(int a,out int [,]X)
{int i,j;
X = new int[a, a];
for (i = 0; i < a; i++)
{
Console.WriteLine("Введите {0} строку матрицы", i + 1);
for (j = 0; j < a; j++)
X[i, j] = Convert.ToInt32(Console.ReadLine());
//Console.ReadLine();
}
}
//---------------static int max(int a,int [,] X)
{int mx,i,j;
mx=X[0,0];
for (i=0;i<a;i++)
for (j=0;i<a;i++)
if (X[ i, j]>mx) mx=X [i,j];
return mx;}
//---------------static int sum(int a,int b,int [,] T,int [] V)
{int s=0,j;
for (j=0;j<b;j++)
s+=T[a,j]*V[j];
return s;}
//----------
static int chis0(int a,int [,]T)
{int c=0,i;
for (i=0;i<a;i++)
if (T[i,i]==0)
c++;
return c;}
static void Main(string[] args)
{ Console.WriteLine("Введите размер матрицы");
m = Convert.ToInt32(Console.ReadLine());
int [,] A=new int[m,m];
int [,] B=new int[m,m];
int [ ] X=new int[m];
int [] Y=new int[m];
int [ ] C=new int [m];
int []D=new int[m];
int P,Q,j,Z,CH;
Console.WriteLine("Матрица A");
inpmatr(m,out A);
Console.WriteLine("Вектор X");
inpvect(m,out X);
Console.WriteLine("Матрица B");
inpmatr(m,out B);
Console.WriteLine("Вектор Y");
inpvect(m,out Y);
P=chis0(m,A);
Q=chis0(m,B);
if (P<Q)
{Z=max(m,A);
for (j=0;j<m;j++)
{CH=sum(j,m,A,X);
C[j]=CH+Z;}
Console.WriteLine("Вектор C");
outrez(m,C);}
else
{Z=max(m,B);
for (j=0;j<m;j++)
{CH=sum(j,m,B,Y);
D[j]=CH-Z;}
Console.WriteLine("Вектор D");
outrez(m,D);}
}
Download