Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Тема_2_6_FoxЦиклы.doc
Скачиваний:
3
Добавлен:
11.08.2019
Размер:
61.44 Кб
Скачать

Тема 2.6. Создание программных файлов. Модульность программ.

Тема 2.6.2: команды управления

  1. Команда if

  2. Команда case

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

Команда IF. В зависимости от условия команда выполняет те или иные <команды>, находящиеся внутри конструкции IF...ENDIF.

IF <условие> <команды> [ELSE <команды>]

ENDIF

Если условие истинно, выполняются все <команды>, следующие от IF до ELSE, если ложно, то <команды> от ELSE до ENDIF. Если необязательная фраза ELSE отсутствует и условие ложно, все внутренние <команды> пропускаются и выполняется команда, следующая за ENDIF. Допустимо вложение друг в друга конструкций типа IF ... ENDIF и других структурных команд.

Пример. Вывести большее из двух чисел А и В, а если числа равны, вывести сообщение "ЧИСЛА РАВНЫ".

IF а=Ь

?'ЧИСЛА РАВНЫ' ELSE

IF a>b

? а ELSE

? b ENDIF

ENDIF

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

Команда DO CASE. Конструкция DO CASE ... ENDCASE решает задачи, аналогичные команде IF, но в ней может быть указано сразу несколько условий, которые последовательно проверяются во всех фразах CASE.

DO CASE

CASE <условие 1 >

<команды>

CASE <условие 2>

<команды>

[OTHERWISE

<команды>]

ENDCASE

Если встретилось истинное <условие>, выполняются нижеследующие <команды> до следующей фразы CASE, или OTHERWISE, или ENDCASE, и конструкция завершается. Если ни одно из CASE-условий не истинно, выполняются <команды>, стоящие за фразой OTHERWISE до ENDCASE, если фраза OTHERWISE отсутствует, не выполняется ни одна команда. Пример для условий предыдущей задачи показан ниже.

DO CASE

CASE а=b ,

?'ЧИСЛА РАВНЫ' CASE а>Ь

?' а=',а CASE a<b

?'b=',b

ENDCASE

Команда очень удобна для обработки выбора из меню в программах. Разрешается вложение команд DO CASE, IF.

В случае, если найдено истинное CASE-условие, остальные условия не проверяются и выполняется команда, стоящая за ENDCASE. Кроме перечисленных команд IF и DO CASE, в СУБД FoxPro имеется очень полезная функция анализа условия – IIF().

Тема 2.6.3: команды организации циклов.

  1. Цикл с условием

  2. Цикл с параметром

  3. Цикл сканирования бд

В FoxPro имеются развитые средства организации программных циклов, которые в зависимости от постановки задачи могут быть классифицированы на циклы с условием (итерационные циклы) и циклы с параметром (арифметические циклы).

Цикл с условием. Реализация так называемых итерационных циклов, т.е. циклов с заранее известным условием их окончания и неизвестным числом повторов, выполняется следующей конструкцией:

DO WHILE <условие>

<команды>

ENDDO

Команды, заключенные между DO WHILE и ENDDO, будут выполняться до тех пор, пока <условие> истинно. Если оно ложно или становится ложным, осуществляется переход к команде, следующей за ENDDO.

Пример. Ввести с клавиатуры и суммировать числа Х в переменную S до тех пор, пока сумма не превысит 1000.

s=0

DO WHILE s<=1000

INPUT 'ВВЕДИТЕ X' TO x

s=s+x

ENDDO

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

EXIT которая передаст управление команде, следующей за ENDDO.

Следующая команда осуществляет передачу управления в цикле, но в противоположную сторону - в его начало, на саму команду цикла:

LOOP

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

Рассмотренные команды действуют не только в структуре DO WHILE, но и во всех других командах организации циклов (FOR и SCAN).

Пример. Допустим, что в условиях предыдущего примера требуется суммировать только положительные числа X, а в случае, если встретится Х=0, вообще прекратить суммирование.

а=0

DO WHILE s<1000

INPUT 'ВВЕДИТЕ X' ТО х

IF х<0 LOOP

ENDIF

IF x=0 EXIT

