Программирование на языке высокого уровня C#

Массивы, символы и строки

Разбить на страницы
Показывать лекцию целиком

Массивы

Презентацию к данной лекции Вы можете скачать здесь.

Массив — это ограниченная совокупность однотипных величин. Элементы массива имеют одно и то же имя, а различаются по порядковому номеру ( индексу ).

Массив в С# относится к ссылочным типам данных, то есть располагается в динамической области памяти, поэтому создание массива начинается с выделения памяти под его элементы. Элементами массива могут быть величины как значимых, так и ссылочных типов (в том числе массивы). Массив значимых типов хранит значения, массив ссылочных типов — ссылки на элементы. Всем элементам при создании массива присваиваются значения по умолчанию: нули для значимых типов и null для ссылочных.

На рис 6.1 представлен массив, состоящий из пяти элементов любого значимого типа, например, int или double, а рисунок 6.2 иллюстрирует организацию массива из элементов ссылочного типа.

(рис 6.2) Простые переменные и массив из элементов значимого типа(рис 6.1) Массив из элементов ссылочного типа

Вот, например, как выглядят операторы создания массива из 10 целых чисел и массива из 100 строк:

int[]    w = new int[10];
string[] z = new string[100];

В первом операторе описан массив w типа int[]. Операция new выделяет память под 10 целых элементов, и они заполняются нулями.

Во втором операторе описан массив z типа string[].Операция new выделяет память под 100 ссылок на строки, и эти ссылки заполняются значением null. Память под сами строки, составляющие массив, не выделяется — это будет необходимо сделать перед заполнением массива.

Количество элементов в массиве ( размерность ) не является частью его типа, оно задается при выделении памяти и не может быть изменено впоследствии. Размерность может задаваться не только константой, но и выражением. Результат вычисления этого выражения должен быть неотрицательным, а его тип должен иметь неявное преобразование к int, uint, long или ulong.

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

w[4]        z[i]

С элементом массива можно делать все, что допустимо для переменных того же типа. Если при работе с массивом значение индекса выходит за границы массива, генерируется исключение IndexOutOfRangeException.

Массивы одного типа можно присваивать друг другу. При этом происходит присваивание ссылок, а не элементов, как и для любого другого объекта ссылочного типа, например:

int[] a = new int[10];
int[] b = a;             // b и a указывают на один и тот же массив

Все массивы в C# имеют общий базовый класс Array, определенный в пространстве имен System. В нем есть несколько полезных методов, упрощающих работу с массивами, например, методы получения размерности, сортировки и поиска. Мы рассмотрим эти методы немного позже в разделе "Класс System.Array".

В C# существуют три разновидности массивов: одномерные, прямоугольные и ступенчатые (невыровненные). О последних, менее распространенных, можно прочитать в учебнике (Павловская Т. А. С#. Программирование на языке высокого уровня. — СПб.: Питер, 2010), а сейчас займемся одномерными массивами.

Одномерные массивы

Одномерные массивы используются в программах чаще всего. Варианты описания массива:

тип[] имя;
тип[] имя = new тип [ размерность ];
тип[] имя = { список_инициализаторов };
тип[] имя = new тип [] { список_инициализаторов };
тип[] имя = new тип [ размерность ] { список_инициализаторов };

Примеры описаний (один пример на каждый вариант описания):

int[] a;                                    // 1    элементов нет
int[] b = new int[4];                       // 2    элементы равны 0
int[] c = { 61, 2, 5, -9 };                 // 3    new подразумевается
int[] d = new int[] { 61, 2, 5, -9 };       // 4    размерность вычисляется
int[] e = new int[4] { 61, 2, 5, -9 };      // 5    избыточное описание

Здесь описано пять массивов. Отличие первого оператора от остальных состоит в том, что в нем фактически описана только ссылка на массив, а память под элементы массива не выделена.

В каждом из остальных массивов по четыре элемента целого типа. Как видно из операторов 3–5, массив при описании можно инициализировать. Если при этом не задана размерность (оператор 3), количество элементов вычисляется по количеству инициализирующих значений. Для полей объектов и локальных переменных можно опускать операцию new, она будет выполнена по умолчанию (оператор 2). Если присутствует и размерность, и список инициализаторов, размерность должна быть константой (оператор 4).

В качестве примера рассмотрим программу, которая определяет сумму и количество отрицательных элементов, а также максимальный элемент массива, состоящего из 6 целочисленных элементов (листинг 6.1).

using System;
namespace ConsoleApplication1
{    class Class1
    {
        static void Main()
        {
            const int n = 6;
            int[] a = new int[n] { 3, 12, 5, -9, 8, -4 };

            Console.WriteLine( "Исходный массив:" );
            for ( int i = 0; i < n; ++i )
                Console.Write( "\t" + a[i] );
            Console.WriteLine();

            long sum = 0;              // cумма отрицательных элементов
            int  num = 0;              // количество отрицательных элементов
            for ( int i = 0; i < n; ++i )
                if ( a[i] < 0 )
                {
                    sum += a[i];
                    ++num;
                }

            Console.WriteLine( "Сумма  отрицательных = " + sum );
            Console.WriteLine( "Кол-во отрицательных = " + num );

            int max = a[0];             // максимальный элемент
            for ( int i = 1; i < n; ++i )
                if ( a[i] > max ) max = a[i];

            Console.WriteLine( "Максимальный элемент = " + max );
        }
    }
}

Обратите внимание, что для вывода массива требуется организовать цикл.

Прямоугольные массивы

Прямоугольный массив имеет более одного измерения. Чаще всего в программах используются двумерные массивы. Варианты описания двумерного массива:

тип[,] имя;
тип[,] имя = new тип [ разм_1, разм_2 ];
тип[,] имя = { список_инициализаторов };
тип[,] имя = new тип [,] { список_инициализаторов };
тип[,] имя = new тип [ разм_1, разм_2 ] { список_инициализаторов };

Примеры описаний (один пример на каждый вариант описания):

int[,] a;                                      // 1  элементов нет
int[,] b = new int[2, 3];                      // 2  элементы равны 0
int[,] c = {{1, 2, 3}, {4, 5, 6}};             // 3  new подразумевается
int[,] c = new int[,] {{1, 2, 3}, {4, 5, 6}};  // 4  размерность вычисляется
int[,] d = new int[2,3] {{1, 2, 3}, {4, 5, 6}};// 5  избыточное описание

К элементу двумерного массива обращаются, указывая номера строки и столбца, на пересечении которых он расположен, например:

a[1, 4]        b[i, j]        b[j, i]

