Лекции Булатицкий Дмитрий Иванович (во многом по материалам Прасолова А. Н.)
![]()
|
Указатели и функцииФункции, как и другие объекты программы, располагаются в памяти ЭВМ. Любая область памяти имеет адрес, в том числе и та, в которой находятся функция. Имя функции без круглых скобок за ним представляет собой константный адрес этой области памяти. Таким образом, имея функции со следующими прототипами: double sin(double x); double cos(double x); double tan(double x); мы можем в программе использовать имена sin, cos и tan, которые будут обозначать адреса этих функций. Можно описать и указатель на функцию. Например, для функции с аргументом типа double, возвращающей значение типа double, описание такого указателя будет выглядеть следующим образом: double (*fn)(double x); Здесь, как и в случае указателя на массив, круглые скобки увеличивают приоритет операции *. Если бы они отсутствовали, то была бы описан не указатель на функцию, а функция, возвращающая значение указателя на double. После того, как описан указатель на функцию, становятся возможными следующие операции: fn = sin; /* Настройка указателя на функцию sin */ a = fn(x); /* Вызов функции sin через указатель */ fn = cos; /* Настройка указателя на функцию cos */ b = fn(x); /* Вызов функции cos через указатель */ Можно описать массив указателей на функцию и проинициализировать его: double (*fnArray[3])(double x) = { sin, cos, tan }; Теперь становится возможным следующий цикл: for(i=0; i<3; i++) printf( "F(x) = %lf\n", fnArray[i](x) ); Можно описать функцию возвращающую значение указателя на функцию: double (*fnFunc(int i)) (double x) { switch(i) { case 0 : return sin; case 1 : return cos; case 2 : return tan; } return NULL; } Описанная функция имеет параметр типа int и возвращает значение указателя на функцию с аргументом типа double, возвращающую значение типа double. После описания функции fnFunc становится возможным следующий цикл: for(i=0; i<3; i++) printf( "F(x) = %lf\n", fnFunc(i)(x) ); Оператор typedefОписания, подобные описаниям предыдущего раздела, достаточно сложны для понимания. Для упрощения описаний сложных типов в языке Си предусмотрен оператор typedef. Его использование иллюстрируется следующим синтаксисом: БНФ: typedef описание_одного_имени Под описанием_одного_имени подразумевается любое, сколь угодно сложное описание данного. Но в этом случае имя будет обозначать не имя данного, а имя нового типа, который соответствует типу данного и может быть использован в качестве имени типа в любых других определениях данных. Рассмотрим пример: typedef double DArray[100]; DArray A, B, C; Если бы в первом описании отсутствовало бы ключевое слово typedef, то имя DArray представляло бы имя массива из 100 элементов типа double, для которого бы выделялся соответствующий объем памяти. При наличии typedef компилятор будет воспринимать имя DArray как имя нового типа данных, а именно, типа массива из 100 элементов типа double. Очевидно, никакой памяти при этом не выделяется. Во втором описании используется имя нового типа DArray. Каждое из определяемых имен A, B и C будет считаться массивом из ста элементов типа double, и для каждого из них будет выделен соответствующий объем памяти. Описания указателей на функции из предыдущего раздела можно существенно упростить, используя оператор typedef: typedef double (*Fun)(double x); /*Тип указателя*/ Fun fnArray[3] = { sin, cos, tan }; /*Массив функций*/ Fun fnFunc(int i) /* Функция, возвращающая функцию */ { switch(i) { case 0 : return sin; case 1 : return cos; case 2 : return tan; } } Совершенно очевидно, что последние описания значительно понятнее. Простейшая графикаТекстовый и графический режим видеоадаптераКак это и ни странно звучит сегодня, но основной видеорежим у персональных компьютеров — это текстовый режим, в котором графические элементы создаются с использованием псевдографических символов. Лишь в дальнейшем, уже по командам операционной системы, видеоадаптер переключается в графический режим. Это хорошо заметно, когда после включения питания компьютер работает под управлением программ BIOS. А вот пользователи используют текстовый режим работы видеоподсистемы только в режиме MS-DOS или, например, в операционной системе Linux в режиме терминала. Появление двух различных принципов построения изображения на экране монитора возникло исторически. Текстовый режим достался персональному компьютеру IBM PC от вычислительных машин, где графический режим в то время являлся весьма уникальной особенностью, для поддержки которой требовалось необычайно много ресурсов. При этом, чтобы рисовать на экране или печатающем устройстве, использовались различные ухищрения, например, создавали изображение с помощью набора символов букв, цифр и знаков препинания. Кстати, тогда активно использовался термин "средства машинной графики". Для всемерного сокращения аппаратных и программных ресурсов в персональных компьютерах IBM PC был реализован великолепный способ "рисования", в котором использовались символы так называемой псевдографики. Для вывода символов букв и цифр, а также псевдографики используется очень простой принцип, который может быть реализован даже с помощью обычных стандартных логических микросхем. Вся площадь экрана разделяется на маленькие области — знакоместа. Например, площадь экрана в 720 точек по горизонтали и 350 по вертикали делится на прямоугольники 9x14 (используются также варианты 8x14, 9x16 и пр.), образуя 80 столбцов и 25 строк. В этом случае, скажем, буква "А" может быть нарисована так, как показано на рис. (конечно, варианты бывают разные). Используя такой принцип, для запоминания символа требуется всего одна ячейка памяти, а образ символа, который будет построен на экране монитора, хранится в "постоянной" памяти видеоадаптера. Следует заметить, что в персональных компьютерах IBM PC для каждой точки использовались два байта — в первом хранился код символа, а во втором — атрибуты символа (цвет, яркость, мигание), что приводило к необходимости выделения 4 Кбайт для каждого кадра. В персональных компьютерах IBM PC XT образы символов хранились в микросхеме ПЗУ, что приводило к проблемам, например русификации компьютера. То есть требовалось снять микросхему ПЗУ с платы видеоадаптера и установить новую с другой прошивкой (в не таких уж старых принтерах точно так же приходится поступать, когда надо русифицировать принтер для режима MS-DOS). Начиная с IBM PC AT, таблица знакогенератора загружается центральным процессором в ОЗУ видеоадаптера, причем пользователь может указать, какая кодовая таблица ему нужна. После удешевления микросхем памяти и повышения производительности процессоров текстовый режим перестал пользоваться популярностью у пользователей, которые теперь предпочитают работать в графической оболочке, например операционной системы Windows. Но в таком случае компьютеру приходится помнить о каждой точке на экране, т. е. один байт управляет не группой точек, как в текстовом режиме, а всего лишь одной. В дальнейшем для хранения информации о цвете и яркости точки стали отводить 2 байта, а потом и более. Так как пользователи после непродолжительного восторга от новейшего компьютера очень скоро снова становятся недовольными возможностями вывода графической информации на монитор, то разработчики компьютерного железа систематически вводят все новые и новые стандарты построения изображения. Вначале человеку приходилось работать за черно-белым монитором, потом появились цветные с довольно скромными характеристиками. Далее последовательно увеличивалось число выводимых на экран точек и количество цветов, которые можно было отобразить. Соответственно, каждый стандарт характеризовался разрешением и глубиной цвета (одновременно менялись значения кадровой и строчной развертки монитора, а также способ синхронизации изображения). |