Смекни!
smekni.com

Программирование в СИ (стр. 7 из 8)

В последней (m-1)-й строке прямоугольной динамической матрицы m ´ n могут содержаться элементы, не принадлежащие исходному одномерному массиву. Поэтому при переборе элементов массива необходима соответствующая проверка.

comp ** A = NULL;

A = (comp **) malloc( m * sizeof(comp *));

// проверка выделения памяти

for(int i=0; i < m; i++)

A[i] = (comp *) malloc(k * sizeof(comp));

// проверка выделения памяти

for( i =0; i < m; i++)

for( int j =0; j < n; j++)

if( (long) i*k+j < T) // работаем только с элементами

// исходного одномерного массива {

A[i][j].re = 0;

A[i][j].im = 0;

}

// работа программы

// освобождение памяти

for( i =0; i < m; i++)

free(A[i]);

free(A);

2.6. Вывод числовой информации

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

Например выведем вещественное число с двумя знаками после запятой.

charbuf[5];

floatx = 3.1415;

sprintf(buf, “%4.2”, x);

outtextxy(100, 100, buf);

Цифра 4 в форматной строке задает количество байтов в памяти, которые будет занимать выводимая форматированная информация без учета признака конца строки. Прием используется для предотвращения выхода за диапазон массива. Подобная ошибка возникла бы в случае
x = 13.1415.

2.7. Задержка экрана

Организация задержки экрана не зависит от выбора графического или текстового режима, и реализуется следующим образом

if (!getch())

getch();

Данный код корректно обрабатывает два возможных случая. Во-первых, при нажатии обычной клавиши. При этом с клавиатуры в буфер ввода помещается ненулевой ascii-код символа, соответствующего нажатой клавише. Тогда условие !getch() ложно и второй getch() не вызывается.

Во-вторых, при нажатии клавиши с расширенным кодом (например, функциональные клавиши, стрелки) с клавиатуры в буфер ввода поступают два числа: ноль и scan-код этой клавиши. Тогда условие !getch() истинно, вызывается второй getch(), который считывает scan-код и тем самым очищает буфер.

Другим способом задержки экрана является код

while(!getch())

;

Отметим, что стандартным способом задержки (в учебниках и примерах из справок по функциям) является вызов функции

getch();

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


2.8. Реакция программы на нажатие конкретной клавиши

В следующем фрагменте выходим из цикла по нажатию клавиши Escape

#define ESC 27

while(1){

if(kbhit()){

char c=getch();

if(c == 0)

{

getch();

continue;

}

else if( c == ESC)

break;

}

//работа цикла

}

2.9. Организация ввода числовой информации

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

Предлагается следующий алгоритм для ввода целого положительного числа. Данные считываются с клавиатуры посимвольно, сохраняются в памяти и затем распознаются с помощью функции sscanfформатированного ввода из строки. Строка выводится в графическом режиме посимвольно.

#define ENTER 13

main(){

//инициализация графического режима

char c, buf[2], *str=(char *)malloc(1);

int number;

str[0] = ’&bsol;0’;

buf[1] = ‘&bsol;0’;

while( (c = getch()) != ENTER){

if( c < ’0’ || c> ’9’)

continue;

buf[0] = c; // введенный символ оформляем в виде строки

outtext(buf); // и выводим на экран в графическом режиме

str = realloc(str, strlen(str) + 2);

str[strlen(str) + 1] = ‘&bsol;0’;

str[strlen(str)] = c; // запоминаемсимволвпамяти

}

sscanf(str, “%d”, &number);

}

2.10. Проверка выхода аргумента функции из ОДЗ

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

Например,

intflag=0; //глобальный флаг

// работаем с функцией y = x1/2

float f(float x){

if(x<0){

flag=1;

return 0;

}

else{

flag=0;

return sqrt(x);

}

}

void main(){

float x, y;

scanf(“%f”, &x);

y=f(x);

if(flag==1)

printf(“Выход из ОДЗ. ”);

else

printf(“Нет выхода из ОДЗ. Продолжаем вычисления”);

}

2.11. Графическая и математическая системы координат

Для рисования графика функции программисту удобнее использовать математическую систему координат (МСК), расположенную по центру экрана. Графические функции работают в графической системе координат (ГСК).


а б

Рис. 1. Системы координат: а – математическая; б – графическая

Инициализируем переменные.

intmaxx = getmaxx(),

maxy = getmaxy(),

px = 30, // количество пикселей в одной математической единице по оси Ох

py = px * ((float)maxx/maxy); // количество пикселей в одной математической единице по оси Оy.

Соответствие между двумя системами координат представлено
ниже

Соответствие между МСК и ГСК

МСК ГСК
(0, 0) ………………………………. (maxx / 2, maxy / 2)
(1, 0) ………………………………. (maxx / 2 + px, maxy / 2)
(0, 1) ………………………………. (maxx / 2, maxy / 2 – py)
(x, y) ….……………………………. (maxx / 2 + x px, maxy / 2 – y py)
(x, f(x)) ……………………………. (maxx / 2 + x px, maxy / 2 – f(x) py)

Реализуем масштабирование по оси координат Ох так, чтобы график функции y = f(x) на заданном отрезке [a, b] размещался по всей ширине экрана. Для этого найдем коэффициенты u и v линейного отображения g(x) = u x + v, при котором отрезок [a, b] переходит в отрезок [0, maxx]. Из системы линейных уравнений