Внимание

Необходимо помнить, что компилятор воспринимает как номер строки первый индекс, как бы он ни был обозначен в программе.

В качестве примера рассмотрим программу, которая для целочисленной матрицы размером 3 x 4 определяет среднее арифметическое ее элементов и количество положительных элементов в каждой строке.

Для нахождения среднего арифметического элементов массива требуется найти их общую сумму, после чего разделить ее на количество элементов. Порядок перебора элементов массива (по строкам или по столбцам) роли не играет. Нахождение количества положительных элементов каждой строки требует просмотра матрицы по строкам. Схема алгоритма приведена на рис 6.3, программа — в листинге 6.2.

using System;
namespace ConsoleApplication1
{    class Class1
    {
        static void Main()
        {
            const int m = 3, n = 4;
            int[,] a = new int[m, n] {
                { 2,-2, 8, 9 }, 
                {-4,-5, 6,-2 },
                { 7, 0, 1, 1 } 
             };

            Console.WriteLine( "Исходный массив:" );
            for ( int i = 0; i < m; ++i )
            {
                for ( int j = 0; j < n; ++j )
                    Console.Write( "\t" + a[i, j] );
                Console.WriteLine();
            }

            double sum = 0;
            int nPosEl;
            for ( int i = 0; i < m; ++i )
            {
                nPosEl = 0;
                for ( int j = 0; j < n; ++j )
                {
                    sum += a[i, j];
                    if ( a[i, j] > 0 ) ++nPosEl;
                }
                Console.WriteLine( "В строке {0} {1} положит-х элементов", 
                    i, nPosEl  );
            }
            Console.WriteLine( "Среднее арифметическое всех элементов: " 
                + sum / m / n );
        }
    }
}

Ступенчатые массивы

В ступенчатых массивах количество элементов в разных строках может различаться. В памяти ступенчатый массив хранится иначе, чем прямоугольный: в виде нескольких внутренних массивов, каждый из которых имеет свой размер. Кроме того, выделяется отдельная область памяти для хранения ссылок на каждый из внутренних массивов (рис 6.3).

(рис 6.3) Ступенчатый массив

Фрагмент программы, иллюстрирующий работу со ступенчатым массивом, приведен в листинге 6.5 (после рассмотрения оператора foreach ).

Класс System.Array

Все массивы в C# построены на основе базового класса Array, который содержит полезные для программиста свойства и методы, часть из которых перечислена в таблилце 6.1.

Некоторые элементы класса Array
Элемент Вид Описание
Length Свойство Количество элементов массива (по всем размерностям)
BinarySearch Статический метод Двоичный поиск в отсортированном массиве
Clear Статический метод Присваивание элементам массива значений по умолчанию
Copy Статический метод Копирование заданного диапазона элементов одного массива в другой массив
GetValue Метод Получение значения элемента массива
IndexOf Статический метод Поиск первого вхождения элемента в одномерный массив
Reverse Статический метод Изменение порядка следования элементов на обратный
Sort Статический метод Упорядочивание элементов одномерного массива

В листинге 6.3 продемонстрировано применение элементов класса Array при работе с одномерным массивом.

using System;
namespace ConsoleApplication1
{    class Class1
    {   static void Main()
        {
            int[] a =  { 24, 50, 18, 3, 16, -7, 9, -1 };

            PrintArray( "Исходный массив:", a );
            Console.WriteLine( Array.IndexOf( a, 18 ) ); 

            Array.Sort(a);
            PrintArray( "Упорядоченный массив:", a );
            Console.WriteLine( Array.BinarySearch( a, 18) );
        }

        public static void PrintArray( string header, int[] a )
        {
            Console.WriteLine( header );
            for ( int i = 0; i < a.Length; ++i )
                Console.Write( "\t" + a[i] );
            Console.WriteLine();
        }
    }
}

Методы Sort, IndexOf и BinarySearch являются статическими, поэтому к ним обращаются через имя класса, а не экземпляра, и передают в них имя массива. Двоичный поиск можно применять только для упорядоченных массивов. В классе Class1 описан вспомогательный статический метод PrintArray, предназначенный для вывода массива на экран.

Результат работы программы:

Исходный массив: 
        24      50      18      3       16      -7      9       -1
2
Упорядоченный массив:
        -7      -1      3       9       16      18      24      50
5

Оператор foreach

Оператор foreach применяется для перебора элементов в специальным образом организованной группе данных. Массив является именно такой группой. Удобство этого вида цикла заключается в том, что нам не требуется определять количество элементов в группе и выполнять их перебор по индексу: мы просто указываем на необходимость перебрать все элементы группы. Синтаксис оператора:

foreach ( тип имя in выражение ) тело_цикла

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

Например, пусть задан массив:

int[] a =  { 24, 50, 18, 3, 16, -7, 9, -1 };

Вывод этого массива на экран с помощью оператора foreach выглядит следующим образом:

foreach ( int x in a ) Console.WriteLine( x );

Этот оператор выполняется так: на каждом проходе цикла очередной элемент массива присваивается переменной х и с ней производятся действия, записанные в теле цикла.

В листинге 6.4 решается та же задача, что и в листинге 6.1, но с использованием цикла foreach. Обратите внимание, насколько понятнее стала программа.

using System;
namespace ConsoleApplication1
{   class Class1
    {   static void Main()
        {
            int[] a = { 3, 12, 5, -9, 8, -4 };

            Console.WriteLine( "Исходный массив:" );
            foreach ( int elem in a )
                Console.Write( "\t" + elem );
            Console.WriteLine();

            long sum = 0;              // cумма отрицательных элементов
            int  num = 0;              // количество отрицательных элементов
            foreach ( int elem in a )
                if ( elem < 0 )
                {
                    sum += elem;
                    ++num;
                }

            Console.WriteLine( "sum = " + sum );
            Console.WriteLine( "num = " + num );

            int max = a[0];            // максимальный элемент
            foreach ( int elem in a )
                if ( elem > max ) max = elem;

            Console.WriteLine( "max = " + max );
        }
    }
}

Внимание

Ограничением оператора foreach является то, что с его помощью можно только просматривать значения в группе данных, но не изменять их.

Еще один пример использования оператора для работы со ступенчатым массивом приведен в листинге 6.5.

...
int[][] a = new int[3][];
          a[0] = new int [5] { 24, 50, 18, 3, 16 };
          a[1] = new int [3] { 7, 9, -1 };
          a[2] = new int [4] { 6, 15, 3, 1 };
          Console.WriteLine( "Исходный массив:" );
