Пример организации светового меню Меню современных программ, как правило, представляет собой набор строк по которому перемещается светлый прямоугольник - световое окно. Для написания программ с подобным меню необходимо уметь выводить в нужное место экрана информацию разными цветами. Экран IBM PC имеет 25 строк и 80 позиций. Нумерация строк и позиций начинается с 1. Первая строка находится вверху, первая позиция слева. Все необходимые функции работы с экраном IBM PC имеются в библиотеке компилятора, их прототипы находятся в файле conio.h. Рассмотрим некоторые из этих функций: void clrscr( void ); - осуществляет стирание экрана; void gotoxy( int x, int y ); - перемещает курсор в позицию x строки y; void cprintf( char *format, ... ); - выполняет то же самое, что и printf, но выводит информацию, используя установленный цвет фона и цвет символа; void textcolor( int color ); - установка цвета символа с кодом color; void textbackground( int color ); - установка цвета фона с кодом color; Последние функции не изменяют цвет уже выведенных символов. Их влияние распространяется на все последующие выводы с помощью функции cprintf. При установке цвета допускается использовать шестнадцать цветов символа с кодами 0...15, и восемь цветов фона с кодами 0...7. Для удобства работы с цветами в conio.h определены мнемонические имена для цветов: enum COLORS { /* цвета для символов и фона */ BLACK /* черный */, BLUE /* синий */, GREEN /* зеленый */, CYAN /* салатовый */, RED /* красный */, MAGENTA /* малиновый */, BROWN /* коричневый */, LIGHTGRAY /* светло-серый */, /* цвета только для символов */ DARKGRAY /*темно-серый */, LIGHTBLUE /* ярко-синий */, LIGHTGREEN /*ярко-зеленый*/, LIGHTCYAN /*ярко-салатовый*/, LIGHTRED /*ярко-красный*/, LIGHTMAGENTA /*ярко-малиновый*/, YELLOW /* желтый */, WHITE /* белый */ }; Приведенная ниже программа вычисляет функции sin(x), cos(x) и tan(x) в зависимости от выбора пользователя. Выбор осуществляется с помощью светового меню. Движение светового окна организуется путем перерисовки пункта меню другим цветом фона. Основной цикл этой программы управляет изменением переменной choice, в которой хранится текущий выбор пользователя. #include <stdio.h> #include <math.h> #include <conio.h> #include "keyboard.h" #define N 4 #define ROW 10 #define COL 35 #define TEXT_C WHITE #define TEXT_BG BLACK #define CHOICE_BG LIGHTGRAY void out_str( int num, int bg_color ); /* Организация светового меню */ void main ( void ) { int loop; /* Флаг конца работы */ int choice; /* Текущий выбор пункта меню */ int old_choice; /* Старый выбор пункта меню */ double fun, x; /* Значения функции и аргумента */ int i; textbackground( TEXT_BG ); textcolor( TEXT_C ); clrscr(); gotoxy( COL, ROW-1 ); cprintf( "Аргумент x=" ); scanf( "%lf", &x ); /* Начальный вывод всех пунктов меню */ i=1; while( i <= N ) { out_str( i, TEXT_BG ); i++; } loop = 1; choice = 1; old_choice = 2; while ( loop ) { out_str( old_choice, TEXT_BG ); out_str( choice, CHOICE_BG ); old_choice = choice; switch( GetCh() ) { case kbUp : if ( choice>1 ) choice--; else choice = N; break; case kbDown : if ( choice<N ) choice++; else choice = 1; break; case kbEnter : switch ( choice ) { case 1 : fun=sin(x); break; case 2 : fun=cos(x); break; case 3 : fun=tan(x); break; case 4 : loop=0; continue; } textbackground( TEXT_BG ); gotoxy( COL-5, ROW+6 ); cprintf( "Значение функции %lf\n", fun ); } } } /* Функция вывода строки меню с указанным цветом фона */ void out_str( int num, int bg_color ) { textbackground( bg_color ); gotoxy( COL, ROW+num ); switch( num ) { case 1: cprintf( "1. sin(x) " ); break; case 2: cprintf( "2. cos(x) " ); break; case 3: cprintf( "3. tan(x) " ); break; case 4: cprintf( "4. Конец работы" ); break; } } На аналогичных принципах могут быть построены более сложные диалоговые программы, имеющие разнообразные вертикальные, горизонтальные, вложенные и выпадающие меню, управляемые световым окном. Массивы. Адресная арифметика языка Си Массив - это совокупность элементов данных одного и того же типа, объединенных общим именем и расположенных в непрерывной области памяти ЭВМ так, что к каждому элементу массива можно получить доступ, зная его порядковый номер или индекс. Описание массива Описание массива производится с помощью обычного оператора описания, при этом за именем массива в квадратных скобках должна быть записана целая положительная константа или константное выражение, равное размеру этого массива, то есть максимально возможному числу элементов. Например: int a[100], ab[2*40]; double c[200], speed[100]; char name[20]; Имя массива без квадратных скобок за ним имеет значение, равное адресу первого элемента этого массива. Имя массива с квадратными скобками, в которых записано индексное выражение целого типа, обозначает значение соответствующего элемента массива. В языке Си нумерация элементов массива начинается с нуля, то есть для массива d из пяти элементов допустимы следующие обозначения: d[0], d[1], d[2], d[3], d[4]. Индексированные переменные могут использоваться в любых выражениях в тех местах, где допускается применение переменных соответствующих типов. При работе с индексированными переменными необходимо внимательно следить за тем, чтобы индексы не вышли из допустимого диапазона, определяемого описаниями массивов. Дело в том, что компилятор не проверяет факт выхода индексов за границы массива, а при ошибочном занесении данных за пределы массива может запортиться нужная информация и, скорее всего, компьютер зависнет. Ввод-вывод массива Язык Си не имеет встроенных средств для ввода-вывода массива целиком, поэтому массив вводят и выводят поэлементно с помощью циклов, как, например, в следующей программе: #include <stdio.h> void main(void) { double a[100]; int n, i; printf("Введите количество чисел n = "); scanf("%d", &n); if( n>(sizeof a)/sizeof(double) ) { printf("Слишком много элементов\n"); return; } for(i=0; i<n; i++) { printf("a[%d] = ", i); scanf("%lf", &a[i]); } /* Операторы, обрабатывающие массив */ } Во многих случаях удобно возложить на программу подсчет числа элементов, вводимого массива, при этом ввод завершается при появлении во входном потоке признака конца данных. Таким признаком в следующей программе служит число большее 1.0e300 #include <stdio.h> void main(void) { double a[100], temp; int n, end; for(end=n=0; n<(sizeof a)/sizeof(double); n++) { printf("a[%d] = ", n); scanf("%lf", &temp); if( temp>=1.0e300 ) { end=1; break; } a[n] = temp; } if( end ) { /* Операторы, обрабатывающие массив */ } else printf("Переполнение массива\n"); } Вывод массива, содержащего большое количество элементов желательно производить в несколько строк с остановом после заполнения экрана. Следующий фрагмент программы выводит массив строками по 5 элементов. После вывода 120 элементов программа останавливается для просмотра выдачи. Очередные 120 элементов выводятся после нажатия на любую клавишу. for (i=0; i<n; i++) { printf("%10.3lf ", a[i]); if( (i+6) % 5 == 0 ) printf("\n"); if( (i+121) % 120 == 0 ) { getch(); clrscr(); } } Здесь стандартная функция clrscr() очищает экран. Инициализация массива Инициализация - присвоение значений вместе с описанием данных. Ранее была рассмотрена инициализация простых переменных, например: int a = 5; Для инициализации массива за его именем располагают знак присваивания и список инициализации, который представляет собой заключенные в фигурные скобки и разделенные запятыми инициализирующие значения. Ниже приведен пример инициализации массива: int a[4] = { 15, 21, 1, 304 }; индексы элементов -> 0 1 2 3 Констант в списке инициализации должно быть не больше, чем объявленный размер массива. Если их меньше, то элементы для которых нет констант обнуляются. Для инициализируемого массива допускается вообще не указывать размер. В этом случае размер массива определяется по количеству констант, например по описанию int c[] = { 1, 15, 18, 11, 20 }; транслятор выделит 10 байт для хранения массива из 5 двухбайтовых целых чисел. Частный случай инициализации массива - инициализация строк. Массив символов может быть проинициализирован стандартным образом: char s[] = { 'A', 'B', 'C', 'D' }; Строка символов дополнительно должна завершаться нуль-символом. char s[] = { 'A', 'B', 'C', 'D', '\0' }; В связи с тем, что инициализацию строк приходится организовывать довольно часто, язык Си предусматривает для этого упрощенную форму записи: char s[] = "ABCD"; этом случае нуль-символ автоматически дописывается в конец строки. Два последних примера инициализации строки совершенно эквивалентны. |