Массивы переменных как однородные статические структуры данных. Строки символов. Инициализация переменных и мас­сивов

Вид материалаЛекция
Подобный материал:




ЛЕКЦИЯ 3

Массивы переменных как однородные статические структуры данных. Строки символов. Инициализация переменных и мас­сивов. Управляющие конструкции языка Си: синтаксис и се­мантика.

$ 1. МАССИВЫ ПЕРЕМЕННЫХ КАК ОДНОРОДНЫЕ СТАТИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ.

Мы рассмотрели простые переменные, являющиеся носителями од­ного единственного значения, будь то число или внутреннее машинное представление некоторого символа ASCII. Однако при решении большинст­ва практических задач на ЭВМ приходится иметь дело с наборами данных, представимых в виде векторов, таблиц, строк или абстрактных множеств с неупорядоченной структурой.

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

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

[класс памяти] тип имя[константное арифметическое выражение];

Например:

int mas[10];

char z[20];

определяют два массива: массив mas, состоящий из 10 элементов типа int, и массив символов z, длина которого равна 20.

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

c = 2*mas[5] + 7;

Отметим, что компилятор Си нумерует элементы массивов начиная с нуля (а не с единицы, как это принято во многих языках программирова­ния). Поэтому в приведенном примере одним из операндов арифметическо­го выражения является шестой а не пятый элемент массива mas. Соот­ветственно, последний элемент этого массива будет иметь индекс 9. В общем случае порядковые номера элементов могут задаваться произволь­ными арифметическими выражениями целого типа, которые будем называть индексными выражениями.

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

$ 2. СТРОКИ СИМВОЛОВ

Мы уже познакомились с понятием символьной строки как последова­тельности, состоящей из одного или более символов ASCII. Рассмотрим вопрос размещения строк в памяти ЭВМ и их использование в программе. Дело в том, что в языке Си нет специального типа, который можно было бы использовать для описания строк. Вместо этого они представляются в виде массивов элементов типа char. Такое решение проблемы означает, что символы строки располагаются в соседних ячейках памяти - по одно­му символу в байте.

В то же время, столь упрощенное представление о строках несколько затрудняет практическую работу с ними, поскольку в большинстве случаев строки интересуют нас как целостные в логическом отношении единицы информации, а не как наборы символов, из которых они состоят. Частич­ный выход из создавшейся ситуации достигается путем помещения ноль-символа (Esc-последовательность \0) в конец всякой строки. Это означает, что под строкой следует понимать последовательность симво­лов, начинающуюся в нулевом элементе массива типа char и заканчиваю­щуюся символом \0. При этом нужно помнить, что описывая массив симво­лов для хранения строки необходимо резервировать одну дополнительную ячейку памяти под нуль-символ. Так, например, для представления стро­ки, содержащей 40 символов, в программе необходимо иметь описание ви­да:

char string[41];

Тем не менее, ввиду того, что в языке Си нет средств для работы с массивами как с единым целым, то и не существует возможности манипу­лировать строками как неделимыми единицами информации. Это затрудне­ние снимается за счет использования функций стандартной библиотеки языка ( ). Примеры некоторых функций:

strlen(s) - определение длины строки s до ноль-символа

strcmp(s1,s2) - сравнение строк

strncmp(s1,s2,n) - сравнение строк длиной n

strcpy(s1,s2) - копирование строки s2 в s1

strncpy(s1,s2,n) - копирование n символов из строки s2 в s1

strcat(s1,s2) - добавление строки s2 k s1 (s1=s1+s2)

strncat(s1,s2,n) - добавление к строке s1 n символов из s2

strchr(s,c) - поиск первого появления символа с в строке s

strcspn(s1,s2) - поиск первого появления символа из s2 в s1

strnset(s,c,n) - инициализация строки n символами с

strrev(s) - разворот строки

strrchr(s,c) - поиск последнего появления символа с в s

strlwr(s) - преобразование строки в нижний регистр

strupr(s) - преобразование строки в верхний регистр

Для ввода/вывода строк на стандартные устройства могут использо­ваться функции gets(s) и puts(s) или scanf и printf с форматным кодом %s.

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