foreach ( int [] mas1 in a )
            {
                foreach ( int x in mas1 ) 
                       Console.Write( "\t" + x );
                Console.WriteLine();
            }
         // поиск числа 18 в нулевой строке:   
         Console.WriteLine( Array.IndexOf( a[0], 18 ) );
...

Массивы объектов

При создании массива, состоящего из элементов ссылочного типа, память выделяется только под ссылки на элементы, а сами элементы необходимо разместить в хипе явным образом. В качестве примера создадим массив из объектов некоторого класса Monster:

using System;
namespace ConsoleApplication1
{
    class Monster { ... }
    
    class Class1
    {   static void Main()
        {
            Random rnd = new Random();
            const int n = 5;
            Monster[] stado = new Monster[n];                   // 1
            for ( int i = 0; i < n; ++i )                       // 2
            {
                stado[i] = new Monster( rnd.Next( 1, 100 ), 
                                        rnd.Next( 1, 200 ), 
                                       "Crazy" + i.ToString() );
            }
            foreach ( Monster x in stado ) x.Passport();        // 3
        }
    }
}

Результат работы программы:

Monster Crazy0   health = 18 ammo = 94
Monster Crazy1   health = 85 ammo = 75
Monster Crazy2   health = 13 ammo = 6
Monster Crazy3   health = 51 ammo = 104
Monster Crazy4   health = 68 ammo = 114

Пример поиска в массиве объектов приведен в конце следующей лекции.

Символы и строки

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

Символы

Символьный тип char предназначен для хранения символов в кодировке Unicode. Символьный тип относится к встроенным типам данных C# и соответствует стандартному классу Char библиотеки .NET из пространства имен System. В этом классе определены статические методы, позволяющие задать вид и категорию символа, а также преобразовать символ в верхний или нижний регистр и в число. Некоторые методы приведены в таблилце 6.2, с остальными можно ознакомиться по учебнику [4].

Некоторые методы класса System.Char
Метод Описание
GetNumericValue Возвращает числовое значение символа, если он является цифрой, и –1 в противном случае
IsControl Возвращает true, если символ является управляющим
IsDigit Возвращает true, если символ является десятичной цифрой
IsLetter Возвращает true, если символ является буквой
IsLower Возвращает true, если символ задан в нижнем регистре
IsUpper Возвращает true, если символ записан в верхнем регистре
IsWhiteSpace Возвращает true, если символ является пробельным (пробел, перевод строки и возврат каретки)
Parse Преобразует строку в символ (строка должна состоять из одного символа)
ToLower Преобразует символ в нижний регистр
MaxValue, MinValue Возвращают символы с максимальным и минимальным кодами (эти символы не имеют видимого представления)

В листинге 6.6 продемонстрировано использование этих методов.

using System;
namespace ConsoleApplication1
{  class Class1
   {  static void Main()
     {
        try
        {
           char b = 'B', c = '\x63', d = '\u0032';                      // 1
           Console.WriteLine( "{0}  {1}  {2}", b, c, d );
           Console.WriteLine( "{0}  {1}  {2}",
                char.ToLower(b), char.ToUpper(c), char.GetNumericValue(d) );

           char a;
           do                                                           // 2
           {
               Console.Write( "Введите символ: " );
               a = char.Parse( Console.ReadLine() );
               Console.WriteLine( "Введен символ {0}, его код – {1}",
                                   a, (int)a );
               if (char.IsLetter(a))      Console.WriteLine("Буква");
               if (char.IsUpper(a))       Console.WriteLine("Верхний рег.");
               if (char.IsLower(a))       Console.WriteLine("Нижний рег.");
               if (char.IsControl(a))     Console.WriteLine("Управляющий");
               if (char.IsNumber(a))      Console.WriteLine("Число");
               if (char.IsPunctuation(a)) Console.WriteLine("Разделитель");
           } while (a != 'q');
       }
       catch
       {
           Console.WriteLine( "Возникло исключение" );
           return;
       }
    }
  }
}

Массивы символов

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

using System;
namespace ConsoleApplication1
{   class Class1
    {   static void Main()
        {
            char[] a = { 'm', 'a', 's', 's', 'i', 'v' };                // 1
            char[] b = "а роза упала на лапу азора".ToCharArray();      // 2
                
            PrintArray( "Исходный массив а:", a );

            int pos = Array.IndexOf( a, 'm' );
            a[pos] = 'M';
            PrintArray( "Измененный массив а:", a );

            PrintArray( "Исходный массив b:", b );
            Array.Reverse( b );
            PrintArray( "Измененный массив b:", b );
        }

        public static void PrintArray( string header, Array a )
        {
            Console.WriteLine( header );
            foreach ( object x in a ) Console.Write( x );
            Console.WriteLine( "\n" );
        }
    }
}

Результат работы программы:

Исходный массив а:
massiv

Измененный массив а:
Massiv

Исходный массив b:
а роза упала на лапу азора

Измененный массив b:
ароза упал ан алапу азор а

Строки типа string

Тип string, предназначенный для работы со строками символов в кодировке Unicode, является встроенным типом C#. Ему соответствует базовый класс System.String библиотеки .NET.

Создать строку можно несколькими способами:

string s;                       // инициализация отложена
string t = "qqq";               // инициализация строковым литералом
string u = new string(' ', 20); // конструктор создает строку из 20 пробелов
char[] a = { '0', '0', '0' };   // массив для инициализации строки
string v = new string( a );     // создание из массива символов