ENDIF

s=s+x

ENDDO

Отсутствие меток вынуждает программиста обращаться к командам EXIT и LOOP, которые, однако, имеют смысл только в циклах. Поэтому иногда приходится использовать команды цикла там, где никакого цикла нет, применяя их как операторные скобки. В качестве условия ставится какое-либо всегда истинное условие, обычно это просто логическая "Истина" (.Т.):

DO WHILE .t. <команды> ENDDO.

Цикл с параметром. Арифметический цикл предполагает наличие переменной, ограничивающей число циклов.

FOR <переменная>=<ВырN1> ТО <BыpN2> [STEP <BыpN3>]

<команды>

ENDFOR

Допускается также использование вместо команды ENDFOR команды NEXT (как в Бейсике).

Здесь <переменная> используется в качестве управляющего параметра цикла, для которого <BыpNl> является начальным значением, <BыpN2> - конечным, a <BыpN3> - шагом изменения <переменной>. Если последний параметр отсутствует, шаг равен 1.

Таким образом, цикл будет выполняться столько раз, сколько нужно, чтобы <переменная> от значения, равного <BыpNl>, достигла <BыpN2> с шагом <BыpN3>. <Переменная> в каждом цикле сначала получает новое значение и затем сравнивается с <BыpN2>. Если она меньше или равна <BыpN2>, продолжается выполнение цикла, если больше, выполнение цикла заканчивается и программа продолжается с команды, следующей за ENDFOR. Если

<BыpN3> отрицательно, переменная в каждом цикле будет уменьшаться. Тогда <вырN1> должно быть больше <BыpN2>.

Хотя все параметры команды FOR допускается менять внутри цикла, это никак не влияет на число циклов или значение <переменной>. Исключение составляет сама <переменная>, изменение которой влечет изменение числа циклов. В цикл FOR могут включаться команды EXIT и LOOP. Наиболее частое применение команды FOR - организация циклов с заранее известным их числом. Тогда <переменная> имеет смысл счетчика циклов.

Примеры. Текущие значения переменной I показаны после знаков &&.

FOR i=2 TO 5 FOR i=12 TO 3 STEP -2

? i &6 2,3,4,5 ? i && 12,10,8,6,4 END FOR END FOR ? i && 6 ? i && 2

Как видим при завершении цикла переменная цикла получает значение неравное предельно установленной величине. Этим фактором следует воспользоваться для выяснения причины завершения цикла, который может быть осуществлен как естественным образом (после выполнения всех предписанных циклов), так и при помощи команды EXIT по некоторому внутреннему <условию>.

Положим организован следующий цикл:

FOR I=K TO M

<команды>

IF <условие> EXIT

END IF

<команды> END FOR

Тогда если 1<=М, цикл был завершен принудительно, иначе - естественно:

IF K=M

<обнаружен выход по ЕХ1Т> ELSE

<обнаружен естественный выход> ENDIF

Сказанное справедливо для циклов с возрастанием переменной цикла.

Для отрицательного шага рассуждения в точности обратные (IF I>=M).

Цикл сканирования базы данных. Следующая команда применяется для перемещения в базе данных и выполнения <команд> для каждой встреченной записи, которая отвечает условиям.

SCAN [<границы>] [FOR <условие>] [WHILE <условие>]

<команды>

ENDSCAN

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

SCAN-цикл может быть завершен как по достижении <границ> его действия, так и при встрече конца базы данных. Выяснить это обстоятельство можно с помощью функции EOF(). Если EOF()=.t., цикл завершен раньше времени. Исключение составляет цикл с FOR-условием - такой цикл всегда продолжается до достижения конца файла.

• Здесь уместно обсудить вопрос о технике перемещения в базе данных "по условию". Ниже приводятся фрагменты программ поиска в базе KADR.DBF всех записей с фамилиями, начинающимися с буквы "П", как с использованием цикла DO WHILE, так и SCAN-цикла. Рассматривается как последовательный поиск, так и ускоренный с применением индексного файла KADRFAM.IDX, созданного по полю FAM.

1. USE kadr