u a + v = 0

u b + v = maxx

находимu = maxx / (b-a), v = -a maxx / (b-a). Тогда точке (x, f(x)) будет соответствовать пиксель

( (maxx / (b-a)) * x - a * maxx / (b-a) , maxy / 2 - f(x) * py)),

где px = maxx/(b-a). Затем график можно нарисовать с помощью цикла, в котором счетчик является вещественной математической переменной. Например:

for(float x = a; x <= b; x += (b-a) / maxx)

putpixel((maxx / (b-a)) * x - a * maxx / (b-a), maxy / 2- f(x) * py));

Данный цикл при больших a и b может оказаться бесконечным. Это возможно в случае, если шаг цикла (b-a) / maxx будет меньше расстояния между числом a и его ближайшим соседом справа для типа float.

2.12. Использование двух видеостраниц

Для рисования вращающейся звезды (см. задание 3.4) лучше использовать две видеостраницы.

int page=0;

for(double f = 0; f < 2 ×M_PI-M_PI / 100; f += M_PI / 50) {

otrisovka(X0, Y0, R1, r2, fi0 + f, COLOR); /* рисуем новую звезду на активной странице, которая по умолчанию имеет нулевой номер*/

setvisualpage(page); /* показываем изображение новой звезды*/

page=abs(page-1); /* меняем номер страницы с 0 на 1 или наоборот*/

setactivepage(page); /* меняем активную страницу*/

otrisovka(X0, Y0, R1, r2, fi0 + f-M_PI/ 50, getbkcolor()); /* стираем старую звезду на активной странице*/

}

2.13. Рисование изображений в bmp-формате

Для создания фона в задаче о снегопаде можно использовать 16-ти цветный bmp-файл, так как это устраняет проблему самостоятельного рисования фонового изображения средствами языка C++. Для загрузки изображения из файла надо выполнить действия:

1) с позиции 22 в файле прочитать высоту рисунка;

2) вычислить ширину записанного изображения

ширина = (размер_файла - 118) / высота;

3) загрузить сам рисунок, начиная с позиции 118, учитывая, что в одном байте содержится 2 пикселя и то, что изображение в файле записано построчно, причем первая строка записана в конец файла, а последняя – с позиции 118.

// карта замещения цветов для создания визуального эффекта

char map[] = {0,12,2,6,9,5,3,8,7,4,10,14,1,13,11,15};

int y0 = getmaxy();

// Открываем картинку

FILE *f = fopen(fon, "rb");

if(f==NULL)

return 2;

// читаем ширину картинки

fseek(f, 0, 2);

long l = ftell(f)-118;

fseek(f, 22, 0);

int w,h;

fread(&h, 2, 1, f);

w = int(l / h);

// читаем и рисуем картинку

fseek(f, 118, 0);

int x=0;

int y=0;

while(1) {

c = fgetc(f);

if(feof(f))

break;

ch = map[c/16];

cl = map[c%16];

putpixel(2*x+0, y0-y, ch);

putpixel(2*x+1, y0-y, cl);

if(++x==w) {

x=0;

y++;

}

}

fclose(f);

2.14. Работа с мышью

Вызовы BIOS используют программные прерывания. BIOS имеет несколько различных прерываний для разных целей. Для работы с мышью используют прерывание 0x33. Для доступа к этим прерываниям используется функция Си с прототипом в файле <dos.h>

int int86(int num, REGS *in, REGS *out);

где num – номерпрерывания. Объединение REGS имеетвид

union REGS{

struct WORDREGS x;

struct BYTEREGS y;

};

struct WORDREGS{

unsigned int ax, bx, cx, dx, si, di, cflags, flags;

};

struct BYTEREGS{

unsigned char al, ah, bl, bh, cl, ch, dl, dh;

};

//Определим глобальную переменную

REGSregs;

//показать курсор

void showcursor(void){

regs.x.ax = 0x01;

int86(0x33,&regs,&regs);

}

//спрятатькурсор

void hidecursor(void){

regs.x.ax = 0x02;

int86(0x33,&regs,&regs);

}

//получениестатусамыши

void get_mouse_status(int& button,int& x,int& y){

regs.x.ax = 0x03;

int86(0x33,&regs,&regs);

button = regs.h.bl;

x = regs.x.cx;

y = regs.x.dx;

}

//пример использования мыши

main(){

//инициализация графического режима

int button, x, y;

char str[20];

showcursor();

while(1){

get_mouse_status(button, x, y);

if(x == 0 || y == 0)

break;

sprintf(str, “%d %d”,x, y);

outtext(30, 30, str);

}

hidecursor();

}


3. ЗАДАНИЯ ДЛЯ ЛАБОРАТОРНОЙ РАБОТЫ

3.1. Звездное небо

На экране в непрерывном режиме рисуются звезды (пиксели) в случайном месте и случайным цветом. Распределение случайных величин равномерное. При наложении новой звезды на другую видимую звезду обе стираются. Рисование прекращается нажатием клавиши Escape. Затем происходит подсчет числа видимых звезд, и процент заполнения неба выводится по центру графического экрана с точностью до сотых долей процента. Использовать готический шрифт размером 1 см.

Рисование звезд и их подсчет реализовать в виде отдельных функций. Получить ответ для двух режимов VGAHI и VGALO.

3.2. Снегопад

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