Для строк определены следующие операции:

  • присваивание ( = );
  • проверка на равенство ( == );
  • проверка на неравенство ( != );
  • обращение по индексу ( [] );
  • сцепление (конкатенация) строк ( + ).
  • Несмотря на то, что строки являются ссылочным типом данных, на равенство и неравенство проверяются не ссылки, а значения строк. Строки равны, если имеют одинаковое количество символов и совпадают посимвольно.

    Обращаться к отдельному элементу строки по индексу можно только для получения значения, но не для его изменения. Это связано с тем, что строки типа string относятся к так называемым неизменяемым типам данных. Методы, изменяющие содержимое строки, на самом деле создают новую копию строки. Неиспользуемые "старые" копии автоматически удаляются сборщиком мусора.

    В классе System.String предусмотрено множество методов, полей и свойств, позволяющих выполнять со строками практически любые действия. Некоторые элементы класса приведены в таблилце 6.3, с остальными можно ознакомиться по учебнику.

    Некоторые элементы класса System.String
    Название Вид Описание
    Compare Статический метод Сравнение двух строк в лексикографическом (алфавитном) порядке. Разные реализации метода позволяют сравнивать строки и подстроки с учетом и без учета регистра и особенностей национального представления дат и т. д.
    Concat Статический метод Конкатенация строк. Метод допускает сцепление произвольного числа строк
    Copy Статический метод Создание копии строки
    Format Статический метод Форматирование в соответствии с заданными спецификаторами формата (см. далее)
    IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny Методы Определение индексов первого и последнего вхождения заданной подстроки или любого символа из заданного набора
    Insert Метод Вставка подстроки в заданную позицию
    Join Статический метод Слияние массива строк в единую строку. Между элементами массива вставляются разделители (см. далее)
    Length Свойство Длина строки (количество символов)
    Split Метод Разделение строки на элементы, используя заданные разделители. Результаты помещаются в массив строк
    Substring Метод Выделение подстроки, начиная с заданной позиции
    ToCharArray Метод Преобразование строки в массив символов
    ToLower, ToUpper Методы Преобразование символов строки к нижнему или верхнему регистру

    Пример применения методов приведен в листинге 6.8.

    using System;
    namespace ConsoleApplication1
    {   class Class1
        {   static void Main()
            {
                string s = "прекрасная королева Изольда";
                Console.WriteLine( s );
                string sub = s.Substring( 3 ).Remove( 12, 2 );              // 1
                Console.WriteLine( sub );
    
                string[] mas = s.Split(' ');                                // 2
                string joined = string.Join( "! ", mas );
                Console.WriteLine( joined );
    
                Console.WriteLine( "Введите строку" );
                string x = Console.ReadLine();                              // 3
                Console.WriteLine( "Вы ввели строку " + x );
    
                double a = 12.234;
                int b = 29;
                Console.WriteLine( " a = {0,6:C}  b = {1,2:X}", a, b );     // 4
                Console.WriteLine( " a = {0,6:0.##}  a = {1,5:0.# ' руб. '}",
                                   a, b );                                  // 5
            }
        }
    }

    Результат работы программы:

    прекрасная королева Изольда
    красная корова Изольда
    прекрасная! королева! Изольда
    Введите строку
    не хочу!
    Вы ввели строку не хочу!
    a = 12,23p.  b = 1D
    a = 12,23 a=29 pуб.

    Форматирование строк

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

    В общем виде параметр задается следующим образом:

    {n [,m[:спецификатор_формата]]}

    Здесь n — номер параметра. Параметры нумеруются с нуля, нулевой параметр заменяется значением первой переменной из списка вывода, первый параметр — второй переменной, и т. д. Параметр m определяет минимальную ширину поля, которое отводится под выводимое значение. Если выводимому числу достаточно меньшего количества позиций, неиспользуемые позиции заполняются пробелами. Если числу требуется больше позиций, параметр игнорируется.

    Спецификатор формата, как явствует из его названия, определяет формат вывода значения. Например, спецификатор C (Currency) означает, что параметр должен форматироваться как валюта с учетом национальных особенностей представления, а спецификатор Х (Hexadecimal) задает шестнадцатеричную форму представления выводимого значения.

    В операторе 5 используются так называемые пользовательские шаблоны форматирования. Если приглядеться, в них нет ничего сложного: после двоеточия задается вид выводимого значения посимвольно, причем на месте каждого символа может стоять либо #, либо 0. Если указан знак #, на этом месте будет выведена цифра числа, если она не равна нулю. Если указан 0, будет выведена любая цифра, в том числе и 0.

    Строки типа StringBuilder

    Возможности, предоставляемые классом string, широки, однако требование неизменности его объектов может оказаться неудобным. В этом случае для работы со строками применяется класс StringBuilder, определенный в пространстве имен System.Text и позволяющий изменять значение своих экземпляров. О нем можно прочитать в учебнике [4].

    Вопросы и задания для самостоятельной работы студента

  • Перечислите способы описания массивов.
  • Чем отличается хранение в памяти массивов из величин значимого и ссылочного типов?
  • Является ли размерность частью описания массива?
  • Может ли размерность массива описана переменной (а не константой)?
  • Можно ли изменить размерность массива после выделения памяти под него?
  • Какие виды массивов используются в С#?
  • Что происходит, если количество инициализаторов массива не соответствует заявленной размерности?
  • Что происходит при присваивании массивов?
  • Опишите два-три метода сортировки массивов.
  • Опишите основные методы и свойства класса System.Array
  • Какие ограничения имеет оператор foreach по сравнению с оператором for?
  • Что такое кодировка Unicode?
  • Какие средства работы с отдельными символами предоставляет C#?
  • Опишите основные методы и свойства класса string.
  • Можно ли изменить длину строки после того, как память под нее была выделена?
  • Какое основное ограничение имеет класс string?
  • Какие существуют возможности форматирования строк?
  • Перечислите спецификации формата.
  • Опишите пользовательский формат вещественного числа с двумя ведущими нулями и тремя знаками после запятой.
  • Изучите по справочной системе свойства и методы стандартного класса System.Array.
  • Изучите по справочной системе свойства и методы стандартного класса System.String.
  • Изучите по справочной системе свойства и методы стандартного класса System.Char.
  • Изучите по справочной системе свойства и методы стандартного класса System.Text.StringBuilder.
  • Изучите разделы стандарта C#, касающиеся массивов.
  • Изучите разделы стандарта C#, касающиеся символов.
  • Изучите разделы стандарта C#, касающиеся строк.
  • Лабораторные работы

    Лабораторная работа 5. Одномерные массивы

    В одномерном массиве, состоящем из n вещественных элементов, вычислить:

  • сумму отрицательных элементов массива;
  • произведение элементов массива, расположенных между максимальным и минимальным элементами.
  • Упорядочить элементы массива по возрастанию.

    Лабораторная работа 6. Двумерные массивы

    Дана целочисленная прямоугольная матрица. Определить:

  • количество строк, не содержащих ни одного нулевого элемента;
  • максимальное из чисел, встречающихся в заданной матрице более одного раза.
  • Лабораторная работа 7. Строки

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

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

    Задание выполнить двумя способами: без использования элементов стандартных классов System.Array, System.Char и System.String и с их использованием.

    Задание: упорядочить предложения по возрастанию количества содержащихся в них слов.

    Страницы:

    Массивы

    Презентацию к данной лекции Вы можете скачать здесь.

    Массив — это ограниченная совокупность однотипных величин. Элементы массива имеют одно и то же имя, а различаются по порядковому номеру ( индексу ).

    Массив в С# относится к ссылочным типам данных, то есть располагается в динамической области памяти, поэтому создание массива начинается с выделения памяти под его элементы. Элементами массива могут быть величины как значимых, так и ссылочных типов (в том числе массивы). Массив значимых типов хранит значения, массив ссылочных типов — ссылки на элементы. Всем элементам при создании массива присваиваются значения по умолчанию: нули для значимых типов и null для ссылочных.

    На рис 6.1 представлен массив, состоящий из пяти элементов любого значимого типа, например, int или double, а рисунок 6.2 иллюстрирует организацию массива из элементов ссылочного типа.

    (рис 6.2) Простые переменные и массив из элементов значимого типа(рис 6.1) Массив из элементов ссылочного типа

    Вот, например, как выглядят операторы создания массива из 10 целых чисел и массива из 100 строк:

    int[]    w = new int[10];
    string[] z = new string[100];

    В первом операторе описан массив w типа int[]. Операция new выделяет память под 10 целых элементов, и они заполняются нулями.

    Во втором операторе описан массив z типа string[].Операция new выделяет память под 100 ссылок на строки, и эти ссылки заполняются значением null. Память под сами строки, составляющие массив, не выделяется — это будет необходимо сделать перед заполнением массива.

    Количество элементов в массиве ( размерность ) не является частью его типа, оно задается при выделении памяти и не может быть изменено впоследствии. Размерность может задаваться не только константой, но и выражением. Результат вычисления этого выражения должен быть неотрицательным, а его тип должен иметь неявное преобразование к int, uint, long или ulong.

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

    w[4]        z[i]

    С элементом массива можно делать все, что допустимо для переменных того же типа. Если при работе с массивом значение индекса выходит за границы массива, генерируется исключение IndexOutOfRangeException.

    Массивы одного типа можно присваивать друг другу. При этом происходит присваивание ссылок, а не элементов, как и для любого другого объекта ссылочного типа, например:

    int[] a = new int[10];
    int[] b = a;             // b и a указывают на один и тот же массив

    Все массивы в C# имеют общий базовый класс Array, определенный в пространстве имен System. В нем есть несколько полезных методов, упрощающих работу с массивами, например, методы получения размерности, сортировки и поиска. Мы рассмотрим эти методы немного позже в разделе "Класс System.Array".

    В C# существуют три разновидности массивов: одномерные, прямоугольные и ступенчатые (невыровненные). О последних, менее распространенных, можно прочитать в учебнике (Павловская Т. А. С#. Программирование на языке высокого уровня. — СПб.: Питер, 2010), а сейчас займемся одномерными массивами.

    Одномерные массивы

    Одномерные массивы используются в программах чаще всего. Варианты описания массива:

    тип[] имя;
    тип[] имя = new тип [ размерность ];
    тип[] имя = { список_инициализаторов };
    тип[] имя = new тип [] { список_инициализаторов };
    тип[] имя = new тип [ размерность ] { список_инициализаторов };

    Примеры описаний (один пример на каждый вариант описания):

    int[] a;                                    // 1    элементов нет
    int[] b = new int[4];                       // 2    элементы равны 0
    int[] c = { 61, 2, 5, -9 };                 // 3    new подразумевается
    int[] d = new int[] { 61, 2, 5, -9 };       // 4    размерность вычисляется
    int[] e = new int[4] { 61, 2, 5, -9 };      // 5    избыточное описание

    Здесь описано пять массивов. Отличие первого оператора от остальных состоит в том, что в нем фактически описана только ссылка на массив, а память под элементы массива не выделена.

    В каждом из остальных массивов по четыре элемента целого типа. Как видно из операторов 3–5, массив при описании можно инициализировать. Если при этом не задана размерность (оператор 3), количество элементов вычисляется по количеству инициализирующих значений. Для полей объектов и локальных переменных можно опускать операцию new, она будет выполнена по умолчанию (оператор 2). Если присутствует и размерность, и список инициализаторов, размерность должна быть константой (оператор 4).

    В качестве примера рассмотрим программу, которая определяет сумму и количество отрицательных элементов, а также максимальный элемент массива, состоящего из 6 целочисленных элементов (листинг 6.1).

    using System;
    namespace ConsoleApplication1
    {    class Class1
        {
            static void Main()
            {
                const int n = 6;
                int[] a = new int[n] { 3, 12, 5, -9, 8, -4 };
    
                Console.WriteLine( "Исходный массив:" );
                for ( int i = 0; i < n; ++i )
                    Console.Write( "\t" + a[i] );
                Console.WriteLine();
    
                long sum = 0;              // cумма отрицательных элементов
                int  num = 0;              // количество отрицательных элементов
                for ( int i = 0; i < n; ++i )
                    if ( a[i] < 0 )
                    {
                        sum += a[i];
                        ++num;
                    }
    
                Console.WriteLine( "Сумма  отрицательных = " + sum );
                Console.WriteLine( "Кол-во отрицательных = " + num );
    
                int max = a[0];             // максимальный элемент
                for ( int i = 1; i < n; ++i )
                    if ( a[i] > max ) max = a[i];
    
                Console.WriteLine( "Максимальный элемент = " + max );
            }
        }
    }

    Обратите внимание, что для вывода массива требуется организовать цикл.

    Прямоугольные массивы

    Прямоугольный массив имеет более одного измерения. Чаще всего в программах используются двумерные массивы. Варианты описания двумерного массива:

    тип[,] имя;
    тип[,] имя = new тип [ разм_1, разм_2 ];
    тип[,] имя = { список_инициализаторов };
    тип[,] имя = new тип [,] { список_инициализаторов };
    тип[,] имя = new тип [ разм_1, разм_2 ] { список_инициализаторов };

    Примеры описаний (один пример на каждый вариант описания):

    int[,] a;                                      // 1  элементов нет
    int[,] b = new int[2, 3];                      // 2  элементы равны 0
    int[,] c = {{1, 2, 3}, {4, 5, 6}};             // 3  new подразумевается
    int[,] c = new int[,] {{1, 2, 3}, {4, 5, 6}};  // 4  размерность вычисляется
    int[,] d = new int[2,3] {{1, 2, 3}, {4, 5, 6}};// 5  избыточное описание

    К элементу двумерного массива обращаются, указывая номера строки и столбца, на пересечении которых он расположен, например:

    a[1, 4]        b[i, j]        b[j, i]

    Внимание

    Необходимо помнить, что компилятор воспринимает как номер строки первый индекс, как бы он ни был обозначен в программе.

    В качестве примера рассмотрим программу, которая для целочисленной матрицы размером 3 x 4 определяет среднее арифметическое ее элементов и количество положительных элементов в каждой строке.

    Для нахождения среднего арифметического элементов массива требуется найти их общую сумму, после чего разделить ее на количество элементов. Порядок перебора элементов массива (по строкам или по столбцам) роли не играет. Нахождение количества положительных элементов каждой строки требует просмотра матрицы по строкам. Схема алгоритма приведена на рис 6.3, программа — в листинге 6.2.

    using System;
    namespace ConsoleApplication1
    {    class Class1
        {
            static void Main()
            {
                const int m = 3, n = 4;
                int[,] a = new int[m, n] {
                    { 2,-2, 8, 9 }, 
                    {-4,-5, 6,-2 },
                    { 7, 0, 1, 1 } 
                 };
    
                Console.WriteLine( "Исходный массив:" );
                for ( int i = 0; i < m; ++i )
                {
                    for ( int j = 0; j < n; ++j )
                        Console.Write( "\t" + a[i, j] );
                    Console.WriteLine();
                }
    
                double sum = 0;
                int nPosEl;
                for ( int i = 0; i < m; ++i )
                {
                    nPosEl = 0;
                    for ( int j = 0; j < n; ++j )
                    {
                        sum += a[i, j];
                        if ( a[i, j] > 0 ) ++nPosEl;
                    }
                    Console.WriteLine( "В строке {0} {1} положит-х элементов", 
                        i, nPosEl  );
                }
                Console.WriteLine( "Среднее арифметическое всех элементов: " 
                    + sum / m / n );
            }
        }
    }

    Ступенчатые массивы

    В ступенчатых массивах количество элементов в разных строках может различаться. В памяти ступенчатый массив хранится иначе, чем прямоугольный: в виде нескольких внутренних массивов, каждый из которых имеет свой размер. Кроме того, выделяется отдельная область памяти для хранения ссылок на каждый из внутренних массивов (рис 6.3).

    (рис 6.3) Ступенчатый массив

    Фрагмент программы, иллюстрирующий работу со ступенчатым массивом, приведен в листинге 6.5 (после рассмотрения оператора foreach ).

    Класс System.Array

    Все массивы в C# построены на основе базового класса Array, который содержит полезные для программиста свойства и методы, часть из которых перечислена в таблилце 6.1.

    Некоторые элементы класса Array
    Элемент Вид Описание
    Length Свойство Количество элементов массива (по всем размерностям)
    BinarySearch Статический метод Двоичный поиск в отсортированном массиве
    Clear Статический метод Присваивание элементам массива значений по умолчанию
    Copy Статический метод Копирование заданного диапазона элементов одного массива в другой массив
    GetValue Метод Получение значения элемента массива
    IndexOf Статический метод Поиск первого вхождения элемента в одномерный массив
    Reverse Статический метод Изменение порядка следования элементов на обратный
    Sort Статический метод Упорядочивание элементов одномерного массива

    В листинге 6.3 продемонстрировано применение элементов класса Array при работе с одномерным массивом.

    using System;
    namespace ConsoleApplication1
    {    class Class1
        {   static void Main()
            {
                int[] a =  { 24, 50, 18, 3, 16, -7, 9, -1 };
    
                PrintArray( "Исходный массив:", a );
                Console.WriteLine( Array.IndexOf( a, 18 ) ); 
    
                Array.Sort(a);
                PrintArray( "Упорядоченный массив:", a );
                Console.WriteLine( Array.BinarySearch( a, 18) );
            }
    
            public static void PrintArray( string header, int[] a )
            {
                Console.WriteLine( header );
                for ( int i = 0; i < a.Length; ++i )
                    Console.Write( "\t" + a[i] );
                Console.WriteLine();
            }
        }
    }

    Методы Sort, IndexOf и BinarySearch являются статическими, поэтому к ним обращаются через имя класса, а не экземпляра, и передают в них имя массива. Двоичный поиск можно применять только для упорядоченных массивов. В классе Class1 описан вспомогательный статический метод PrintArray, предназначенный для вывода массива на экран.

    Результат работы программы:

    Исходный массив: 
            24      50      18      3       16      -7      9       -1
    2
    Упорядоченный массив:
            -7      -1      3       9       16      18      24      50
    5

    Оператор foreach

    Оператор foreach применяется для перебора элементов в специальным образом организованной группе данных. Массив является именно такой группой. Удобство этого вида цикла заключается в том, что нам не требуется определять количество элементов в группе и выполнять их перебор по индексу: мы просто указываем на необходимость перебрать все элементы группы. Синтаксис оператора:

    foreach ( тип имя in выражение ) тело_цикла

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

    Например, пусть задан массив:

    int[] a =  { 24, 50, 18, 3, 16, -7, 9, -1 };

    Вывод этого массива на экран с помощью оператора foreach выглядит следующим образом:

    foreach ( int x in a ) Console.WriteLine( x );

    Этот оператор выполняется так: на каждом проходе цикла очередной элемент массива присваивается переменной х и с ней производятся действия, записанные в теле цикла.

    В листинге 6.4 решается та же задача, что и в листинге 6.1, но с использованием цикла foreach. Обратите внимание, насколько понятнее стала программа.

    using System;
    namespace ConsoleApplication1
    {   class Class1
        {   static void Main()
            {
                int[] a = { 3, 12, 5, -9, 8, -4 };
    
                Console.WriteLine( "Исходный массив:" );
                foreach ( int elem in a )
                    Console.Write( "\t" + elem );
                Console.WriteLine();
    
                long sum = 0;              // cумма отрицательных элементов
                int  num = 0;              // количество отрицательных элементов
                foreach ( int elem in a )
                    if ( elem < 0 )
                    {
                        sum += elem;
                        ++num;
                    }
    
                Console.WriteLine( "sum = " + sum );
                Console.WriteLine( "num = " + num );
    
                int max = a[0];            // максимальный элемент
                foreach ( int elem in a )
                    if ( elem > max ) max = elem;
    
                Console.WriteLine( "max = " + max );
            }
        }
    }

    Внимание

    Ограничением оператора foreach является то, что с его помощью можно только просматривать значения в группе данных, но не изменять их.

    Еще один пример использования оператора для работы со ступенчатым массивом приведен в листинге 6.5.

    ...
    int[][] a = new int[3][];
              a[0] = new int [5] { 24, 50, 18, 3, 16 };
              a[1] = new int [3] { 7, 9, -1 };
              a[2] = new int [4] { 6, 15, 3, 1 };
              Console.WriteLine( "Исходный массив:" );
    foreach ( int [] mas1 in a )
                {
                    foreach ( int x in mas1 ) 
                           Console.Write( "\t" + x );
                    Console.WriteLine();
                }
             // поиск числа 18 в нулевой строке:   
             Console.WriteLine( Array.IndexOf( a[0], 18 ) );
    ...

    Массивы объектов

    При создании массива, состоящего из элементов ссылочного типа, память выделяется только под ссылки на элементы, а сами элементы необходимо разместить в хипе явным образом. В качестве примера создадим массив из объектов некоторого класса Monster:

    using System;
    namespace ConsoleApplication1
    {
        class Monster { ... }
        
        class Class1
        {   static void Main()
            {
                Random rnd = new Random();
                const int n = 5;
                Monster[] stado = new Monster[n];                   // 1
                for ( int i = 0; i < n; ++i )                       // 2
                {
                    stado[i] = new Monster( rnd.Next( 1, 100 ), 
                                            rnd.Next( 1, 200 ), 
                                           "Crazy" + i.ToString() );
                }
                foreach ( Monster x in stado ) x.Passport();        // 3
            }
        }
    }

    Результат работы программы:

    Monster Crazy0   health = 18 ammo = 94
    Monster Crazy1   health = 85 ammo = 75
    Monster Crazy2   health = 13 ammo = 6
    Monster Crazy3   health = 51 ammo = 104
    Monster Crazy4   health = 68 ammo = 114

    Пример поиска в массиве объектов приведен в конце следующей лекции.

    Символы и строки

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

    Символы

    Символьный тип char предназначен для хранения символов в кодировке Unicode. Символьный тип относится к встроенным типам данных C# и соответствует стандартному классу Char библиотеки .NET из пространства имен System. В этом классе определены статические методы, позволяющие задать вид и категорию символа, а также преобразовать символ в верхний или нижний регистр и в число. Некоторые методы приведены в таблилце 6.2, с остальными можно ознакомиться по учебнику [4].

    Некоторые методы класса System.Char
    Метод Описание
    GetNumericValue Возвращает числовое значение символа, если он является цифрой, и –1 в противном случае
    IsControl Возвращает true, если символ является управляющим
    IsDigit Возвращает true, если символ является десятичной цифрой
    IsLetter Возвращает true, если символ является буквой
    IsLower Возвращает true, если символ задан в нижнем регистре
    IsUpper Возвращает true, если символ записан в верхнем регистре
    IsWhiteSpace Возвращает true, если символ является пробельным (пробел, перевод строки и возврат каретки)
    Parse Преобразует строку в символ (строка должна состоять из одного символа)
    ToLower Преобразует символ в нижний регистр
    MaxValue, MinValue Возвращают символы с максимальным и минимальным кодами (эти символы не имеют видимого представления)

    В листинге 6.6 продемонстрировано использование этих методов.

    using System;
    namespace ConsoleApplication1
    {  class Class1
       {  static void Main()
         {
            try
            {
               char b = 'B', c = '\x63', d = '\u0032';                      // 1
               Console.WriteLine( "{0}  {1}  {2}", b, c, d );
               Console.WriteLine( "{0}  {1}  {2}",
                    char.ToLower(b), char.ToUpper(c), char.GetNumericValue(d) );
    
               char a;
               do                                                           // 2
               {
                   Console.Write( "Введите символ: " );
                   a = char.Parse( Console.ReadLine() );
                   Console.WriteLine( "Введен символ {0}, его код – {1}",
                                       a, (int)a );
                   if (char.IsLetter(a))      Console.WriteLine("Буква");
                   if (char.IsUpper(a))       Console.WriteLine("Верхний рег.");
                   if (char.IsLower(a))       Console.WriteLine("Нижний рег.");
                   if (char.IsControl(a))     Console.WriteLine("Управляющий");
                   if (char.IsNumber(a))      Console.WriteLine("Число");
                   if (char.IsPunctuation(a)) Console.WriteLine("Разделитель");
               } while (a != 'q');
           }
           catch
           {
               Console.WriteLine( "Возникло исключение" );
               return;
           }
        }
      }
    }

    Массивы символов

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

    using System;
    namespace ConsoleApplication1
    {   class Class1
        {   static void Main()
            {
                char[] a = { 'm', 'a', 's', 's', 'i', 'v' };                // 1
                char[] b = "а роза упала на лапу азора".ToCharArray();      // 2
                    
                PrintArray( "Исходный массив а:", a );
    
                int pos = Array.IndexOf( a, 'm' );
                a[pos] = 'M';
                PrintArray( "Измененный массив а:", a );
    
                PrintArray( "Исходный массив b:", b );
                Array.Reverse( b );
                PrintArray( "Измененный массив b:", b );
            }
    
            public static void PrintArray( string header, Array a )
            {
                Console.WriteLine( header );
                foreach ( object x in a ) Console.Write( x );
                Console.WriteLine( "\n" );
            }
        }
    }

    Результат работы программы:

    Исходный массив а:
    massiv
    
    Измененный массив а:
    Massiv
    
    Исходный массив b:
    а роза упала на лапу азора
    
    Измененный массив b:
    ароза упал ан алапу азор а

    Строки типа string

    Тип string, предназначенный для работы со строками символов в кодировке Unicode, является встроенным типом C#. Ему соответствует базовый класс System.String библиотеки .NET.

    Создать строку можно несколькими способами:

    string s;                       // инициализация отложена
    string t = "qqq";               // инициализация строковым литералом
    string u = new string(' ', 20); // конструктор создает строку из 20 пробелов
    char[] a = { '0', '0', '0' };   // массив для инициализации строки
    string v = new string( a );     // создание из массива символов

    Для строк определены следующие операции:

  • присваивание ( = );
  • проверка на равенство ( == );
  • проверка на неравенство ( != );
  • обращение по индексу ( [] );
  • сцепление (конкатенация) строк ( + ).
  • Несмотря на то, что строки являются ссылочным типом данных, на равенство и неравенство проверяются не ссылки, а значения строк. Строки равны, если имеют одинаковое количество символов и совпадают посимвольно.

    Обращаться к отдельному элементу строки по индексу можно только для получения значения, но не для его изменения. Это связано с тем, что строки типа string относятся к так называемым неизменяемым типам данных. Методы, изменяющие содержимое строки, на самом деле создают новую копию строки. Неиспользуемые "старые" копии автоматически удаляются сборщиком мусора.

    В классе System.String предусмотрено множество методов, полей и свойств, позволяющих выполнять со строками практически любые действия. Некоторые элементы класса приведены в таблилце 6.3, с остальными можно ознакомиться по учебнику.

    Некоторые элементы класса System.String
    Название Вид Описание
    Compare Статический метод Сравнение двух строк в лексикографическом (алфавитном) порядке. Разные реализации метода позволяют сравнивать строки и подстроки с учетом и без учета регистра и особенностей национального представления дат и т. д.
    Concat Статический метод Конкатенация строк. Метод допускает сцепление произвольного числа строк
    Copy Статический метод Создание копии строки
    Format Статический метод Форматирование в соответствии с заданными спецификаторами формата (см. далее)
    IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny Методы Определение индексов первого и последнего вхождения заданной подстроки или любого символа из заданного набора
    Insert Метод Вставка подстроки в заданную позицию
    Join Статический метод Слияние массива строк в единую строку. Между элементами массива вставляются разделители (см. далее)
    Length Свойство Длина строки (количество символов)
    Split Метод Разделение строки на элементы, используя заданные разделители. Результаты помещаются в массив строк
    Substring Метод Выделение подстроки, начиная с заданной позиции
    ToCharArray Метод Преобразование строки в массив символов
    ToLower, ToUpper Методы Преобразование символов строки к нижнему или верхнему регистру

    Пример применения методов приведен в листинге 6.8.

    using System;
    namespace ConsoleApplication1
    {   class Class1
        {   static void Main()
            {
                string s = "прекрасная королева Изольда";
                Console.WriteLine( s );
                string sub = s.Substring( 3 ).Remove( 12, 2 );              // 1
                Console.WriteLine( sub );
    
                string[] mas = s.Split(' ');                                // 2
                string joined = string.Join( "! ", mas );
                Console.WriteLine( joined );
    
                Console.WriteLine( "Введите строку" );
                string x = Console.ReadLine();                              // 3
                Console.WriteLine( "Вы ввели строку " + x );
    
                double a = 12.234;
                int b = 29;
                Console.WriteLine( " a = {0,6:C}  b = {1,2:X}", a, b );     // 4
                Console.WriteLine( " a = {0,6:0.##}  a = {1,5:0.# ' руб. '}",
                                   a, b );                                  // 5
            }
        }
    }

    Результат работы программы:

    прекрасная королева Изольда
    красная корова Изольда
    прекрасная! королева! Изольда
    Введите строку
    не хочу!
    Вы ввели строку не хочу!
    a = 12,23p.  b = 1D
    a = 12,23 a=29 pуб.

    Форматирование строк

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

    В общем виде параметр задается следующим образом:

    {n [,m[:спецификатор_формата]]}

    Здесь n — номер параметра. Параметры нумеруются с нуля, нулевой параметр заменяется значением первой переменной из списка вывода, первый параметр — второй переменной, и т. д. Параметр m определяет минимальную ширину поля, которое отводится под выводимое значение. Если выводимому числу достаточно меньшего количества позиций, неиспользуемые позиции заполняются пробелами. Если числу требуется больше позиций, параметр игнорируется.

    Спецификатор формата, как явствует из его названия, определяет формат вывода значения. Например, спецификатор C (Currency) означает, что параметр должен форматироваться как валюта с учетом национальных особенностей представления, а спецификатор Х (Hexadecimal) задает шестнадцатеричную форму представления выводимого значения.

    В операторе 5 используются так называемые пользовательские шаблоны форматирования. Если приглядеться, в них нет ничего сложного: после двоеточия задается вид выводимого значения посимвольно, причем на месте каждого символа может стоять либо #, либо 0. Если указан знак #, на этом месте будет выведена цифра числа, если она не равна нулю. Если указан 0, будет выведена любая цифра, в том числе и 0.

    Строки типа StringBuilder

    Возможности, предоставляемые классом string, широки, однако требование неизменности его объектов может оказаться неудобным. В этом случае для работы со строками применяется класс StringBuilder, определенный в пространстве имен System.Text и позволяющий изменять значение своих экземпляров. О нем можно прочитать в учебнике [4].

    Вопросы и задания для самостоятельной работы студента

  • Перечислите способы описания массивов.
  • Чем отличается хранение в памяти массивов из величин значимого и ссылочного типов?
  • Является ли размерность частью описания массива?
  • Может ли размерность массива описана переменной (а не константой)?
  • Можно ли изменить размерность массива после выделения памяти под него?
  • Какие виды массивов используются в С#?
  • Что происходит, если количество инициализаторов массива не соответствует заявленной размерности?
  • Что происходит при присваивании массивов?
  • Опишите два-три метода сортировки массивов.
  • Опишите основные методы и свойства класса System.Array
  • Какие ограничения имеет оператор foreach по сравнению с оператором for?
  • Что такое кодировка Unicode?
  • Какие средства работы с отдельными символами предоставляет C#?
  • Опишите основные методы и свойства класса string.
  • Можно ли изменить длину строки после того, как память под нее была выделена?
  • Какое основное ограничение имеет класс string?
  • Какие существуют возможности форматирования строк?
  • Перечислите спецификации формата.
  • Опишите пользовательский формат вещественного числа с двумя ведущими нулями и тремя знаками после запятой.
  • Изучите по справочной системе свойства и методы стандартного класса System.Array.
  • Изучите по справочной системе свойства и методы стандартного класса System.String.
  • Изучите по справочной системе свойства и методы стандартного класса System.Char.
  • Изучите по справочной системе свойства и методы стандартного класса System.Text.StringBuilder.
  • Изучите разделы стандарта C#, касающиеся массивов.
  • Изучите разделы стандарта C#, касающиеся символов.
  • Изучите разделы стандарта C#, касающиеся строк.
  • Лабораторные работы

    Лабораторная работа 5. Одномерные массивы

    В одномерном массиве, состоящем из n вещественных элементов, вычислить:

  • сумму отрицательных элементов массива;
  • произведение элементов массива, расположенных между максимальным и минимальным элементами.
  • Упорядочить элементы массива по возрастанию.

    Лабораторная работа 6. Двумерные массивы

    Дана целочисленная прямоугольная матрица. Определить:

  • количество строк, не содержащих ни одного нулевого элемента;
  • максимальное из чисел, встречающихся в заданной матрице более одного раза.
  • Лабораторная работа 7. Строки

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

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

    Задание выполнить двумя способами: без использования элементов стандартных классов System.Array, System.Char и System.String и с их использованием.

    Задание: упорядочить предложения по возрастанию количества содержащихся в них слов.

    Вернуться к учебному плану