2. USE kadr [INDEX kadrfam] LOCATE FOR fani='n' SCAM FOR fairF='n' DO WHILE !EOF() <обработка записи>

ENDSCAN

CONTINUE ENDDO

3. USE kadr INDEX kadrfam

4. USE kadr INDEX kadrfam SEEK 'П' SEEK 'П' DO WHILE fanr='n' SCAN WHILE fam='n'

<обработка ааписи> <обработка эаписи>

SKIP

ENDSCAN

ENDDO

В примере 2 подключение индекса (опция INDEX kadrfam) обеспечивает сканирование базы с оптимизацией по технологии Rushmore. В этом случае пример идентичен примеру 4. Однако для

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

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

Такая ситуация может возникнуть, например, при необходимости сканировать базу в обратном направлении - снизу-вверх:

DO WHILE !BOF()

<обрабоччса ааписи>

SKIP -1 ENDDO

Следует заметить, что выполнение каждой команды ENDSCAN перемещает указатель записей. Это значит, что завершение SCAN-цикла с WHILE-условием переносит нас за пределы действия этого условия.

Пусть нам нужно найти и вывести суммарную зарплату S для каждого подразделения базы KADR.DBF (KADRPODR.IDX - индексный файл по полю PODR). Использование двух вложенных SCAN-циклов (ниже слева) повлечет ошибку - пропуск одной записи для каждого нового подразделения. Ниже справа приведено правильное решение.

USE kadr INDEX kadrpodr USE kadr INDEX kadrpodr SCAN DO WHILE !EOF() p=podr p=podr

8=0 S=0

SCAN WHILE podr=p SCAN WHILE podr=p

s=3+szar s=s+szar ENDSCAN ENDSCAN ?podr,s ?podr,s ENDSCAN ENDDO

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

Для иллюстрации техники группировки данных нам понадобится другая база данных. Положим она содержит сведения о работниках предприятия (RAB.DBF) с указанием их принадлежности подразделению (поле PODR), бригаде (BRIG) и звену (ZVENO), а также фамилию (FAM) и другие личные данные, которые сейчас не существенны. База имеет следующую структуру:

Field # Field Name Type Width

1 PODR Character 10

2 BRIG Character 2

3 ZVENO Character 2

4 FAM Character 26

5 ...

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

С тем, чтобы решение задачи было возможно, база проиндексирована по перечисленным полям командой

INDEX ON podr+brig+zveno TO rab

Текст программы приведен ниже.

*-1ТОБ.РКС-----------------------итоговая сводка работников

USE rab INDEX rab

CLEAR

? 'Список работников с разбивкой по местам работы'

•••а=0 66 общее число работников предприятия DO WHILE 'EOF() 66 внешний цикл

ass=G 66 число работников подразделения p=podr 66 название подразделения ? 'ПОДРАЗДЕЛЕНИЕ',?

DO WHILE p=podr 66 цикл по подразделению ss=0 66 число работников бригады b=brig 66 номер бригады ?' БРИГАДА НОМЕР',Ь DO WHILE p=podr AND b=brig 66 цикл по бригаде

8=0 66 число работников звена z=zveno 66 номер звена ? ' ЗВЕНО НОМЕР' , z 66 цикл по звену SCAN WHILE p=podr AND b=brig AND z=zveno

?? fam AT(10) 66 фамилии работников 8=8+1 66 подсчет работников ENDSCAN

? ' ',LTRIM(STR(s)),'чел.' 66 работников в звене эа=зэ+з ENDDO

? ' В бригаде',b,LTRIM(STR(8s) ),'чел. ' 66' в бригаде sss=sss+ss

ENDDO ? ' В подразделении',p,LTRIM(STR(sss)),'чел.' && подразд.

SSSS=3SSS+SSS

ENDDO

? 'ВСЕГО',LTRIM(STR(aass)),'человек' && на предприятии

RETURN &&—--——————--——------———-———----—----———

Видим, что для наших целей понадобилось организовать четыре цикла, из которых только самый внутренний SCAN-цикл осуществляет перемещение указателя записей. Остальные WHILE-ЦИКЛЫ контролируют заданные условия, инициализируют, формируют и выводят значения сумм.

5