$ 3 ИНИЦИАЛИЗАЦИЯ ПЕРЕМЕННЫХ И МАССИВОВ

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

для простых переменных инициализатор имеет следующий формат:

<тип> имя переменной = произвольное константное выражение;


Например:

char sym = 0x73, slash = '/';

int n = 10, k = 2;

float x = 2.5, y = 0.12e3;

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

int mas[5] = 0, 1, 2, 3, 4 ;

char string[5] = 'm','a','r','t','\0';

float val[10] = 1.2, 1.7, 4.1;

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

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

int mas[] = { 1, 2, 3} ;

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

char string[] = "mart";

что эквивалентно предыдущему примеру.

С другой стороны, описание

char rob[80] = "строка";

объявляет массив, состоящий из 80 элементов типа char, но лишь 6 из них отличны от нуль-символа.

$ 4. УПРАВЛЯЮЩИЕ КОНСТРУКЦИИ ЯЗЫКА СИ.

К ним относятся : условный оператор, переключатель, несколько раз­новидностей оператора цикла и операторы передачи управления.

4.1. Условный оператор if-else

Является простейшим и эффективным средством, позволяющим програм­мировать разветвляющиеся алгоритмы. Его формальный синтаксис задается следующей формулой:

if(выражение) оператор1;

[else оператор2;]

причем else-часть не является обязательной и может быть опущена. В скобках после if -произвольное выражение, приводимое к логическому значению. Если результатом вычисления выражения является логическое значение "истина"(отличное от нуля), то выполняются действия, отвеча­ющие оператору1. В противном случае осуществляется переход к операто­ру2 в else-части условного оператора, а при отсутствии ее - к опера­тору, непосредственно следующему за оператором if. Пример:

if(i>0) y=x/i;

else

x=i/2; y=x+5;

Если один оператор if вложен в другой, то else-часть связывается с ближайшим предыдущим оператором if. Чтобы изменить это соглашение, необходимо использовать фигурные скобки.

if(n > 0) if(n > 0)

if(a > b) { if(a > b)

z = a; z = a; }

else else

z = b; z = b;

4.2. Оператор-переключатель switch

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

switch(выражение)

{ [case константное выражение: [операторы ][break;]]

. . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . .

[case константное выражение: [операторы ][break;]]

[default: [операторы][break;]]

}

где любая case- или default-часть может отсутствовать, а также мо­гут быть опущены операторы в любой из этих частей. В скобках после switch -произвольное выражение целого тапа. Константное выражение в case обрабатывается в период компиляции программы. Никакие два конс­тантных выражения в одном операторе-переключателе не могут иметь оди­наковых значений.

Семантика. Предварительно вычисленное выражение в круглых скобках сравнивается с константой во всех вариантах case и управление переда­ется той группе операторов, которая соответствует найденному значе­нию. Если значение ни одного из константных выражений не совпало со значением (выражения), то выполняются операторы, связанные с меткой default, а при ее отсутствии - оператор, непосредственно следующий за оператором switch.

В следующем примере значение переменной ор, имеющей тип char, оп­ределяет ту арифметическую операцию, которая должна быть выполнена над переменными х и у:

switch( op )


{case '+': z = x + y;

break;

case '-': z = x - y;

break;

case '*': z = x * y;

break;

case '/': z = x / y;

}

Ключевое слово case вместе с константой служат просто меткой соот­ветствующих операторов, и если будут выполняться операторы для неко­торого варианта case, то далее будут выполняться операторы всех пос­ледующих вариантов до тех пор, пока не встретится оператор break. Поэтому, если нескольким различным значениям (выражения) должны соот­ветствовать одни и те же действия, можно воспользоваться следующей конструкцией:

switch(key)


{ case '0':

case '1':

case '2':

case '3':

case '4':

case '5':

case '6':

case '7':

case '8':

case '9':

printf("Это цифрв"); }

4.3. Оператор цикла while

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

while(выражение)

оператор

4.4. Опреатор цикла do while

Условие проверяется после завершения очередной итерации (цикл с постусловием)

do

оператор

while(выражение)