С помощью этого оператора гораздо проще решить пример 5-2 (program P5_2).
Оператор цикла с постусловием:
üREPEAT оператор UNTIL условие
Оператор, в цикле выполняется до тех пор, пока ложно условие. В отличие от оператора WHILE здесь цикл будет выполнен хотя бы раз. Структуру с постусловием удобно применять в случае, если цикл необходимо выполнить хотя бы раз независимо от значения условия или, если само условие формируется в цикле и не может быть оценено до входа в цикл. Внутри цикла нет необходимости использовать блок begin (блок образуют сами слова repeat...until). Пример решения предыдущей задачи приведен справа. В виду того, что здесь оказывается возможным деление на ноль, в программу вставлен оператор if, предотвращающий такую возможность.
Выход из цикла после выполнения всех его циклов называется естественным. Принудительный выход для циклов любого вида может быть выполнен специальным оператор выхода
üBREAK
который переключает программу на оператор, следующий сразу за операторами, включенными в цикл. Принудительный выход из цикла в любое другое место, очевидно, может быть осуществлен и оператором GOTO. Если нужно, не выполняя до конца текущего цикла, начать следующий, следует воспользоваться оператором
üСONTINUE
Действие указанных операторов (применительно к циклу FOR) иллюстрирует рисунок справа.
@ Задание 5.7.Написать программу, в которой вводятся два операнда Х и Y и знак операции (+,–,/,*). Вычислить результат Z в зависимости от знака. Предусмотреть реакции на возможный неверный знак операции, а также на ввод Y=0 при делении. Организовать возможность многократных вычислений без перезагрузки программа (т.е. построить цикл). В качестве символа прекращения вычислений принять ‘0’.
Функциональные ряды. При работе с компьютером возникает впечатление его огромной интеллектуальной силы. На самом деле это не так. Собственно процессор умеет (правда очень быстро) выполнять только четыре арифметических действия и логические операции, т.е. располагает возможностями ученика 1-го класса. Откуда же вся его математическая мощь. Ответ простой – от программистов. Разработчики компиляторов языков (в частности Паскаля) побеспокоились о том, чтобы в нем присутствовали многие математические функции. Когда мы используем выражение exp(x) мы на самом деле вызываем подпрограмму вычисления ex, написанную для нас неизвестным автором из фирмы Borland. Однако мы можем сделать это и сами. Существует методы, позволяющие вычислять функции, используя лишь небогатые возможности процессора. Так из математики хорошо известны функциональные ряды Тейлора (здесь аргумент включен в члены ряда). Хотя такие ряды бесконечны, нам нет необходимости (и возможности) вычислять их целиком. Значения элементов ряда быстро убывают и мы можем прекратить вычисления в тот момент, когда очередной член станет меньше заданной погрешности ε.
Пример 5-7. Вычислить с заданной погрешностью функцию exдля произвольного значения Х<1. Ряд Тейлора для нее выглядит следующим образом.
ex≈1+x+x2/2!+ x3/3!+ x4/4!+...
Отсюда можно записать аналитические зависимости (справа). Здесь у – искомая функция, r – элемент ряда, i – номер члена разложения. Напишите программу вычисления функции с погрешностью не более 0,001. Это означает, что вычисления можно прекратить, если очередной член разложения становится меньше указанного значения.
Сложные циклы.Этот термин означает вложенность одного цикла в другой.
Пример 5-8. Вычислить значения функции Y=X2+Z для 0≤X≤4 и 0≤Z≤ 10 с шагом 1. В этой функции два аргумента, т.е. она является не плоской кривой, а криволинейной поверхностью. Решение здесь очень простое. Строятся два цикла – внешний (по Х) и внутренний (по Z). Поскольку аргументы и функция целочисленные и шаг равен 1, можно использовать оператор for. В данном случае безразлично, какой параметр поместить снаружи, а какой внутри. Здесь на одно изменение переменной Х произойдет 11 изменений Z.
В следующих заданиях условия целочисленности аргумента и/или шаг=1 не соблюдаются и для организации циклов придется использовать оператор while.
@ Задание 5.8. Вычислить функции Y=X2+Z для 0≤X≤4 с шагом 1 и 1≤Z≤10 с шагом 2.
@ Задание 5.9. Вычислить функции Y=X2+Z для 0≤X≤4 с шагом 0,5 и 1≤Z≤10 с шагом 2.
@ Задание 5.10. Напечатать таблицу умножения.
6. МАССИВЫ
Как правило, данные для вычислений задаются в упорядоченной форме – в виде последовательности ряда (вектора) чисел или в виде таблицы (матрицы) чисел. Такие совокупности данных называются массивами. Например, вектор А длиной К чисел и матрица В из N строк и M столбцов (всего из NM элементов) выглядят следующим (справа) образом.
Построение программ, оперирующих с элементами массивов – важнейшая часть техники программирования.
Цифры при имени массива, указывающие порядковый номер элемента, называются индексами. Элементы массивов Аi и Bij обозначаются как А[I] и B[I,J]. К массиву в целом обратиться нельзя. Обработка массива означает последовательную обработку отдельных его элементов.
Оператор описания массивов. Если предполагается работа с массивами, предварительно следует “известить” об этом компьютер в разделе описаний (VAR) программы. Для одномерного массива это оператор вида
üимя_массива: ARRAY [диапазон] OF тип_массива
Например,
VAR x,z: ARRAY [1..8] OF REAL;
y: ARRAY [5..10] OF INTEGER; b: ARRAY [1..4, 1..5] OF INTEGER;
Здесь первый оператор описывает массивы X и Z из 8-ти элементов (с номерами от 1 до 8) вещественного типа. Второй – массив Y из 5-ти элементов (с номерами от 5 до 10) целочисленного типа, третий – двумерный массив B из четырех строк и пяти столбцов.
Первоочередной задачей при работе с массивами является ввод-вывод данных. Ввод организуется с помощью циклов, как показано ниже.
VAR i,j: INTEGER;
FOR i:=1 TO 8 DO BEGIN{ввод вектора Х с подсказкой}
WRITE('x[',i,']='); READLN(x[i]) END;
FOR i:=1 TO 4 DO{ввод матрицы В с подсказкой}
FOR j:=1 TO 5 DO BEGIN
WRITE('b[',i,j,']='); READLN(b[i,j]);
END;
FOR i:=1 TO 4 DO BEGIN{построчный вывод матрицы B}
FOR j:=1 TO 5 DO WRITE('b[',i,j,']=',b[i,j]:4:1,' ');
WRITELN{вывод пустой строки}
END;
Сначала осуществляется ввод в вектор X. На экране мы увидим, например, подсказку вида х[2]=, после чего можно ввести значение этого элемента. Аналогичную подсказку (b[2,4]=) увидим для матрицы В размерностью 4 строки на 5 столбцов. Ввод осуществляется с помощью двух циклов, один из которых вложен в другой. В наружном цикле изменяется первый индекс I элемента матрицы В, во внутреннем – второй индекс J. Индекс J изменяется быстрее, чем I (на одно изменение I индекс J изменяется 5 раз). Это означает, что ввод элементов матрицы будет производиться в следующей последовательности: B[1,1], B[1,2],...B[1,5]; B[2,1],B[2,2],...B[2,5];...;B[4,1], B[4,2], ...B[4,5], т.е. по строкам. Аналогично осуществляется и вывод, но вместо оператора READLN используется оператор WRITELN. В примере производится вывод данных из матрицы В. Если позволяет ширина экрана, удобно выводить одну строку матрицы на одной строке монитора. Оператор WRITE('b[',i,j,']= ',b[i,j]:4:1,' ') выводит данные, например, в виде b[2,3]=25.3.Поскольку оператор WRITE не переводит строку вывода, принудительный переход на новую строку осуществляется пустым оператором WRITELN после того, как строка была полностью выведена.
Начальные значения скалярным переменным и элементам массива (в особенности при отладке) можно задать в разделе констант (начинается со слова const). Например:
CONST z:ARRAY [1..3] OF INTEGER=(4,5,2);
x: INTEGER=5;
r:ARRAY [1..3,1..2] OF INTEGER=((1,2),(3,4),(5,6));
Здесь вектору Z присваиваются значения: z[1]=4, z[2]=5, z[3]=2, переменной х: 5, а прямоугольной матрице R: r[1,1]=1, r[1,2]=2, r[2,1]=3, r[2,2]=4, r[3,1]=5, r[3,2]=6.
Пример 6-1. В векторе С предельной размерности 10 элементов найти максимальный по значению элемент и его номер в С по порядку. В программе сделана проверка для N=4 и C=[5,2,7,4] в ее обрабатывающей части. Здесь переменная М запоминает значение максимального элемента, а К – номер этого элемента в векторе С. Первоначально в качестве такого элемента берется самый первый.
program P6_1; var i,n,m,k: integer; c: array [1..10] of integer; begin write('n='); readln(n); for i:=1 to n do begin write('i=',i:2,' c='); readln(c[i]); end; | n=4 Пр | оверка | ||
m:=c[1]; k:=1; for i:=2 to n do if m<c[i] then begin m:=c[i]; k:=i end; writeln('m=',m:2,' n=',k:1); end. | m=5, k=1 i=2 5>2 | i=3 5<7 m=7,k=3 | i=4 7>4 | i=5 7, 3 |
Пример 6-2. Определим значения вкладов в банке на конец года. Положим, имеется N счетов вкладчиков. Для всех них известны значения остатков на счете в конце каждого квартала. Следует определить и напечатать значения всех вкладов на конец года с учетом известного процента роста вклада. Все суммы считаем целочисленными (копейки игнорируем).
Program P6-2;
var n,i,j:integer; s,y,sr:real; x: array [1..10,1..5] of real;
Begin
readln(n);{число вкладов (до 10)}
for i:=1 to n do; for j:=1 to 4 do begin{ввод сведений о вкладах}
write('введите остаток по вкладу номер', i,'за', j ,'квартал');
readln(x[i,j]);
End;
s:=0;
writeln(' Счет № Остатки по кварталам');
writeln(' I II III IV ВСЕГО');
for i:=1 to n do begin{вычисление годового остатка}
y:=(x[i,1]+x[i,2]+x[i,3]+x[i,4])/4;{средний остаток}
if y<=5000 then y:=1.05*y;
if (y>5000) and (y<=10000) then y:=1.1*y;
if y>10000 then y:=1.2*y;
x[i,5]:=x[i,4]+y;{остаток вклада с начислениями}
writeln(i,x[i,1],x[i,2],x[i,3],x[i,4],x[i,5]);
s:=s+x[i,5];
End;
sr:=s/n;
writeln('Сумма всех вкладов в банке = ',s);
writeln('Средний вклад = ',sr);
End.
Данные о вкладах хранятся в массиве Х из N строк и пяти столбцов. Первые четыре элемента каждой i-ой строки (Х[i,1], Х[i,2], Х[i,3], Х[i,4]), хранят остатки вклада на конец каждого из четырех кварталов года. В последний, пятый элемент строки X[i,5] следует занести вычисленную величину вклада на конец года, который равен остатку вклада на конец последнего квартала Х[i,4], плюс установленный процент от среднего значения вклада Y=(Х[i,1]+ Х[i,2]+Х[i,3]+ Х[i,4])/4 за год. Положим, определено, что на вклад до 5000 предусмотрен процент роста – 5%, на вклад до 10000 – 10%, на вклад свыше 10000 – 20%. Иными словами установлены коэффициенты роста 1.05, 1.1 и 1.2 соответственно. Кроме перечисленного, следует найти сумму всех вкладов в банке S и среднее значение вклада, приходящееся на одного вкладчика (S/N).
@ Здания для самостоятельного решения
Задание 6.1. В векторе Х найти элемент, максимально близкий к некоторому, произвольно заданному числу Y и его номер.
Задание 6.2. В векторе Х сдвинуть по кольцу его содержимое на 1 клетку, на 2, на К клеток. Подсказка. Здесь понадобится вспомогательный массив Y, куда и будем заносить уже сдвинутые данные, а затем возвращать их в Х.
Задание 6.3. Пусть имеется таблица-массив, содержащая сведения о работниках (всего К человек) бригады: Имя, Отработано дней, Должностной оклад, Фактическая зарплата. Рассчитать зарплату для каждого работника.
Задание 6.4. Усложним предыдущее задание. Пусть бригаде установлена премия в Р=100000р., которая делится не поровну, а с учетом коэффициента трудового участи (КТУ). Рассчитайте размер премии для каждого.
Задание 6.5.Имеется прямоугольная матрица X[N,M]. Заполнить элементы матрицы числами натурального ряда в последовательности, указанной на рисунке справа.
Задание 6.6. Запрограммировать процесс выбора в детской считалке. Пусть нужно выбрать случайным образом дежурного по кухне из группы в M человек. Дети становятся в круг и “считаются” от номера 1 по следующему правилу. Из круга по часовой стрелке удаляется с определенным шагом N каждый участник. В конце останется только один – дежурный. Для (см. рисунок) примера M=8, N=3. Тогда последовательно из круга выйдут номера 1,4,7,3,8,6. Наконец останутся только номера 2 и 5 и счет продолжается уже между ними 2→5→2. Таким образом, “повезло” номеру 5. В программе вывести номера всех выбывающих элементов и номер дежурного.
Сортировки в массиве.Сортировка данных является очень распространенной задачей и для нее имеется несколько методов.
Пример 6-3.В векторе X расположить элементы в порядке убывания их значений. Алгоритм реализуется при помощи двух вложенных циклов. В наружном цикле последовательно перебираются числа x(i) массива и во внутреннем сравниваются со всеми оставшимися числами x(j) справа от данного. Если выясняется, что какое-то из x(i) меньше сравниваемого, они меняются местами – большее число становится на место меньшего. В программе для наглядности в качестве элементов массива взяты их номера i. Если вектор имеет длину четыре (N=4), будет выполнена следующая последовательность перестановок чисел:1,2,3,4: при i=1 – 2,1,3,4; 3,1,2,4; 4,1,2,3;при i=2 – 4,2,1,3; 4,3,1,2;при i=3 – 4,3,2,1.Здесь для обмена значений элементов x[i]↔x[j] вводится специальная “транзитная” переменная М для временного хранения данных. Действительно, если использовать только операторы x[i]:=x[j]; x[j]:=x[i] мы получим неверный результат. Хотя х[i] и примет значение х[j], оператор x[j]:=x[i]ничего не изменит, ведь х[i] теперь равен х[j]. С тем, чтобы не потерять исходное значение х[i], оно запоминается в переменной М.
@ Здания для самостоятельного решения
Задание 6.7. Сортировка выбором.Рассмотренный алгоритм очень прост для программирования, но содержит лишние действия. Очевидно, нет необходимости делать обмен элементов всякий раз, когда встретился больший элемент. На самом деле это нужно выполнить только единожды для максимального элемента из оставшихся. Напишите такую программу.
Задание 6.8. Сортировка обменом.Метод заключается в анализе соседних элементов массива. Если х[i]<х[i+1] элементы меняются местами. По достижении конца массива в нижней клетке окажется самое маленькое значение. Затем процесс повторяется, но уже без последнего элемента и т.д. Такой просмотр вектора нужно выполнить N раз. Однако его можно сократить, если зафиксировать факт прекращения обменов.
Задание 6.9.Пусть имеется таблица работников цеха со столбцами: Имя, Бригада, Отработано дней, Зарплата. Отсортировать любым методом таблицу по возрастанию значений столбца “Отработано дней”.
Задание 6.10.Отсортировать ту же таблицу так, чтобы сначала люди в ней располагались по размеру зарплаты, а затем по числу отработанных дней. Т.е. работники, имеющие одинаковую зарплату, должны идти в порядке количества отработанных ими дней.
Задание 6.11.Отсортировать таблицу по номерам бригад. Подвести итоги для каждой бригады (число работников, число дней, суммарная зарплата) и для всего цеха целиком.
Задание 6.12. Поиск в отсортированном массиве.Очевидно, что найти нужное значение Х в некотором массиве можно сплошным перебором данных. Однако в худшем случае (если искомое значение находится внизу или его нет вовсе) нам придется просмотреть все элементы массива. Если массив отсортирован, имеется гораздо более быстрый алгоритм поиска, называемый бинарным. Массив делится пополам и Х сравнивается со средним элементом. Если Х оказался больше, пополам делится нижняя часть, если нет – верхняя и поиск ведется там т.д. Напишите программу поиска.
Пример 6-4.Заполнить двумерный массив A(N,N) элементами натурального ряда (т.е. числами 1,2,3, и т.д.), начиная с нижнего правого угла в направлении, показанном пунктиром на рис. 6.4а. Чтобы выявить необходимые законы перемещения по матрице, в ее клетках показаны индексы элементов. Способов решения таких такого рода задач может быть несколько.
Заметим, что в зависимости от того, с какой стороны матрицы мы находимся, нам необходимо совершать следующие движения:
1). если у правой стороны матрицы, то вверх на одну клетку и вниз-влево по диагонали до нижней границы;
2). если у нижней границы, то влево на одну клетку и вверх-вправо по диагонали до правой границы;
3). у верхней границы – влево на одну клетку и вниз-влево до левой границы;
4). у левой границы – вверх на одну клетку и вверх-вправо до правой границы.
В любом случае движение прекращается при достижении клетки A(1,1). Результат заполнения массива А показан на рис. 6.4б.
Программа приведена ниже. Здесь ST – номер текущей строки (первоначально N, поскольку движение начинается с последней ячейки массива A(N,N)), KL – номер текущей колонки (первоначально N), K – растущее значение натурального ряда (первоначально 1). Самый внешний цикл (while k<n*n) ограничивает все действия достижением растущим значением натурального ряда K значения N*N, поскольку именно столько клеток имеется в квадратной матрице размерности N. Внутри цикла организованы четыре разные группы операций в зависимости от того, какое из четырех типовых элементарных действий (см. выше) выполняется. Определяет тип действия оператор if/else if, в котором выясняется, где именно вы находитесь. Внутри каждого IF организован цикл while, в котором осуществляются необходимые перемещения в матрице в соответствии с одним из четырех алгоритмов. По завершении всех действий, т.е. после достижения последней клетки (в нашем случае A(1,1)), выполняется последовательная печать строк матрицы A с заполненными клетками.
Program P6-4;
Uses crt;
var n,i,j,st,kl,k:integer;
a:array [1..10,1..10] of integer;
Begin;
Clrscr;
write(‘укажите размерность матрицы (до 10)’); readln(n);
st:=n; kl:=n; k:=1; {текущие строка и колонка, элементы натурального ряда}
a[st,kl]:=k;{начальному элементу a(n,n) присваивается 1}
{цикл - конец вычислений по достижении последнего элемента массива}
while k<n*n do begin
{правая сторона – 1 клетка вверх}
if (kl=n) and (st>1) then begin st:=st-1; k:=k+1; a[st,kl]:=k;
while (st<n) and (kl>0) do begin st:=st+1; kl:=kl-1; k:=k+1; a[st,kl]:=k end;{далее вниз-влево}
End
{нижняя сторона – 1 клетка влево}
else if (kl>1) and (st=n) then begin kl:=kl-1; k:=k+1; a[st,kl]:=k;
while (st>1) and (kl<n) do begin st:=st-1; kl:=kl+1; k:=k+1; a[st,kl]:=k end;{далее вверх-вправо}
End
{верхняя сторона – 1 клетка влево}
else if (kl>1) and (st=1) then begin kl:=kl-1; k:=k+1; a[st,kl]:=k;
while (st<n) and (kl>1) do begin st:=st+1; kl:=kl-1; k:=k+1; a[st,kl]:=k end;{далее вниз-влево}
End
{левая сторона – 1 клетка вверх}
else if(kl=1) and (st>1) then begin st:=st-1; k:=k+1; a[st,kl]:=k;
while (st>1) and (kl>0) do begin st:=st-1; kl:=kl+1; k:=k+1; a[st,kl]:=k end;{далее вверх-вправо}
End;
End;
writeln('вывод результата');
for i:=1 to n do begin for j:=1 to n do write(a[i,j]:4); writeln; end;
End.
СИМВОЛЬНЫЕ ДАННЫЕ
Паскаль позволяет обрабатывать не только числовые, но и символьные данные, которые бывают двух типов. Символы описываются в описательной части программы атрибутом CHAR и хранят один знак. Строки это цепочки символов и описываются атрибутом STRING. Например, var ST: char; SM: string[32]; SS: string. Здесь ST – одиночный символ, SM – строка не более чем из 32 символов. Если количество символов не указано, строке присваивается емкость в 255 символа. В программе и символы и строки должны заключаться в апострофы, например: ST:=‘a’; SM:=‘экзамен’;. Над символами и строками с помощью приведенных в таблице функций производятся различные операции.
Функция | Назначение |
concat (строка1, строка2) | Соединяет строки строка1 и строка2 в одну (пример: concat('а','б')='аб') |
copy(строка, позиция, количество) | Копирует из строки, начиная с заданной позиции количество символов (пример: copy('программа',4,5)='грамм') |
delete(строка, количество, позиция) | Удаляет из строки количество символов, начиная с заданной позиции (пример: delete('программа',4,4)='прома') |
insert(строка1, строка2, позиция) | Вставляет строку1в строку2, начиная с заданной позиции (пример: insert('сколько стоит','это ',9)='сколько это стоит') |
length(строка) | Определяет длину строки (пример: length('саша')=4) |
pos(строка1, строка2) | Отыскивает в строке2 первое вхождение строки1 и определяет номер позиции, с которой она начинается (пример: pos('саша','а')=2) |
upcase(символ) | Преобразует символ латинского алфавита в заглавный |
str(число, формат, строка) | Преобразует число типа integer или real в строку по заданному (если есть) формату (примеры: str(5,x) – результат х='5', str(18.3:5:2,y) – результатy='18.30') |
val(строка, число, признак) | Преобразует строку в целое или вещественное число, если оно прошло успешно, признак =0 (пример: val('12.4',x,k) – получим x=12.4, k=0) |
ord(символ) | Преобразует символ в целое число – код символа в ASCII-таблице (пример: ord(Я)=159) |
chr(число) | Преобразует число в символ из ASCII-таблицы с соответствующим кодом (пример: chr(159)='Я') |
Над символьными данными определена операция ‘+’ (аналогичная concat) сцепления. Пример: ‘студент ’+’Петров’= ’студент Петров’.
Пример 7-1.В символьной строке Х=‘Петров Саша’ поменять местами имя и фамилию и поместить результат в Y. Решение потребует трех действий: 1). Нахождение позиции пробела n=7, 2). Остаток фразы от пробела (т.е. ‘Саша’) поместить в Y. 3). Дополнить Y пробелом и начальным фрагментом фразы Х до пробела. Для наглядности процесс реализован в трех операторах. Но можно записать его и в один
y:=copy(x,pos(' ',x)+1,length(x))+' '+copy(x,1,pos(' ',x)-1);
Пример 7-2.В символьной строке Х подсчитать количество K слов. Считаем, что число слов равно числу пробелов +1. Первый вариант программы P7_2 имеет недостаток. Если перед первым словом предложения или после последнего имеются пробелы, или внутри фразы встречается более одного пробела разом, число найденных слов окажется больше фактического. Исправим программу с учетом этих обстоятельств. Во втором варианте добавлен просмотр начала фразы до первого не пробела (j – номер первого значащего символа). Затем просматривается остаток фразы, где подсчитываются только одиночные пробелы (после пробела в i-ой позиции не должен стоять другой пробел). Дополните программу выдачей по отдельности всех слов предложения и их (справа) длин.
коды | символы |
0..32 | управляющие |
65..90 | A..Z |
97..122 | a..z |
128..159 | А..Я (кроме Ё) |
160..175 | а..п (кроме ё) |
224..239 | р..я |
240,241 | Ё,ё |
Представление символьных данных. Каждому символу ПК сопоставлен код (целое число от 0 до 255) из ASCII-таблицы. Первые 128 символов включают цифры, знаки, латинские символы. Из них символы с кодами 0..31 являются служебными (возврат каретки, перевод строки и т.д.). Латинские буквы A..Z имеют коды 65..90, a..z – 97..122. Следующие 128 позиций заняты символами псевдографики и буквами национального алфавита. В кириллице буквы A..Я имеют коды 128..159, a..п – 160..175, р..я – 224..239, буквы Ё – 240, ё – 241. Заметим, что коды заглавных и строчных букв a..п различаются на 32, а букв р..я – на 80. Очевидно, что на клавиатуре нет всех 256 знаков. Тем не менее, они могут быть отражены в программе с помощью своего кода в форме: #код. Так, оператор write(#65,#177,#201,#205,#187); выведет строку: “A▒╔═╗”. Символы, отсутствующие на клавиатуре, можно найти в справочнике, а можно и вывести вместе с их кодами на экран с помощью операторов: for i:=0 to 255 do write(chr(i),i:3,' ');. Отметим, что коды от 0 до 31 являются управляющими и, хотя многие из них имеют экранное отображение, использовать эти символы для непосредственного вывода нельзя. Символьные данные можно сравнивать между собой. При этом более короткая строка дополняется символами с кодом 0 до размеров более длинной строки. Далее последовательно слева направо коды символов сравниваются попарно из обеих строк (чей код больше – тот символ больше). Например: ‘а’<’б’; ‘а’=’а’; ’а’>’А’ (заглавные буквы имеют меньший код); ‘ВАЛЯ’<’ВАСЯ’ (расхождение в третьем символе, где ‘Л’<’C’); ‘ЯША’>’ПETP’ (буква Я больше П).
Пример 7-3.В строке S содержатся русские и латинские символы (заглавные и строчные), цифры и знаки препинания. Преобразовать все символы S в заглавные. Результат занести в D. В программе Х – строка размером в один символ, куда заносятся поочередно все символы из S для преобразования. В результате получим D='абвxyz123ABC'. Преобразование здесь осуществляет оператор вида X:=chr(ord(x[1])-32). Здесь сначала выясняется код ord(x[1])текущего символа, из него вычитается 32 (т.е. вычисляется код соответствующей заглавной буквы), и, наконец, этот код снова преобразуется в символ.
Program P7_3;
var x:string[1]; d:string; i:integer;
const s:string='абвxyz123ABC'; {тестовый пример}
Begin
d:='';
for i:=1 to length(s) do begin{перебор символов в S}
x:=copy(s,i,1);{очередной символ заносится в Х}
{если 'а'<=буква<='п', код уменьшаем на 32}
if (x>='а')and(x<='п') then x:=chr(ord(x[1])-32);
{если 'р'<=буква<='я', код уменьшаем на 80}
if (x>='р')and(x<='я') then x:=chr(ord(x[1])-80);
{латинские преобразуем в заглавные}
if x<'А' then x:=upcase(x[1]);
d:=d+x;{заполнение слова D}
End;
write(d);{результат: 'АБВXYZ123ABC'}
End.
@ Здания для самостоятельного решения
1. В символьной строке Х удалить лишние (начальные, конечные и сдвоенные) пробелы.
2. В Х подсчитать число вхождений слова ‘его’.
3. В Х поменять порядок символов на обратный.
4. В Х напечатать самое длинное слово.
5. В Х подсчитать число вхождений всех встречающихся знаков.
6. В Х подсчитать число вхождений произвольного символа.
7. В Х в каждом слове поменять порядок символов на обратный.
8. В Х расположить слова в порядке увеличения их длины.
9. Имеется строка Х длиной ≤N, предназначенная для вывода. Выровнять при печати X к правой границе так, чтобы строка занимала все N позиций. Выравнивание производить за счет равномерного увеличения числа пробелов между словами.
10. Зашифровать строку Х, заменив каждый символ, на символ, следующий за данным по алфавиту (буква А заменяется на Б и т.д., буква Я заменяется на А). Расшифровать полученный текст.
11. Написать программу формирования числа (до 1000 руб.) в сумму прописью (например, 103=‘сто три рубля’).
12. В строке Х имеются открывающиеся и закрывающиеся скобки (включая вложенные). Выяснить, правильно ли они расставлены. Если есть ошибки – сообщить об этом конкретно, включая номер позиции, где она обнаружена.
13. В строка Х содержит любые русские и латинские символы (как заглавные, так и строчные), цифры и знаки препинания. Преобразовать все символы Х в строчные. Результат занести в Y.
14. Пусть имеется таблица работников бригады со столбцами: Имя, Отработано дней, Зарплата. Отсортировать любым методом таблицу по алфавиту. Для упрощения будем считать, что имена не превышают 8-ми символов, содержат только заглавные буквы и не имеют буквы Ё (эта буква в кодовой таблице русских символов находится не на месте).
15. Отсортировать таблицу по алфавиту, где для имен допускаются любые буквы русского алфавита, включая Ё и ё. Сложность здесь заключается как раз в этих буквах. Их коды 240 и 241, т.е. самые большие среди русских букв, в виду чего сравнивать слова придется не целиком, а побуквенно. В случае, если встретилась буква Ё и ё, в программе они должны считаться большими букв Е/е и меньшими Ж/ж.
16. Написать программу, которая из заданной даты (в диапазоне 1900..2100) формирует следующую. Исходная дата задается в форме текстовой строки вида ‘дд.мм.гггг’, например ’06.04.2002’. Подсказка: признаком високосного года является кратность года числу 4. Исключением являются года с двумя нулями на конце, число сотен в которых не кратно 4 (например, 1800, 1900, 2100).
17. Написать программу, которая от заданной даты (диапазон 1900..2100) находит новую, отстоящую от данной на М месяцев. Если в новом месяце такой даты нет, берется последний день нового месяца.
18. Написать программу, которая от заданной даты (1900..2100), находит новую, отстоящую от данной на Х дней.
ЗАПИСИ
Массивы определяют однородную совокупность данных. На практике часто требуется объединять в один объект данные разных типов. Так для хранения сведений о месячной выработке работников бригады понадобятся следующие сведения: Табельный номер, Имя, Дневной тариф, число отработанных Дней. Ясно, что табельный номер должен быть целого типа, имя – строкового, тариф и дни – вещественного. Мы можем объединить эту совокупность данных (они называются полями) в объект, называемый запись (record). Дадим ему, например имя Vr (от слова выработка). Первоначально удобно описать тип-запись как тип данных конструкцией, изображенной слева. Позже с помощью оператора Var можно описать уже конкретные записи данного типа.
Пример (ниже). Здесь сначала описан тип записи Vr, состоящей из полей: tab, im, tarif, dn соответствующих типов. Затем в разделе Var описаны уже конкретные (рабочие) записи: X и массив записей Y. Обращаться к элементам записей нужно, используя полное имя (имязаписи.имяполя), например x.tarif, x.im. А для массива записей нужно указывать и индекс: y[3].tarif. Записи удобно использовать при работе с файлами.
type vr=record{объявление типа записи}
tab: integer;{табель}
im: string[4];{имя}
tarif, dn: real
End;
var x:vr; y:array [1..5] of vr;
ФАЙЛЫ
Информация в компьютере хранится в файлах (обычно на диске). Файловая система состоит из двух уровней: физического файла и логического файла. Физический файл – это собственно файл данных на диске, порт, принтер, любое устройство. Логический файл – файловая переменная (типа String), описанная в программе в разделе переменных. В зависимости от способа объявления формируется один из следующих типов файлов:
1. Типизированные файлы. Состоят из данных одного, объявленного типа.
Объявление файла: [имя]: file of [тип];
Примеры: A: file of string[80]; F1: file of char; F2: file of real;
2. Текстовые файлы. Состоят из символов.
Объявление текстового файла: [имя]: text;.
Пример: f3: text;
В типизированных файлах информация хранится в двоичном виде, а в текстовых – в естественном. Элемент файла – запись (не путать с понятием record). Обычно, это строка файла.
Подлинное имя дискового файла используется только чтобы связать его с внутренним именем в программе, с которым она далее и работает. Для работы с файлами всех типов используется ряд процедур и функций:
assign(фп, файл) | Связывает файл с файловой переменной (ФП). |
reset(фп) | Открывает существующий файл для чтения из него. |
rewrite(фп) | Создает и открывает файл для записи в него. |
close(фп) | Закрывает файл. |
erase(фп) | Стирает файл (он должен быть закрыт). |
eof(фп) | Признак конца файла (True, если конец). |
Ввод и вывод информации для типизированных и текстовых файлов производится процедурами:
read(f,x1,x2,…xn)илиreadln(f,x1,x2,…xn) – чтение информации х1,х2,…,xn из логического файла f.
write(f,x1,x2,…xn)илиwriteln(f,x1,x2,…xn) – запись информации х1,х2,… хn в логический файл f.
Для управления текстовыми файлами используется следующие процедуры и функции:
append(фп) | Открывает файл для дополнения. |
eoln(фп) | Признак конца строки (True, если конец). |
read(фп,переменные) | Считывает данные из файла. |
readln(фп,переменные) | Считывает данные из файла, переходит на следующую строку. |
write(фп,переменные) | Записывает данные в файл. |
writeln(фп,переменные) | Записывает данные в файл, переходит на следующую строку. |
Для нетекстовых файлов:
filesize(фп) | Число записей в файле. |
filepos(фп) | Номер текущей записи. |
seek(фп,номер) | Устанавливает указатель на запись с заданным номером. |
truncate(фп) | Усекает файл до текущей позиции. |
Различают два способа доступа к файлам. Последовательный, когда к конкретной записи можно перейти, только перебрав все предыдущие, и прямой (или произвольный) доступ к любой записи по ее номеру. Текстовые файлы могут иметь в каждой строке записи произвольной длины и поэтому реализуют только последовательный доступ. Другие типы файлов имеют записи фиксированной длины. В виду этого здесь можно вычислить положение любой записи на диске, т.е. организовать прямой доступ.
Пример 9-1.
а). Вычислить по точкам функцию y=x/2 для x=0,0.5,1.0, …4 и записать результаты в текстовый файл с именем func. Текстовый файл удобен тем, что его можно просмотреть в любом текстовом редакторе и, при желании откорректировать данные. Файлу не обязательно иметь расширение. Мы придали ему расширение txt с тем, чтобы проще было его просматривать в файлерах Проводник или TotalCommander (эти программы для файлов с расширением txt автоматически вызывают Блокнот). Физическому файлу дадим имя func.txt, а логическому имя f, и именно с ним будем далее работать.
б). Cоставить программу чтения из файла func.txt записанной ранее в него информации.
program 9_1a;{запись вычисленной функции в файл}
var f:text;{объявлен текстовый логический файл f}
x,y:real;
Begin
{логический файл f связывается с физическим func.txt}
assign(f,'func.txt');
rewrite(f);{файл f открывается для записи в него}
x:=0;
while x<=4 do begin{вычисление в цикле функции}
y:=x/2; x:=x+0.5;
writeln(f,x:3:1,y:4:1);{запись в файл переменных х и у}
End;
close(f);{закрытие файла}
End.
program 9_1b;{чтение записанных ранее данных из файла}
var f:text;{объявлен текстовый файл f}
x,y:real; i:integer;
Begin
assign(f,'func.txt');
reset(f);{открытие файла для чтения}
for i:=1 to 9 do begin
read(f,y,x);{чтение из файла в память}
{вывод на монитор, считанной из файла информации}
writeln('y=',y:3:1,' x=',x:4:1);
End;
close (f);{закрытие файла}
End.
Пример 9-2.Посчитать зарплату рабочих. Сведения об их месячной выработке находятся в типизированном (типа record) файле VIR (рис. 9.1).
файл | Vir | файл | Ved | |||||
tab | im | tarif | dn | im | zar | nalog | vid | |
таб | имя | тариф | дни | имя | зарплата | налог | выдать | |
Иван | Иван | |||||||
Петр | Петр | |||||||
Олег | Олег | |||||||
Рис. | 9.1 |
Он содержит поля: табельный номер tab, имя im (длиной до 4-х знаков), дневной тариф tarif работника, число отработанных им за месяц дней dn. Эти данные вводятся оператором. На основании их компьютером подсчитывается и заполняется файл ведомости VED, содержащий имя im, зарплату zar (=tarif*dn), налог nalog (=13%*zar) и сумму к выдаче vid (=zar-nalog). Далее содержимое файла выводится с подсчетом итоговых сумм. Здесь придется написать две программы. Программой Vvod выполняется следующая последовательность действий: 1). Заполняется файл Vir. 2). Считывается содержимое Vir в массив V. 3). Выполняются все расчеты и заносятся в массив R. 4). Данные из R сохраняются в файле Ved. Программа Vivod реализует только два действия: вывод всей ведомости к оплате или вывод сведений только об одном работнике по запросу (по имени).
program Vvod;{ввод данных и сохранение результата к примеру 9-2}
Uses crt;
const n=3;
type vr=record{объявление записи для Выработки}
tab: integer;{табель}
im: string[4];{имя}
tarif, dn: real;
End;
vd=record{объявление записи для Ведомости}
im: string[4];
zar, nalog, vid: real;
End;
var vir: file of vr;{объявление файла Выработки}
ved: file of vd;{объявление файла Ведомости}
v: array[1..n] of vr;{массив V для ввода}
r: array[1..n] of vd;{массив R для расчета}
I: integer;
Begin
Clrscr;
{связывание логического и физического файлов}
assign(vir,'vir'); assign(ved,'ved');
rewrite(vir);{открытие файла Vir для записи}
writeln('введите!');
writeln('табель, имя, тариф, дни');
for i:=1 to n do begin
readln(v[i].tab); readln(v[i].im);
readln(v[i].tarif); readln(v[i].dn);
writeln(v[i].tab:2, v[i].im:6, v[i].tarif:3:0, v[i].dn:4:0);
write(vir,v[i]);{занесение в файл Vir очередной записи}
End;
reset(vir);{открытие файла Vir для чтения}
rewrite(ved);{открытие файла Ved для записи}
for i:=1 to n do begin{вычисления}
read(vir,v[i]);{чтение записи из файла Vir}
r[i].im:=v[i].im; r[i].zar:=v[i].tarif*v[i].dn;
r[i].nalog:=0.13*r[i].zar; r[i].vid:=r[i].zar-r[i].nalog;
write(ved,r[i]);{занесение записи в файл Ved}
End;
reset(ved);{открытие файла Ved для чтения}
for i:=1 to n do begin{печать}
read(ved,r[i]);{чтение записи из файла Ved}
writeln(r[i].im:4, r[i].zar:5:0, r[i].nalog:7:2, r[i].vid:8:2);
End;
close(ved);close(vir);{закрытие файлов}
End.
program Vivod; {вывод данных по запросу к примеру 9-2}
Uses crt;
const n=3;
Label m;
Type
vd=record{объявление записи для Ведомости}
im: string[4];
zar, nalog, vid: real;
End;
var ved: file of vd;{объявление файла Ведомости}
r: array[1..n] of vd;{массив R для вывода}
xz,xn,xv:real;{итоги: зарплата, налог, выдать}
I: integer;
x:string[4];{искомое имя}
Begin
Clrscr;
assign(ved,'ved.txt');
write('показать всех (0) или одного (имя)? '); readln(x);
writeln(' имя зарплата налог выдать');
reset(ved);{открытие файла Ved для чтения}
if x='0' then begin{вывод всех работников}
for i:=1 to n do begin
read(ved,r[i]);{чтение записи из Ved}
writeln(r[i].im:4, r[i].zar:9:0, r[i].nalog:7:2, r[i].vid:8:2);
{подсчет итогов}
xz:=xz+r[i].zar; xn:=xn+r[i].nalog; xv:=xv+r[i].vid;
End;
writeln('Итог',xz:9:0,xn:7:2,xv:8:2) {вывод итогов}
End;
if x<>'0' then begin{поиск и вывод одного имени}
for i:=1 to n do begin
read(ved,r[i]);
if x=r[i].im then begin{если найдено - вывод и конец}
writeln(r[i].im:4,r[i].zar:9:0, r[i].nalog:7:2, r[i].vid:8:2);
goto m{выход из цикла поиска}
End;
End;
writeln('Не найдено имя: ',x);
M:end;
Close(ved)
End.
Пример 9-3.Положим, в течение месяца работники бригады выполняли различные виды работ (пусть три), сведения о которых хранятся в трех файлах с именами Rab1, Rab2, Rab3. Кроме того, имеется справочный файл тарифов работников Tarif. Необходимо создать файл Ved ведомости на оплату, где будут собраны сведения о всех работниках и сделаны необходимые вычисления.
файл | Tarif | файл | Rab1 | файл | Rab2 | файл | Rab3 | ||||||
tb | im | tr | tb | ch | tb | ch | tb | ch | |||||
таб № | имя | тариф | таб № | часы | таб № | часы | таб № | часы | |||||
Иван | |||||||||||||
Петр | |||||||||||||
Лена | |||||||||||||
Вася | |||||||||||||
Олег | |||||||||||||
массив | MT | массив | MR | ||||||||||
tb | im | tr | tb | ch | |||||||||
файл | Ved | ||||||||||||
tb | im | ch | zr | nl | vd | ||||||||
таб № | имя | часы | з | арплата | налог | выдать | |||||||
Лена | 390,0 | 2610,0 | |||||||||||
Олег | 130,0 | 870,0 | |||||||||||
Вася | 227,5 | 1522,5 | |||||||||||
Иван | 390,0 | 2610,0 | |||||||||||
Петр | 78,0 | 522,0 | |||||||||||
всего | 1215,5 | 8134,5 | Рис. | 9.2 | |||||||||
Последовательность действий:
1. Предварительно создать на диске и заполнить файлы с именами Rab1, Rab2, Rab3 и Tarif.
2. Последовательно считать все три файла в массив Mr[1..15].
3. Отсортировать массив по табельному номеру (по полю mr.tb). Повторяющиеся номера объединить (часы суммируются) в одну строку.
4. Считать файл Tarifв массив Mt[1..6]. Исходя из индивидуальных тарифов, рассчитать зарплату, налог и сумму к выдаче каждого и записать в файл Ved.
5. Вывести из Ved полученные данные на экран вместе с общей суммой зарплат бригады.
Исходные данные и результаты показаны на рис 9.2. Над колонками приведены названия полей, принимающих соответствующие данные.
Программа Vedom реализует процесс обработки данных. Программу занесения данных в фалы Rab1, Rab2, Rab3, Tarifнапишите сами.
program VEDOM;{программа к примеру 9-3}
Uses crt;
type{создание типов записей}
rab=record tb,ch:integer end;{тип записи Работы}
tar=record tb,tr:integer; im:string[4] end; {тип записи Тарифы}
{тип записи Ведомость}
ved=record tb,ch,zr:integer; im:string; nl,vd:real end;
var{создание файлов, рабочих записей и переменных}
r1,r2,r3:file of rab;{файлы Работ}
{массив записей для приема данных из файлов Работ}
mr:array [1..15] of rab;
x: rab; {запись типа Rab, необходимая для сортировки}
t:file of tar;{файл тарифов}
{массив записей для приема данных из файла Тарифов}
mt:array [1..6] of tar;
v:file of ved;{файл Ведомости}
mv:ved; {запись Ведомости}
{переменные для накопления итоговых сумм в Ведомости}
sch,szr:integer; snl,zvd:real;
m,i,j,k:integer;
Begin
Clrscr;
{--------------------слияние Rab1-3 в массив записей MR---------------------------}
assign(r1,'rab1'); assign(r2,'rab2'); assign(r3,'rab3'); reset(r1); reset(r2); reset(r3);
k:=0;
while not eof(r1) do begin k:=k+1; read(r1,mr[k]) end;
while not eof(r2) do begin k:=k+1; read(r2,mr[k]) end;
while not eof(r3) do begin k:=k+1; read(r3,mr[k]) end;