Язык программирования C#
Использование синтаксических операторов языка программирования С#. Составление программы, которая вводит строку в переменную String. Определение номера строк и столбцов всех седловых точек целочисленной прямоугольной матрицы, суммы элементов в строках.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | контрольная работа |
Язык | русский |
Дата добавления | 25.04.2015 |
Размер файла | 177,7 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
1. Опишите синтаксические операторы языка программирования С#. Приведите примеры их использования
Значение аргумента х изменяется от а до b с шагом h. Для каждого х найдите значение функции Y(x), суммы S(x) и и выведите в виде таблицы. Значения а, b, h введите с клавиатуры произвольно. Вычисление Y(x) и S(x) реализуйте в виде функций.
В основной программе организуйте ввод исходных данных, обращение к функциям и вывод результатов.
.
В одномерном массиве, состоящем из n вещественных элементов, вычислить:
- максимальный по модулю элемент массива;
- сумму элементов массива, расположенных между первым и вторым положительными элементами.
Дана целочисленная прямоугольная матрица. Определить:
- сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент;
- номера строк и столбцов всех седловых точек матрицы. (Матрица А имеет седловую точку Аij, если Аij является минимальным элементом в i-й строке и максимальным в j-м столбцеи наоборот).
5. Составьте программу, которая будет вводить строку в переменную String. Напечатайте в алфавитном порядке все слова из данной строки, имеющие заданную длину n.
2. Опишите синтаксические операторы языка программирования С#. Приведите примеры их использования
Состав операторов языка C#, их синтаксис и семантика унаследованы от языка С++. Как и положено, потомок частично дополнил состав, переопределил синтаксис и семантику отдельных операторов, постарался улучшить характеристики языка во благо программиста. Посмотрим, насколько это удалось языку C#.
Оператор присваивания
В лекции 1.3 подробно рассматривались операция и выражение присваивания
X = expr
и многочисленные вариации, позволяющие строить выражения вида:
X1 += X2 *= … = Xk = expr
Синтаксически присваивание состоит из левой и правой частей, разделенных знаком операции присваивания. Правая часть - это выражение, в том числе выражение присваивания, как в последнем примере. Левая часть - это переменная, более точно левая часть представляет собой lvalue - выражение левой части, которому можно присвоить значение. Переменная является наиболее распространенным частным случаем lvalue.
Выражение присваивания представляет пример выражения с побочным эффектом. Прямым эффектом вычисления такого выражения является вычисленное значение и тип выражения expr. Побочным эффектом является присваивание вычисленного значения переменной левой части.
Выражение с побочным эффектом в языке C# можно легко преобразовать в соответствующий оператор. Стоит такое выражение закончить символом точка с запятой, как получится оператор, который можно использовать всюду, где синтаксически допустимы операторы языка. Так что синтаксически оператор присваивания выглядит так:
X = expr;
Допустимы и многочисленные вариации:
X1 += X2 *= … = Xk = expr;
К операторам присваивания можно отнести и такие операторы, как:
X++; X--; ++X; --X;
Эти операторы получены из соответствующих выражений с побочным эффектом приписыванием в конце символа точки с запятой. Когда выражения с побочным эффектом преобразуются в операторы, то побочный эффект занимает подобающее ему место и задает семантику оператора, а вычисление значение выражения становится частью процесса выполнения оператора.
Семантика присваивания
Казалось бы, семантика присваивания проста и очевидна, -- вычисляем выражение правой части и его значение присваиваем соответствующей переменной левой части. Но это лишь общее описание семантики. Детали значительно сложнее. Дело в том, что левая часть и правая часть имеют свои типы, и эти типы могут не совпадать. В этом случае необходимо выполнить преобразование типа правой части к типу левой части. Иногда такое преобразование безопасно и его можно выполнить автоматически. Иногда такое преобразование опасно, и тогда возникнет ошибка, которая чаще всего обнаруживается еще на этапе компиляции.
Будем называть целью левую часть оператора присваивания, источником правую часть оператора присваивания. Источник и цель могут быть как значимого, так и ссылочного типа. Присваивание будем называть ссылочным, если цель ссылочного типа. В этом случае источник должен быть ссылочного типа или быть приведенным к этому типу. Присваивание будем называть значимым, если цель значимого типа. В этом случае источник должен быть значимого типа или быть приведенным к этому типу.
Операции упаковать и распаковать -- boxing и unboxing
Возникает естественный вопрос, можно ли ссылочным переменным, связанным с объектами, хранимыми в куче, присваивать значимые переменные, хранимые в стеке. Можно ли выполнять обратную операцию? В C# такие возможности преобразования типов предусмотрены. Операция «упаковать» (boxing) позволяет переменную значимого типа «упаковать в одежды класса», создавая объект в динамической памяти. Такое преобразование выполняется автоматически всякий раз, когда цель принадлежит классу object, а источником может быть переменная любого из значимых типов. Операция «распаковать» (unboxing) позволяет переменную типа object «распаковать и извлечь хранимое значение». Такое преобразование выполняется автоматически. Извлеченное значение не сохраняет информацию о своем типе. Поэтому, прежде чем присвоить это значение цели, его необходимо привести к нужному типу. Ответственность за это приведение лежит на программисте.
Рассмотрим подробнее, какие преобразования могут выполняться в процессе присваивания:
· Цель и источник значимого типа. Здесь наличествует семантика значимого присваивания. В этом случае источник и цель имеют собственную память для хранения значений. Если типы цели и источника совпадают, то никаких проблем нет. Значения источника копируются и заменяют значения соответствующих полей цели. Источник и цель после этого продолжают жить независимо. У них своя память, хранящая после присваивания одинаковые значения. Если типы разные, то необходимо преобразование типов. Оно может быть безопасным и тогда выполняется автоматически. В противном случае должно явно задаваться программистом. Явные и неявные преобразования внутри арифметического типа, кастинг, метод Parse и методы класса Convert подробно рассматривались в главе 1.2.
· Цель и источник ссылочного типа. Здесь имеет место семантика ссылочного присваивания - присваивание ссылок. В этом случае значениями источника и цели являются ссылки на объекты, хранящиеся в динамической памяти («куче»). Если типы источника и цели совпадают, то никаких проблем нет. Цель разрывает связь с тем объектом, на который она ссылалась до присваивания, и становится ссылкой на объект, связанный с источником. Результат ссылочного присваивания двоякий. Объект, на который ссылалась цель, теряет одну из своих ссылок и может стать «висячим» -- бесполезным объектом, на который никто не ссылается, так что его дальнейшую судьбу определит сборщик мусора. После присваивания с объектом в памяти, на который ссылался источник, теперь связываются, по меньшей мере, две ссылки, рассматриваемые как различные имена одного объекта. Ссылочное присваивание приводит к созданию псевдонимов - к появлению разных имен у одного объекта. Особо следует учитывать ситуацию, когда цель и/или источник имеет значение null - нулевой ссылки, не указывающей ни на какой объект. Если такое значение имеет источник, то в результате присваивания цель получает это значение и более не ссылается ни на какой объект. Если же цель имела значение null, а источник нет, то в результате присваивания ранее «висячая» цель становится ссылкой на объект, связанный с источником. Если типы источника и цели разные, то присваивание без всяких преобразований возможно лишь в том случае, если источник является потомком родительского класса, заданного целью. Цель - родитель может быть связана с объектом своего потомка, поскольку в этом случае все поля и методы родителя имеются и у потомка и будут определены. Если же цель не принадлежит родительскому классу источника, то тогда ссылочное присваивание возможно лишь при условии явного задания приведения типов, но тогда вся ответственность за успех этого преобразования лежит на программисте, который должен быть уверен, что объект источника, связанный ссылкой действительно принадлежит классу целевого объекта.
· Цель ссылочного типа, источник значимого типа. В этом случае «на лету» значимый тип преобразуется в ссылочный. Как обеспечивается двойственность существования значимого и ссылочного типа - переменной и объекта? Ответ прост: за счет эффективно реализованной операции «упаковать» (boxing), выполняемой автоматически. Такое присваивание возможно лишь в том случае, когда цель принадлежит классу object. Поскольку класс object является родителем для всех классов, в том числе и для значимых классов, то при таком присваивании никаких ошибок возникать не будет, оно всегда возможно.
· Цель значимого типа, источник ссылочного типа. В этом случае «на лету» ссылочный тип преобразуется в значимый. Операция «распаковать» (unboxing) выполняет обратную операцию, - она «сдирает» объектную упаковку и извлекает хранимое значение. Заметьте, операция «распаковать» не является обратной к операции «упаковать» в строгом смысле этого слова. Операто рobject obj= xкорректен, но выполняемый следом оператор x = obj приведет к ошибке. Недостаточно, чтобы хранимое значение в упакованном объекте точно совпадало по типу с переменной, которой присваивается объект. Необходимо явно заданное преобразование к нужному типу.
Блок, или составной оператор
С помощью фигурных скобок несколько операторов языка (возможно, перемежаемых объявлениями) можно объединить в единую синтаксическую конструкцию, называемую блоком или составным оператором:
{
оператор_1
…
оператор_N
}
В языках программирования нет общепринятой нормы для использования символа точки с запятой при записи последовательности операторов. Есть три различных подхода и их вариации. Категорические противники точек с запятой считают, что каждый оператор должен записываться на отдельной строке (для длинных операторов определяются правила переноса). В этом случае точки с запятой (или другие аналогичные разделители) не нужны. Горячие поклонники точек с запятой (к ним относятся языки С++ и C#) считают, что точкой с запятой должен оканчиваться каждый оператор. В результате в операторе if перед else появляется точка с запятой. Третьи полагают, что точка с запятой не принадлежит оператору, а играет роль разделителя операторов. В выше приведенной записи блока, следуя синтаксису C#, каждый из операторов заканчивается символом точка с запятой. Но, заметьте, блок не заканчивается этим символом!
Синтаксически блок воспринимается как единичный оператор и может использоваться всюду в конструкциях, где синтаксис требует одного оператора. Тело цикла, ветви оператора if, как правило, представляются блоком.
Пустой оператор
Пустой оператор- это пусто, завершаемое точкой с запятой. Иногда полезно рассматривать отсутствие операторов как существующий пустой оператор. Вот пример:
if (a > b) ;
else
{
int temp = a; a = b; b = temp;
}
Это корректно работающий пример. А вот типичная для новичков ошибка:
for(int i = 0; i < n; i++);
}
Здесь телом цикла является пустой оператор.
Операторы выбора
Как в С++ и других языках программирования, в языке C# для выбора одной из нескольких возможностей используются две конструкции - if и switch. Первую из них обычно называют альтернативным выбором, вторую - разбором случаев.
Оператор if
Начнем с синтаксиса оператора if:
if(выражение_1) оператор_1
else if(выражение_2) оператор_2
else if(выражение_K) оператор_K
else оператор_N
Какие особенности синтаксиса следует отметить? Логические выражения if заключаются в круглые скобки и имеют значения true или false. Каждый из операторов может быть блоком, в частности if-оператором. Поэтому возможна и такая конструкция:
if(выражение1) if(выражение2) if(выражение3) …
Ветви else if, позволяющие организовать выбор из многих возможностей, могут отсутствовать. Может быть опущена и заключительная else-ветвь. В этом случае краткая форма оператора if задает альтернативный выбор - делать или не делать - выполнять или не выполнять then-оператор.
Семантика оператора if проста и понятна. Выражения if проверяются в порядке их написания. Как только получено значение true, проверка прекращается и выполняется оператор (это может быть блок), который следует за выражением, получившим значение true. С завершением этого оператора завершается и оператор if. Ветвь else, если она есть, относится к ближайшему открытому if.
Оператор switch
Частным, но важным случаем выбора из нескольких вариантов является ситуация, при которой выбор варианта определяется значениями некоторого выражения. Соответствующий оператор C#, унаследованный от C++, но с небольшими изменениями в синтаксисе, называется оператором switch. Вот его синтаксис:
switch(выражение)
{
case константное_выражение_1: [операторы_1 оператор_перехода_1]
…
case константное_выражение_K: [операторы_K оператор_перехода_K] [default: операторы_N оператор_перехода_N]
}
Ветвь default может отсутствовать. Заметьте, по синтаксису допустимо, чтобы после двоеточия следовала пустая последовательность операторов, а не последовательность, заканчивающаяся оператором перехода. Константные выражения в case должны иметь тот же тип, что и switch-выражение.
Семантика оператора switch чуть запутана. Вначале вычисляется значение switch-выражения. Затем оно поочередно в порядке следования case сравнивается на совпадение с константными выражениями. Как только достигнуто совпадение, выполняется соответствующая последовательность операторов case-ветви. Поскольку последний оператор этой последовательности является оператором перехода (чаще всего это оператор break), то обычно он завершает выполнение оператора switch. Использование операторов перехода - это плохая идея. Таким оператором может быть оператор goto, передающий управление другой case-ветви, которая в свою очередь может передать управление еще куда-нибудь, получая блюдо «спагетти» вместо хорошо структурированной последовательности операторов. Семантика осложняется еще и тем, что case-ветвь может быть пустой последовательностью операторов. Тогда в случае совпадения константного выражения этой ветви со значением switch-выражения будет выполняться первая непустая последовательность очередной case-ветви.
Если значение switch-выражения не совпадает ни с одним константным выражением, то выполняется последовательность операторов ветви default, если же таковой ветви нет, то оператор switch эквивалентен пустому оператору.
Полагаю, что оператор switch - это самый неудачный оператор языка C# как с точки зрения синтаксиса, так и семантики. Неудачный синтаксис порождает запутанную семантику, являющуюся источником плохого стиля программирования. Понять, почему авторов постигла неудача, можно, оправдать - нет. Дело в том, что оператор унаследован от С++, где его семантика и синтаксис еще хуже. В языке C# синтаксически каждая case-ветвь должна заканчиваться оператором перехода (забудем на минуту о пустой последовательности), иначе возникнет ошибка периода компиляции. В языке С++ это правило не является синтаксически обязательным, хотя на практике применяется та же конструкция с конечным оператором break. При его отсутствии управление «проваливается» в следующую case-ветвь. Конечно, профессионал может с успехом использовать этот трюк, но в целом ни к чему хорошему это не приводит. Борясь с этим, в C# потребовали обязательного включения оператора перехода, завершающего ветвь. Гораздо лучше было бы, если бы последним оператором мог быть только оператор break, как следствие, его можно было бы не писать, и семантика стала бы прозрачной - при совпадении значений двух выражений выполняются операторы соответствующей case-ветви, при завершении которой завершается и оператор switch.
Еще одна неудача в синтаксической конструкции switch связана с существенным ограничением, накладываемым на case-выражения, которые могут быть только константным выражением. Уж если изменять оператор, то гораздо лучше было бы использовать синтаксис и семантику Visual Basic, где в case-выражениях допускается список, каждое из выражений которого может задавать диапазон значений.
Разбор случаев - это часто встречающаяся ситуация в самых разных задачах. Применяя оператор switch, помните о недостатках его синтаксиса, используйте его в правильном стиле. Заканчивайте каждую case-ветвь оператором break, но не применяйте goto.
Содержательный пример применения оператора switch подробно рассмотрен в лекции 1.2. Рассмотрим еще один показательный пример, в котором вычисляется арифметическое выражение с двумя аргументами.
/// <summary>
/// Разбор случаев с использованием списков выражений
/// </summary>
/// <param name=»operation»>операция над аргументами</param>
/// <param name=»arg1?>первый аргумент бинарной операции</param>
/// <param name=»arg2?>второй аргумент бинарной операции</param>
/// <param name=»result»>результат бинарной операции</param>
public void ExprResult(string operation, double arg1, double arg2,
ref double result)
{
switch (operation)
{
case «+»:
case «Plus»:
case «Плюс»:
result = arg1 + arg2;
break;
case «-»:
case «Minus»:
case «Минус»:
result = arg1 -- arg2;
break;
case «*»:
case «Mult»:
case «Умножить»:
result = arg1 * arg2;
break;
case «/»:
case «Divide»:
case «Div»:
case «разделить»:
case «Делить»:
result = arg1 / arg2;
break;
default:
result = 0;
break;
}
}//ExprResult
Обратите внимание, знак операции над аргументами можно задавать разными способами, что демонстрирует возможность задания списка константных выражений в ветвях оператора switch.
Операторы перехода
Операторов перехода, позволяющих прервать естественный порядок выполнения операторов блока, в языке C# несколько.
Все операторы языка C# могут иметь метку - уникальный идентификатор, предшествующий оператору и отделенный от него символом двоеточия. Передача управления помеченному оператору - это классическое использование оператора goto. Оператор goto может использоваться в операторе switch, о чем шла речь выше.
«О вреде оператора goto» и о том, как можно обойтись без него, писал еще Эдсгар Дейкстра при обосновании принципов структурного программирования.
Я уже многие годы не применяю этот оператор и считаю, что хороший стиль программирования не предполагает использования этого оператора в C# ни в каком из вариантов - ни в операторе switch, ни для организации безусловных переходов.
Операторы break и continue
В структурном программировании признаются полезными «переходы вперед» (но не назад), позволяющие при выполнении некоторого условия выйти из цикла, из оператора выбора, из блока. Операторы break и continue специально предназначены для этих целей.
Оператор breakможет стоять в теле цикла или завершать case-ветвь в операторе switch. Пример его использования в операторе switch уже демонстрировался. При выполнении оператора break в теле цикла завершается выполнение самого внутреннего цикла. В теле цикла, чаще всего, оператор break помещается в одну из ветвей оператора if, проверяющего условие преждевременного завершения цикла. Классическим примером является «поиск по образцу», когда в массиве ищется элемент, соответствующий образцу. Понятно, что когда такой элемент найден, поиск можно прекратить. Вот пример метода, реализующего данную стратегию поиска:
/// <summary>
/// Поиск образца в массиве
/// </summary>
/// <param name=»ar»>массив для поиска</param>
/// <param name=»pat»>образец поиска</param>
/// <param name=»patIndex»>индекс найденного элемента</param>
/// <returns>
/// true, если найден элемент, совпадающий с образцом
/// false, в противном случае
/// </returns>
public bool SearchPattern(int[] ar, int pat, out int patIndex)
{
int n = ar.Length;
patIndex = -1;
bool found = false;
for (int i = 0; i < n; i++)
if (ar[i] == pat)
{
found = true;
patIndex = i;
break;
}
return found;
}
Оператор continue используется только в теле цикла. В отличие от оператора break, завершающего внутренний цикл, continue осуществляет переход к следующей итерации этого цикла.
Оператор return
Еще одним оператором, относящимся к группе операторов перехода, является оператор return, позволяющий завершить выполнение процедуры или функции. Его синтаксис:
return [выражение];
Для функций его присутствие и аргумент обязательны, поскольку выражение в операторе return задает значение, возвращаемое функцией.
Операторы цикла
Без циклов жить нельзя в программах, нет.
Оператор for
Наследованный от С++ весьма удобный оператор цикла for обобщает известную конструкцию цикла типа арифметической прогрессии. Его синтаксис: for(инициализаторы; условие; список_выражений) оператор
Оператор, стоящий после закрывающей скобки, задает тело цикла. В большинстве случаев телом цикла является блок. Сколько раз будет выполняться тело цикла, зависит от трех управляющих элементов, заданных в скобках. Инициализаторы задают начальное значение одной или нескольких переменных, часто называемых счетчиками или просто переменными цикла. В большинстве случаев цикл for имеет один счетчик, но часто полезно иметь несколько счетчиков, что и будет продемонстрировано в следующем примере. Условие задает условие окончания цикла, соответствующее выражение при вычислении должно получать значение true или false. Список выражений, записанный через запятую, показывает, как меняются счетчики цикла на каждом шаге выполнения. Если условие цикла истинно, то выполняется тело цикла, затем изменяются значения счетчиков и снова проверяется условие. Как только условие становится ложным, цикл завершает свою работу. В цикле for тело цикла может ни разу не выполняться, если условие цикла ложно после инициализации, а может происходить зацикливание, если условие всегда остается истинным. В нормальной ситуации тело цикла выполняется конечное число раз.
Счетчики цикла зачастую объявляются непосредственно в инициализаторе и соответственно являются переменными, локализованными в цикле, так что после завершения цикла они перестают существовать. В тех случаях, когда предусматривается возможность преждевременного завершения цикла с помощью одного из операторов перехода, счетчики объявляются до цикла, что позволяет анализировать их значения при выходе из цикла.
В качестве примера рассмотрим еще одну классическую задачу: является ли строка текста палиндромом. Напомню, палиндромом называется симметричная строка текста, читающаяся одинаково слева направо и справа налево. Для ее решения цикл for подходит наилучшим образом: здесь используются два счетчика - один возрастающий, другой убывающий. Вот текст соответствующей процедуры:
/// <summary>
/// Определение палиндромов.
/// Демонстрация цикла for
/// </summary>
/// <param name=»str»>текст</param>
/// <returns>true -- если текст является палиндромом</returns>
public bool IsPalindrom(string str)
{
for (int i = 0, j = str.Length -- 1; i < j; i++, j--)
if (str[i] != str[j]) return (false);
return (true);
}//IsPalindrom
В цикле for разрешается опускать некоторые части заголовка цикла. Конструкция этого оператора, в которой все части заголовка опущены, задает бесконечный цикл: for(;;) {…}
Эта конструкция позволяет организовать цикл с проверкой выхода в теле цикла. Ярые любители оператора for, к которым чаще всего относятся любители стиля языка С++, часто пользуются такой конструкцией. Я отношу это к нарушениям хорошего стиля программирования. В таких ситуациях лучше использовать цикл типа while.
Циклы While
Цикл while (выражение) является универсальным видом цикла, включаемым во все языки программирования. Тело цикла выполняется до тех пор, пока остается истинным выражение while. В языке C# у этого вида цикла две модификации - с проверкой условия в начале и в конце цикла. Первая модификация имеет следующий синтаксис: while(выражение) оператор
Эта модификация соответствует стратегии: «сначала проверь, а потом делай». В результате проверки может оказаться, что и делать ничего не нужно. Тело такого цикла может ни разу не выполняться. Конечно же, возможно и зацикливание. В нормальной ситуации каждое выполнение тела цикла - это очередной шаг к завершению цикла.
Цикл, проверяющий условие завершения в конце, соответствует стратегии: «сначала делай, а потом проверь». Тело такого цикла выполняется, по меньшей мере, один раз. Вот синтаксис этой модификации:
do
оператор
while(выражение);
Приведу пример, в котором участвуют обе модификации цикла while. Во внешнем цикле проверка выполняется в конце, во внутреннем - в начале. Внешний цикл представляет собой типичный образец организации консольных программ, когда в диалоге с пользователем многократно решается некоторая задача. На каждом шаге пользователь вводит новые данные, решает задачу и анализирует полученные данные. В его власти, продолжить вычисления или нет, но хотя бы один раз решить задачу ему приходится. Внутренний цикл do while используется для решения уже известной задачи с палиндромами. Вот текст соответствующей процедуры:
/// <summary>
///Два цикла: с проверкой в конце и в начале.
///Внешний цикл -- образец многократно решаемой задачи.
///Завершение цикла определяется в диалоге с пользователем.
/// </summary>
public voidLoop()
{
string answer, text;
do
{
Console.WriteLine(«Введите текст»);
text = Console.ReadLine();
int i =0, j = text.Length-1;
while ((i < j) && (text[i] == text[j]))
{i++; j--;}
if (text[i] == text[j])
Console.WriteLine(text +» -- это палиндром!»);
else
Console.WriteLine(text +» -- это не палиндром!»);
Console.WriteLine(«Продолжим? (yes/no)»);
answer = Console.ReadLine();
}
while(answer ==»yes»);
}//Loop
Цикл foreach
Новым видом цикла, не унаследованным от С++, является цикл foreach, удобный при работе с массивами, коллекциями и другими подобными контейнерами данных. Его синтаксис: foreach(тип идентификатор in контейнер) оператор
Цикл работает в полном соответствии со своим названием - тело цикла выполняется для каждого элемента в контейнере. Тип идентификатора должен быть согласован с типом элементов, хранящихся в контейнере данных. Предполагается также, что элементы контейнера (массива, коллекции) упорядочены. На каждом шаге цикла идентификатор, задающий текущий элемент контейнера, получает значение очередного элемента в соответствии с порядком, установленном на элементах контейнера. С этим текущим элементом и выполняется тело цикла -- выполняется столько раз, сколько элементов находится в контейнере. Цикл заканчивается, когда полностью перебраны все элементы контейнера.
Серьезным недостатком циклов foreach в языке C# является то, что цикл работает только на чтение, но не на запись элементов. Так что наполнять контейнер элементами приходится с помощью других операторов цикла.
В приведенном ниже примере показана работа с трехмерным массивом. Массив создается с использованием циклов типа for, а при нахождении суммы его элементов, минимального и максимального значения используется цикл foreach:
/// <summary>
///Демонстрация цикла foreach.
///Вычисление суммы, максимального и минимального
///элементов трехмерного массива,
///заполненного случайными числами.
/// </summary>
public void SumMinMax()
{
int [,,] arr3d = new int[10,10,10];
Random rnd = new Random();
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
for (int k = 0; k < 10; k++)
arr3d[i, j, k]= rnd.Next(100);
long sum = 0; int min = max = arr3d[0,0,0];
foreach(int item in arr3d)
{
sum +=item;
if (item > max) max = item;
else if (item < min) min = item;
}
Console.WriteLine(«sum = {0}, min = {1}, max = {2}»,
sum, min, max);
}//SumMinMax
Специальные операторы
Операторы языка C#, рассмотренные выше, имеют аналоги практически во всех языках программирования. Рассмотрим теперь более экзотические операторы, не столь часто появляющиеся в других языках программирования.
Оператор yield
При рассмотрении оператора цикла foreach говорилось, что он применим к классам, содержащим контейнеры, и цикл foreach перебирает элементы контейнера в некотором заданном порядке. Для того чтобы класс содержал контейнер, он должен быть перечислимым, будучи наследником интерфейса IEnumerable. Есть другая возможность, -- класс может иметь один или несколько методов, называемых итераторами, создающими контейнеры и возвращающие результат интерфейсного класса IEnumerable.
Оператор yield используется в итераторах и позволяет заполнять контейнер элементами. Его синтаксис:
yield return <выражение>;
Каждое выполнение оператора yield добавляет новый элемент в контейнер. Подробно рассмотрение этого оператора будет дано в главе посвященной интерфейсам. Сейчас же ограничусь одним примером. В класс Testing, используемый в нашем проекте, добавим итератор, создающий коллекцию:
/// <summary>
/// Итератор, создающий коллекцию цветов
/// </summary>
/// <returns>коллекцию </returns>
public System.Collections.IEnumerable Rainbow()
{
yield return «red»;
yield return «orange»;
yield return «yellow»;
yield return «green»;
yield return «blue»;
yield return «violet»;
}
Клиенты этого класса могут работать с этой коллекцией, например так:
string colors = «»;
foreach(string s in tst.Rainbow())
colors += s + «-»;
Здесь tst - объект класса Testing, а переменная s в цикле foreach получит значения всех цветов, помещенных в контейнер оператором yield. Следует заметить, что реально никакие контейнеры не создаются, а цикл foreach на каждом шаге вызывает итератор и создает новый элемент. Именно поэтому цикл foreach работает только на чтение элементов и не работает на запись.
Операторы try, catch, finally
Об охраняемых блоках, блоках, перехватывающих исключения, задаваемых операторами try, catch, finally, мы уже говорили в главе 1.2 и приводили достаточное число примеров. Тема организации обработки исключительных ситуаций и соответствующие операторы будут подробно рассматриваться в отдельной главе, а примеры их использования будут появляться повсеместно.
Операторы checked и unchecked
В лекции 1.3 рассматривались проверяемые и непроверяемые выражения и блоки. Блоки с предшествующими словами checked и unchecked и являются соответствующими операторами. Полагаю, что приведенных ранее сведений достаточно для понимания синтаксиса, семантика и области применения этих операторов.
Оператор fixed
Оператор fixed используется в небезопасных (unsafe) блоках, позволяя фиксировать в памяти расположение переменных, на которые ссылаются указатели. Такая фиксация не позволяет сборщику мусора перемещать зафиксированные переменные. Поскольку в данном курсе работа с указателями, прямая адресация и другие опасные средства, характерные для языка С++, не рассматриваются, то оператор fixed рассматриваться не будет и не будет встречаться в примерах этого курса.
Оператор lock
Оператором lock, блоком lock, критической секцией кода, закрытым блоком называют блок с предшествующим ключевым словом lock
lock {…}
Этот оператор используется при работе с несколькими потоками. Он позволяет закрыть блок кода для одновременной работы нескольких потоков. Ни один поток не сможет войти в закрытый блок, если другой поток уже выполняет код критической секции. Остальные потоки будут ждать, пока закрытый блок не будет освобожден.
Проект Statements
Как обычно, для этой главы построено решение с именем Ch4, содержащее Windows- проект с именем Statements. В проекте создан класс Testting, методы которого позволяют тестировать работу операторов языка C#. Эти методы используются в примерах, приведенных в этой главе.
Архитектурно проект представляет Windows-приложение с главной кнопочной формой. Каждый из интерфейсных классов, включенных в проект, обеспечивает пользовательский интерфейс для работы с тем или иным методом класса Testing.
Интернет ресурс [http://edu.cps.tver.ru/archives/1391]
Значение аргумента х изменяется от а до b с шагом h. Для каждого х найдите значение функции Y(x), суммы S(x) и и выведите в виде таблицы. Значения а, b, h введите с клавиатуры произвольно. Вычисление Y(x) и S(x) реализуйте в виде функций.
В основной программе организуйте ввод исходных данных, обращение к функциям и вывод результатов.
.
namespace Q1_2
{
class Program
{
public static double S(double x,int n)
{
int zn = 1;//переменная для хранения знаменателя
double pX = x / 2;//переменная для хранения x/2
double mn = 1;//переменная для хранения множителя
double rez = 0;//переменная - результат
for (int k = 0;k <= n; k++)//цикл изменения k
{
if (k == 0)//если K=0
{
zn = 1;//знаменатель =1
n = 1;//множитель =1
}
else
{
zn *= k;//знаменатель умножаем на k, получаем (k!)
mn *= pX;//множитель умножаем на x/2, получаем ((x/2)^k)
}
rez += ((Math.Pow(k, 2.0)+1)/zn)*mn;//прибавляем к результату текущее вычисление
}
return rez;//возвращаем результат
}
public static double Y(double x)//функция для нахождения Y(x)
{
var pX = x / 2;//переменная для хранения x/2
var rez = (((x*x)/4) + pX + 1)*Math.Pow(Math.E, pX);//производим вычисление
return rez;//возвращаем результат
}
static void Main(string[] args)
{
Console.WriteLine("Введите a");
double a = double.Parse(Console.ReadLine());//считываем a
Console.WriteLine("Введите b");
double b = double.Parse(Console.ReadLine());//считываем b
Console.WriteLine("Введите h");
double h = double.Parse(Console.ReadLine());//считываем h
Console.WriteLine("Введите n");//просим ввести n
int n = int.Parse(Console.ReadLine());//считываем n
double y;
double s;
double tmp;
while (a<=b)//пока мы не достигли правого предела или не стали больше него
{
Console.WriteLine("X={0}",a);
y = Y(a);
s = S(a,n);
tmp = Math.Abs(y - s);
Console.WriteLine("Y(x)={0}", y);
Console.WriteLine("S(x)={0}", s);
Console.WriteLine("|Y(x)-S(x)|={0}", tmp);
a += h;
}
if (a != b)//если последнее значение было не правым пределом(попадем под условие, если при добавлении h, значение перепрыгнуло порог b)
{
a = b;
Console.WriteLine("X={0}", a);
y = Y(a);
s = S(a, n);
tmp = Math.Abs(y - s);
Console.WriteLine("Y(x)={0}", y);
Console.WriteLine("S(x)={0}", s);
Console.WriteLine("|Y(x)-S(x)|={0}", tmp);
}
Console.ReadKey();
}
}
}
Рисунок 1
3. В одномерном массиве, состоящем из n вещественных элементов, вычислить:
- максимальный по модулю элемент массива;
- сумму элементов массива, расположенных между первым и вторым положительными элементами.
namespace Q1_3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Введите n");//просим ввести n
int n = int.Parse(Console.ReadLine());//считываем n
float [] mas=new float[n];//создаем массив
for (int i = 0; i < n; i++)//цикл по элементам массива
{
Console.Write("Введите mas[{0}]: ",i+1);//просим ввести i элемент массива
mas[i] = float.Parse(Console.ReadLine());//считвываем элемент массива
}
int maxI = 0;//индекс максимального по модлю элемента
for (int i = 1; i < n; i++)//цикл по массиву
{
if (Math.Abs(mas[i])>Math.Abs(mas[maxI]))//если текущее значение элемента(по модулю), больше модуля максимального элемента
{
maxI=i;//прибавляем его к переменной для подсчета суммы отрицательных элементов
}
}
Console.WriteLine("Максимальный по модулю элемент массива: {0}",mas[maxI]);//выводим максимальный по модулю элемент массива
int L = -1;//индекс первого положительного элемента
int R = -1;//индекс второго положительного элемента
for (int i = 0; i < n; i++)//цикл по массиву
{
if (mas[i]>0)//если элемент положительный
{
if (L == -1)//если первого положительного небыло
{
L = i;//помечаем что это первый
}
else//иначе
{
R = i;//это второй положительный
break;//выходим из цикла
}
}
if ((L == -1) || (R == -1))//если мы не нашли первого или второго положительного элемента
{
Console.WriteLine("В массиве нет двух положительных элементов");
}
else//иначе
{
float f = 0;//счетчик суммы
for (int i = L; i <=R; i++)//цикл
{
f += mas[i];
Console.WriteLine("Сумма элементов между первым и вторым положительными элементами (включая их): {0}", f);//выводим сообщение
}
Console.ReadKey();//ждем нажатие клавиши
}
Рисунок 2
4. Дана целочисленная прямоугольная матрица. Определить:
- сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент;
- номера строк и столбцов всех седловых точек матрицы. (Матрица А имеет седловую точку Аij, если Аij является минимальным элементом в i-й строке и максимальным в j-м столбце и наоборот).
программа прямоугольный матрица синтаксический
namespace Q1_3
{
class Program
{
static void Main(string[] args)
{
Console.Write("Введите число строк матрицы: ");//просим ввести число строк матрицы
int n = int.Parse(Console.ReadLine());//считываем количество строк
Console.Write("Введите число столбцов матрицы: ");//просим ввести число столбцов матрицы
int m = int.Parse(Console.ReadLine());//считываем количество столбцов
int[,] Matr = new int[n, m];//создаем матрицу
for (int i = 0; i < n; i++)//цикл по строкам
{
for (int j = 0; j < m; j++)//цикл по столбцам
{
Console.WriteLine("Введите Matr[{0},{1}]= ",i+1,j+1);//просим ввести элемент
Matr[i, j] = int.Parse(Console.ReadLine());//считываем элемент
}
}
for (int i = 0; i < n; i++)//цикл по строкам
{
bool fl = false;
int sum = 0;
for (int j = 0; j < m; j++)//цикл по столбцам
{
if (Matr[i, j] < 0) //если отрицательный элемент
{
fl = true;//поднимаем флаг
break;//выходим их цикла
}
}
if (fl)//если флаг поднят
{
for (int j = 0; j < m; j++)//цикл по столбцам
{
sum += Matr[i, j];
}
Console.WriteLine("Строка {0}, сумма элементов: {1}",i+1,sum);
}
}
var f = false;//флаг - есть ли седловые точки
for (int i = 0; i < n; i++)//цикл по строкам
{
var minel= Matr[i,0];//минимальному элементу текущей строки присваиваем первый элемент текущей строки
for (int j = 0; j < m; j++)
{
if (minel>Matr[i,j])//находим минимальный элемент текущей строки
{minel = Matr[i, j];}
}
for (int j = 0; j < m; j++)//повторно бежим по строке
{
if (Matr[i,j]==minel)//если текущий элемент минимальный
{
var z = true;
for (int k = 0; k < n; k++)//бежим по элементам j-го столбца
{
if (Matr[k,j]>minel)//если нашли элемент, который больше чем минимальный элемент в строке
{
z = false;//опускаем флаг
break;//выходим с цикла
}
}
if (z)//если флаг поднят
{
Console.WriteLine("Седловая точка Matr[{0},{1}]={2}",i+1,j+1,Matr[i,j]);
f = true;
}
}
if (!f)
{
Console.WriteLine("Седловых точек в матрице нет");
}
Console.ReadKey();//ждем нажатие клавиши
}
}
Рисунок 3
5. Составьте программу, которая будет вводить строку в переменную String. Напечатайте в алфавитном порядке все слова из данной строки, имеющие заданную длину n
namespace Q1_4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Введите строку");//просим ввести строку
var s = Console.ReadLine();//считываем строку
Console.WriteLine("Введите n");
int n = int.Parse(Console.ReadLine());//считываем n
string[] slova = s.Split(' ');//разбиваем текст на слова
List<string> good = new List<string>();//создаем List слов
foreach (var m in slova)//цикл по массиву слов
{
if (m.Length == n)//если слово длинны n
{good.Add(m.ToLower());//добавляем в list
}
}
good.Sort();//сортировка
foreach (var a in good)
{
Console.WriteLine(a);//вывод слов
}
Console.ReadKey();//ждем нажатие клавиш
}
}
}
Рисунок 4
Список литературы
1. Интернет ресурс [http://edu.cps.tver.ru/archives/1391]
2. Эндрю Троелсен. Язык программирования C# 2010 и платформа.NET 4.
3. А. Хейлсберг, М. Торгерсен, С. Вилтамут, П. Голд. Язык программирования C#.
4. Чарльз Петцольд. Microsoft Windows Presentation Foundation. Базовый курс.
5. Мак-Дональд, Мэтью. Windows Presentation Foundation в.NET 4.0 с примерами на С# 2010 для профессионалов
Размещено на Allbest.ru
...Подобные документы
Разработка программы, которая выявляет в прямоугольной матрице все подматрицы, состоящие только из m-значных целых чисел. Использование компилируемого языка программирования общего назначения C/C++. Обработка алгоритмов, кодирование программных средств.
курсовая работа [980,1 K], добавлен 05.03.2015Понятие и специфические особенности языка программирования Си, история его создания. Интегрированная система Borland C. Процесс программирования с помощью данного языка. Графические примитивы в языках программирования. Преобразования на плоскости.
курс лекций [782,2 K], добавлен 04.10.2011Использование в операционной системе UNIX языка программирования СИ. Требования к квалификации программиста. Механизм ветвления по условиям, циклы, составные инструкции. Особенности языка СИ. Доступ к памяти компьютера через использование указателей.
презентация [108,6 K], добавлен 22.05.2015Разработка структурной диаграммы программного модуля. Представление схемы для основных расчетов выбранного приложения для создания прямоугольной матрицы. Особенности создания пользовательского интерфейса. Тестирование и отладка спроектированного модуля.
курсовая работа [648,4 K], добавлен 27.05.2015Ознакомление с возможностями языка Си как средой программирования высокого уровня. Циклы программирования параметрического оператора for и функции форматированного ввода. Разработка программы средствами Си: блок-схема, текст и тестирование программы.
контрольная работа [204,4 K], добавлен 26.01.2013Описание алгоритма решения задачи по вычислению суммы элементов строк матрицы с использованием графического способа. Детализация укрупненной схемы алгоритма и разработка программы для решения задачи в среде Turbo Pascal. Листинг и тестирование программы.
курсовая работа [446,0 K], добавлен 19.06.2014Изучение общей структуры языка программирования Delphi: главные и дополнительные составные части среды программирования. Синтаксис и семантика языка программирования Delphi: алфавит языка, элементарные конструкции, переменные, константы и операторы.
курсовая работа [738,1 K], добавлен 17.05.2010Машинные коды и ассемблер. Первые языки программирования высокого уровня. Язык программирования FORTRAN. Достоинства и недостатки ALGOL. Научные и бухгалтерские программы. Основные принципы, которые соблюдались при создании языка программирования Basic.
курсовая работа [407,4 K], добавлен 21.06.2014Характеристика базовых конструкций языков программирования. Изучение истории их развития и классификации. Определение основных понятий языков программирования. Описание основных операторов, которые используются в языках программирования высокого уровня.
курсовая работа [400,6 K], добавлен 10.11.2016Характерные черты программирования на алгоритмическом языке СИ (алфавит, операции, специфика операторов, комментарии и другие элементы). Аналитический обзор и рассмотрение примеров программ, иллюстрирующих особенности применения основных операторов СИ.
презентация [251,0 K], добавлен 26.07.2013Составление программы разветвляющейся структуры для вычисления заданной функции. Нахождение произведения чётных и нечётных первых чисел натурального ряда. Приёмы программирования обработки одномерных массивов. Расчет суммы положительных элементов массива.
контрольная работа [1,3 M], добавлен 20.12.2012Изучение элементов языка С++, программирование разветвлений и циклов с использованием операторов условного и перехода. Обработка одномерных массивов. Поиск максимального элемента массива с заданной размерностью. Листинги программы и результатов.
курсовая работа [647,7 K], добавлен 05.02.2013Язык программирования как формальная знаковая система, предназначенная для записи программ, его отличие от естественных языков. Прописные и строчные буквы латинского алфавита. Ключевые слова языка программирования. Классическая схема создания программы.
презентация [1,2 M], добавлен 19.02.2014Интерфейсные средства СУБД MS Access 2003. Проектирование схемы данных. Создание составного отчёта, содержащего диаграмму. Группировка и сортировка в отчётах. Использование языка программирования VBА, создание макросов. Разработка программы и функций.
курсовая работа [5,2 M], добавлен 20.06.2010Язык программирования как набор лексических и синтаксических правил, задающих внешний вид программы. Двоичное представления команд в универсальных программах и применение Ассамблера для создания макросов и меток. Разработка языков Фортран, Паскаль и Си.
презентация [828,5 K], добавлен 10.05.2011Целесообразность выбора языка программирования. Основные структуры языка программирования. Кодирование по методу четности/нечетности, по методу Хэмминга. Машина Поста. Инструкция программиста и пользователя. Использование программы StudyProgram.
курсовая работа [294,7 K], добавлен 27.02.2009Логические конструкции в системе программирования Паскаль. Команды языка программирования, использование функций, процедур. Постановка и решение задач механики в среде системы Паскаль. Задачи статики, кинематики, динамики решаемые с помощью языка Паскаль.
курсовая работа [290,9 K], добавлен 05.12.2008Алфавит языка программирования C#. Лексемы языка программирования. Область действия переменных. Понятие классов и объектов. Структура программного модуля на С#. Управление процессом повторения вычислений. Продолжение цикла и модификация параметра цикла.
курсовая работа [557,1 K], добавлен 10.03.2014Создание программы на языке программирования С#, которая проверяет наличие в матрице хотя бы одного столбца, содержащего положительный элемент, поиск его номера. Упорядочивание его элементов по возрастанию. Листинг программы и инструкция по работе с ней.
курсовая работа [1,9 M], добавлен 28.05.2014История языка Pascal, его основные концепции. Линейный и циклический алгоритмы, типы данных. Условные операторы, операторы цикла. Программа вычисления суммы n первых членов геометрической прогрессии по любым двум ее членам, номера которых известны.
отчет по практике [421,8 K], добавлен 07.06.2010