Приложения Программирование к конспекту лекций по дисциплине

advertisement
Приложения
к конспекту лекций по дисциплине
Программирование
Оглавление
Приложения ...................................................................................................................................1
к конспекту лекций по дисциплине .............................................................................................1
Программирование ........................................................................................................................1
Оглавление .....................................................................................................................................2
Приложение 1. Некоторые полезные примеры и иллюстрации к разделам конспекта ..........3
Примеры к разделу 5 .................................................................................................................3
Вычисление факториала числа ............................................................................................3
Быстрое возведение чисел в целую степень .......................................................................4
Нахождение наибольшего общего делителя (алгоритм Евклида) ...................................5
Примеры к разделу 7 .................................................................................................................6
Библиотека функций случайных чисел ................................................................................6
Библиотека функций по работе с массивами общего назначения ...................................7
Библиотека функций сортировки массивов .....................................................................12
Библиотека функций поиска в массивах ..........................................................................14
Приложение 2. Функции стандартного ввода/вывода в стиле C (printf, scanf) ....................17
Введение ...................................................................................................................................17
Функция стандартного вывода printf() ..................................................................................17
Примеры программ..............................................................................................................19
Функция стандартного ввода scanf() .....................................................................................22
Примеры программ..............................................................................................................25
Приложение 3. Библиотека консольного ввода-вывода ..........................................................28
Приложение 4. Библиотека управления консолью (MyCrt.h) .................................................30
Приложение 5. Библиотека Menu.h и пример ее использования ............................................36
Библиотека Menu.h без мыши ................................................................................................36
Библиотека Menu.h с мышью .................................................................................................37
Пример использования библиотеки Menu.h ........................................................................39
Приложение 1. Некоторые полезные примеры и
иллюстрации к разделам конспекта
Все программы, приведенные в этом разделе, реализованы в среде MS Visual C++
2010.
Примеры к разделу 5
Вычисление факториала числа
// Различные реализации функций для вычисления факториала числа
#include
#include
#include
#include
"stdafx.h"
<iostream>
<iomanip> // для манипулятора setw()
<limits.h> // для ULONG_MAX - максимальное значение типа unsigned long
using namespace std;
unsigned Factorial_Err(unsigned n)
// При n > 12 значение n! превышает максимальное значение ULONG_MAX типа unsigned
// и функция возвращает неправильные значения
{
unsigned i = 0; // Текущее значение i
unsigned F = 1; // Текущее значение i!
while (i < n)
{
++ i;
// i = i + 1
F *= i; // F = F * i
- Текущее значение i!
}
return F;
// Возвращаем значение n!
}
unsigned Factorial(unsigned n)
// При переполнении возвращает 0 с сообщением об ошибке
// Реализация с помощью цикла while
{
unsigned i = 0; // Текущее значение i
unsigned F = 1; // Текущее значение i!
while (i < n)
{
++ i;
// i = i + 1
if (ULONG_MAX / i < F)
{
F = 0;
cout << "Ошибка. При вычислении n! максимальное "
"значение n не может превышать " << --i << endl;
break;
}
F *= i; // F = F * i
- Текущее значение i!
}
return F;
// Возвращаем значение n!
}
unsigned Factorial_1(unsigned n)
// При переполнении возвращает 0 с сообщением об ошибке
// Реализация с помощью цикла for
{
unsigned F = 1; // Значение 0!
for (unsigned i = 1; i < n; ++i, F *= i)
if (ULONG_MAX / i < F)
{
F = 0;
cout << "Ошибка. При вычислении n! максимальное "
"значение n не может превышать " << --i << endl;
break;
}
return F;
// Возвращаем значение n!
}
unsigned Factorial_2(unsigned n)
// При переполнении возвращает 0 без сообщения об ошибке
// Реализация с помощью цикла for
{
unsigned F = 1; // Значение 0!
for (unsigned i = 1; (i < n) && F; ++i, F = (ULONG_MAX / i < F) ? 0 : F * i);
return F;
// Возвращаем значение n!
}
int main()
// Для проверки работы одного из вариантов необходимо
// снять комментарии с соответствующей строки цикла for
// и закомментировать остальные
{
for (int i = 0; i <= 13; ++ i)
{
cout << setw(2) << right << i << "! = " <<
//
cout << setw(2) << right << i << "! = " <<
//
cout << setw(2) << right << i << "! = " <<
//
cout << setw(2) << right << i << "! = " <<
}
system ("Pause");
return 0;
}
Быстрое возведение чисел в целую степень
//
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
double IntPow(double b, int k, int &Count)
{
// Инвариант: (b ^ k) * p = a ^ n
// Цикл заканчивается при k = 0, тогда p = a ^ n
double p = 1;
Count = 0;
while (k != 0)
{
if (k & 1) // k не четно
{
-- k;
// k = k - 1
p *= b; // p = p * b
}
else
{
k /= 2; // k = k / 2
b *= b; // b = b * b
}
Factorial_Err(i) << endl;
Factorial(i) << endl;
Factorial_1(i) << endl;
Factorial_2(i) << endl;
++ Count;
}
return p;
}
double IntPow1(double a, int n, int &Count)
{
double p = 1;
double b = a;
for (int i = n, Count = 0; i; (i % 2) ? (p *= b, --i) : (b *= b, i /= 2),
++ Count);
return p;
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(0, "");
cout << "
Алгоритм быстрого возведения числа в целую степень.\n";
cout << "
---------------------------------------------------\n";
for (char b = '1'; b != 27; cout << "\n\t\t\tПродолжим? (нет - Esc) ",
b = _getch(), cout << endl)
{
double a;
int n, N;
cout << "\nОснование степени: ";
cin >> a;
cout << "Целая степень: ";
cin >> n;
cout << '\n' << a << " в степени " << n << " равно " << fixed
<< IntPow(a, n, N) << ".\n";
cout << "Количество шагов: " << N << endl;
cout << '\n' << a << " в степени " << n << " равно " << fixed
<< IntPow1(a, n, N) << ".\n";
cout << "Количество шагов: " << N << endl;
}
return 0;
}
Нахождение наибольшего общего делителя (алгоритм Евклида)
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
int NOD_1(int n, int m, int &Count)
// Известно, что: НОД(n, m) = НОД(n - m, m) при n > m и
// НОД(n, m) = НОД(n, m - n) при n < m.
{
int r, a = n, b = m;
Count = 0;
// Инвариант: НОД(a, b) = НОД(n, m)
// Цикл заканчивается при a = b, тогда НОД(n, m) = НОД(a, a) = a
while (a != b)
{
if (a > b)
a = a - b;
else
b = b - a;
++ Count;
}
return a;
}
int NOD_2(int n, int m, int &Count)
// Известно, что: НОД(n, m) = НОД(m, r), где r - остаток от деления n на m.
{
int r, a = n, b = m;
Count = 0;
// Инвариант: НОД(a, b) = НОД(n, m)
// Цикл заканчивается при b = 0, тогда НОД(n, m) = НОД(a, 0) = a
while (b)
{
r = a % b;
a = b;
b = r;
++ Count;
}
return a;
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(0, "");
cout << "
Алгоритм Евклида для нахождения наибольшего общего делителя.\n";
cout << "
------------------------------------------------------------\n";
for (char b = '1'; b != 27; cout << "\n\t\t\tПродолжим? (нет - Esc) ",
b = _getch(), cout << endl)
{
int Count;
int n, m;
cout << "\n Введите два целых числа больших 0: ";
cin >> n >> m;
cout << "\n Значение НОД чисел " << n << " и " << m << " равно "
<< NOD_1 (n, m, Count) << endl;
cout << "Число итераций: " << Count << endl;
cout << "\n Значение НОД чисел " << n << " и " << m << " равно "
<< NOD_2 (n, m, Count) << endl;
cout << "Число итераций: " << Count << endl;
}
return 0;
}
Примеры к разделу 7
Библиотека функций случайных чисел
/*
Датчик случайных чисел
Сохраните этот текст в файле с именем my_rand.h. Поместите
этот файл в каталог проекта и в тексте программы используйте директиву
#include "my_rand.h"
*/
#pragma once
#include <iostream>
#include <time.h>
using namespace std;
//
// Прототипы функций
//
void RandInit();
// Инициализация датчика случайных чисел с помощью системного времени
// Необходимо однократно вызвать при запуске программы
int MyRand(int d);
// Возвращает случайное целое в диапазоне от 0 до d
int MyRand(int ng, int vg);
// Возвращает случайное целое в диапазоне от ng до vg
//
// Реализация
//
void RandInit()
{
srand(_time32(NULL));
}
int MyRand(int d)
{
return rand() % (d + 1);
}
int MyRand(int ng, int vg)
{
return rand() % (vg - ng + 1) + ng;
}
Библиотека функций по работе с массивами общего назначения
/*
Смешанные функции по работе с массивами
Сохраните этот текст в файле с именем arr_common.h. Поместите
этот файл в каталог проекта и в тексте программы используйте директиву
#include " arr_common.h"
*/
#pragma once
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include "my_rand.h"
using namespace std;
//
// Прототипы функций
//
void RandMakeArr(double A[], int n, int d);
// Для массивов с эелементами типа double
// Заполняет массив А из n элементов случайными значениями в диапазоне от 0 до d
void RandMakeArr(double A[], int n, int ng, int vg);
// Для массивов с эелементами типа double
// Заполняет массив А из n элементов случайными значениями в диапазоне от ng до vg
void RandMakeArr(int A[], int n, int d);
// Для массивов с эелементами типа double
// Заполняет массив А из n элементов случайными значениями в диапазоне от 0 до d
void RandMakeArr(int A[], int n, int ng, int vg);
// Для массивов с эелементами типа double
// Заполняет массив А из n элементов случайными значениями в диапазоне от ng до vg
void ArrOut(double A[], int n);
// Вывод на экран массива А из n элементов типа double
void ArrOut(int A[], int n);
// Вывод на экран массива А из n элементов типа int
void Swap(double &a, double &b);
// Обмен значений переменных a и b
void Swap(int &a, int &b);
// Обмен значений переменных a и b
void Swap(int a[], int b[], int n);
// Обмен значений массивов a и b из n элементов типа int
void Swap(double a[], double b[], int n);
// Обмен значений массивов a и b из n элементов типа double
void ArrInit(int A[], int n, int Val);
// Заполнение массива А из n элементов типа int значениями Val
void ArrInit(double A[], int n, double Val);
// Заполнение массива А из n элементов типа double значениями Val
void ArrCopy(int Src[], int Dst[], int n);
// Копирование значений массива Src и Dst из n элементов типа int
void ArrCopy(double Src[], double Dst[], int n);
// Копирование значений массива Src и Dst из n элементов типа double
void MinMax(int A[], int n, int &iMax, int &iMin);
// Поиск минимального и максимального значений в массиве А из n элементов.
// Возвращает индексы первого минимального iMin и первого максимального iMax элементов
void MinMax(int A[], int n, int &iMax, int &iMin, int &cMax, int &cMin);
// Поиск минимального и максимального значений в массиве А из n элементов.
// Возвращает индексы первого минимального iMin и первого максимального iMax элементов и
// количества максимальных cMax и минимальных cMin элементов в массиве
void ArrDelItem(int A[], int &n, int di);
// Удаление элемента с индексом di из массива А с n элементами,
// что эквивалентно сдвигу элементов массива на 1 элемент в сторону меньших значений
индексов элементов.
// Возвращает измененный массив А и его количество элементов n, уменьшенное на 1.
// Контроль корректности входных данных не осуществляется.
void ArrInsItem(int A[], int &n, int ii, int Val);
// Вставка элемента со значением Val на позицию с индексом ii в массив А с n элементами,
// что эквивалентно сдвигу элементов массива на 1 элемент в сторону больших значений
индексов элементов и
// записи в элемент с идексом ii значения Val.
// Возвращает измененный массив А и его количество элементов n, увеличенное на 1.
// Контроль корректности входных данных не осуществляется.
void ArrConcat(int A1[], int n1, int A2[], int n2, int R[], int &n);
// Слияние двух отсортированных по возрастанию массивов А1 и А2 с количеством элементов
n1 и n2 соответственно
// в массив R. Возвращает массив R (также отсортированный по возрастанию) и его
количество элементов n
//
// Реализация
//
void RandMakeArr(double A[], int n, int d)
// Заполняет массив А из n элементов случайными значениями в диапазоне от 0 до d
{
for (int i = 0; i < n; ++i)
A[i] = MyRand(d);
}
void RandMakeArr(double A[], int n, int ng, int vg)
// Заполняет массив А из n элементов случайными значениями в диапазоне от ng до vg
{
for (int i = 0; i < n; ++i)
A[i] = MyRand(ng, vg);
}
void RandMakeArr(int A[], int n, int d)
// Заполняет массив А из n элементов случайными значениями в диапазоне от 0 до d
{
for (int i = 0; i < n; ++i)
A[i] = MyRand(d);
}
void RandMakeArr(int A[], int n, int ng, int vg)
// Заполняет массив А из n элементов случайными значениями в диапазоне от ng до vg
{
for (int i = 0; i < n; ++i)
A[i] = MyRand(ng, vg);
}
void ArrOut(double A[], int n)
// Вывод на экран массива А из n элементов типа double
{
for (int i = 0; i < n; ++i)
cout << A[i] << " ";
cout << endl;
}
void ArrOut(int A[], int n)
// Вывод на экран массива А из n элементов типа double
{
for (int i = 0; i < n; ++i)
cout << A[i] << " ";
cout << endl;
}
void Swap(double &a, double &b)
// Обмен значений переменных a и b
{
double c = a;
a = b;
b = c;
}
void Swap(int &a, int &b)
// Обмен значений переменных a и b
{
int c = a;
a = b;
b = c;
}
void Swap(int a[], int b[], int n)
// Обмен значений массивов a и b из n элементов типа int
{
for (int i = 0; i < n; ++i)
Swap(a[i], b[i]);
}
void Swap(double a[], double b[], int n)
// Обмен значений массивов a и b из n элементов типа double
{
for (int i = 0; i < n; ++i)
Swap(a[i], b[i]);
}
void ArrInit(int A[], int n, int Val)
// Заполнение массива А из n элементов типа int значениями Val
{
for (int i = 0; i < n; ++i)
A[i] = Val;
}
void ArrInit(double A[], int n, double Val)
// Заполнение массива А из n элементов типа double значениями Val
{
for (int i = 0; i < n; ++i)
A[i] = Val;
}
void ArrCopy(int Src[], int Dst[], int n)
// Копирование значений массива Src и Dst из n элементов типа int
{
for (int i = 0; i < n; ++i)
Dst[i] = Src[i];
}
void ArrCopy(double Src[], double Dst[], int n)
// Копирование значений массива Src и Dst из n элементов типа double
{
for (int i = 0; i < n; ++i)
Dst[i] = Src[i];
}
void MinMax(int A[], int n, int &iMax, int &iMin)
// Поиск минимального и максимального значений в массиве А из n элементов.
// Возвращает индексы первого минимального iMin и первого максимального iMax элементов
{
int Max, Min;
iMax = iMin = 0;
Max = Min = A[0];
for (int i = 1; i < n; ++i)
{
if (A[i] > Max)
{
iMax = i;
Max = A[i];
}
if (A[i] < Min)
{
iMin = i;
Min = A[i];
}
}
}
void MinMax(int A[], int n, int &iMax, int &iMin, int &cMax, int &cMin)
// Поиск минимального и максимального значений в массиве А из n элементов.
// Возвращает индексы первого минимального iMin и первого максимального iMax элементов и
// количества максимальных cMax и минимальных cMin элементов в массиве
{
int Max, Min;
iMax = iMin = 0;
cMax = cMin = 1;
Max = Min = A[0];
for (int i = 1; i < n; ++i)
{
if (A[i] > Max)
{
cMax = 1;
iMax = i;
Max = A[i];
}
else
if (A[i] == Max)
++cMax;
if (A[i] < Min)
{
cMin = 1;
iMin = i;
Min = A[i];
}
else
if (A[i] == Min)
++cMin;
}
}
void ArrDelItem(int A[], int &n, int di)
// Удаление элемента с индексом di из массива А с n элементами,
// что эквивалентно сдвигу элементов массива на 1 элемент в сторону меньших значений
индексов элементов.
// Возвращает измененный массив А и его количество элементов n, уменьшенное на 1.
// Контроль корректности входных данных не осуществляется.
{
--n;
for (int i = di; i < n; ++i)
A[i] = A[i + 1];
}
void ArrInsItem(int A[], int &n, int ii, int Val)
// Вставка элемента со значением Val на позицию с индексом ii в массив А с n элементами,
// что эквивалентно сдвигу элементов массива на 1 элемент в сторону больших значений
индексов элементов и
// записи в элемент с идексом ii значения Val.
// Возвращает измененный массив А и его количество элементов n, увеличенное на 1.
// Контроль корректности входных данных не осуществляется.
{
if (ii > n) // Если индекс вставки больше индекса последнего элемента массива
более чем на 1, то
// новый элемент вставляется сразу за последним элементом массива.
ii = n;
for (int i = n; i > ii; --i)
A[i] = A[i - 1];
A[ii] = Val;
++n;
}
void ArrConcat(int A1[], int n1, int A2[], int n2, int R[], int &n)
// Слияние двух отсортированных по возрастанию массивов А1 и А2 с количеством элементов
n1 и n2 соответственно
// в массив R. Возвращает массив R (также отсортированный по возрастанию) и его
количество элементов n.
{
int i, j;
n = i = j = 0;
while (n < n1 + n2)
{
while ((i < n1) && ((A1[i] <= A2[j]) || (j == n2)))
{
R[n] = A1[i];
++i;
++n;
}
while ((j < n2) && ((A2[j] <= A1[i]) || (i == n1)))
{
R[n] = A2[j];
++j;
++n;
}
}
}
Библиотека функций сортировки массивов
/*
Функции сортировки массивов
Сохраните этот текст в файле с именем arr_sort.h. Поместите
этот файл в каталог проекта и в тексте программы используйте директиву
#include " arr_sort.h"
*/
#pragma once
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include "my_rand.h"
using namespace std;
//
// Прототипы функций
//
void Sort1_1(double A[], int n, bool Inc);
// Сортировка методом "пузырька" (вариант 1)
// A - сортируемый массив
// n - количество элементов в массиве
// Inc - порядок сортировки (true - по возрастанию)
void Sort1_2(double A[], int n, bool Inc);
// Сортировка методом "пузырька" (вариант 2)
// A - сортируемый массив
// n - количество элементов в массиве
// Inc - порядок сортировки (true - по возрастанию)
void Sort1_2(int A[], int n, bool Inc);
// Сортировка методом "пузырька" (вариант 2)
// A - сортируемый массив
// n - количество элементов в массиве
// Inc - порядок сортировки (true - по возрастанию)
void Sort2(double A[], int n, bool Inc);
// Сортировка методом обмена
// A - сортируемый массив элементами типа double
// n - количество элементов в массиве
// Inc - порядок сортировки (true - по возрастанию)
void Sort2(int A[], int n, bool Inc);
//
//
//
//
Сортировка методом обмена типа int
A - сортируемый массив
n - количество элементов в массиве
Inc - порядок сортировки (true - по возрастанию)
//
// Реализация
//
void Sort1_1(double A[], int n, bool Inc)
{
for (int i = 1; i < n; ++i)
{
int j = i;
while ((j > 0) && ((Inc && (A[j] < A[j - 1])) || (!Inc && (A[j] > A[j - 1]))))
{
Swap(A[j], A[j - 1]);
--j;
}
}
}
void Sort1_2(double A[], int n, bool Inc)
{
for (int i = 1; i < n; ++i)
for (int j = i;
(j > 0) && ((Inc && (A[j] < A[j - 1])) || (!Inc && (A[j] > A[j - 1]))); --j)
Swap(A[j], A[j - 1]);
}
void Sort2(double A[], int n, bool Inc)
{
for (int i = 0; i < n - 1; ++i)
for (int j = i + 1; j < n; ++j)
if ((Inc && (A[j] < A[i])) || (!Inc && (A[j] > A[i])))
Swap(A[i], A[j]);
}
void Sort2(int A[], int n, bool Inc)
{
for (int i = 0; i < n - 1; ++i)
for (int j = i + 1; j < n; ++j)
if ((Inc && (A[j] < A[i])) || (!Inc && (A[j] > A[i])))
Swap(A[i], A[j]);
}
Программа для проверки функций сортировки массивов
/*
Sort.cpp: определяет точку входа для консольного приложения.
Заголовочные файлы arr_common.h, arr_sort.h и my_rand.h должны находиться в папке
этого проекта, либо путь к ним должен быть указан в настройках параметров проекта:
Меню среды: Проект – Свойства – Свойства конфигурации – Каталоги VC++ - Каталоги
включения и добавляем здесь путь к нашим заголовочным файлам
*/
#include
#include
#include
#include
#include
#include
"stdafx.h"
<iostream>
<conio.h>
"arr_common.h"
"arr_sort.h"
"my_rand.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
const int N = 10;
double M[N];
setlocale(0, "");
RandInit(); // Инициализируем датчик случайных чисел (#include "my_rand.h")
cout << "
Проверка алгоритмов сортировки.\n";
cout << "
-------------------------------\n";
for (char b = '1'; b != 27; cout << "\n\t\t\tПродолжим? (нет - Esc) ",
b = _getch(), cout << endl)
{
RandMakeArr(M, N, 1, 5); // Заполняем массив М из N элементов случайными
числами в диапазоне от 1 до 5 (#include "arr_common.h")
cout << "Исходный массив:\n";
ArrOut(M, N); // Выводим исходный массив М из N элементов на экран
(#include "arr_common.h")
//
Sort1_1(M, N, 1); // Сортируем массив М из N элементов по возрастанию
методом "пузырька" (#include "arr_sort.h")
//
Sort1_2(M, N, 1); // Сортируем массив М из N элементов по возрастанию
методом "пузырька" (#include "arr_sort.h")
Sort2(M, N, 1); // Сортируем массив М из N элементов по возрастанию методом
обмена (#include "arr_sort.h")
cout << "Массив, отсортированный по возрастанию:\n";
ArrOut(M, N); // Выводим отсортированный массив М из N элементов на экран
(#include "arr_common.h")
Sort2(M, N, 0); // Сортируем массив М из N элементов по убыванию методом
обмена (#include "arr_sort.h")
cout << "Массив, отсортированный по убыванию:\n";
ArrOut(M, N); // Выводим отсортированный массив М из N элементов на экран
(#include "arr_common.h")
}
return 0;
}
Библиотека функций поиска в массивах
/*
Функции поиска в массивах
*/
#pragma once
#include "stdafx.h"
//
// Прототипы функций
//
int Find1_1(int A[], int n, int Val);
// Последовательный поиск значения Val в массиве А из n целых значений (вариант 1)
// Возвращает индекс найденного элемента или -1, если искомое значение отсутствует
int Find1_2(int A[], int n, int Val);
// Последовательный поиск значения Val в массиве А из n целых значений (вариант 2)
// Возвращает индекс найденного элемента или -1, если искомое значение отсутствует
int Find2(int A[], int n, int Val);
// Бинарный поиск значения Val в отсортированном по возрастанию массиве А из n целых
значений
// Возвращает индекс найденного элемента или -1, если искомое значение отсутствует
//
// Реализация
//
int Find1_1(int A[], int n, int Val)
// Последовательный поиск значения Val в массиве А из n целых значений (вариант 1)
{
int i = 0;
while (i < n)
{
if (A[i] == Val)
return i;
++i;
}
return -1;
}
int Find1_2(int A[], int n, int Val)
// Последовательный поиск значения Val в массиве А из n целых значений (вариант 2)
// Возвращает индекс найденного элемента или -1, если искомое значение отсутствует
{
for (int i = 0; i < n; ++i)
if (A[i] == Val)
return i;
return -1;
}
int Find2(int A[], int n, int Val)
// Бинарный поиск значения Val в отсортированном по возрастанию массиве А из n целых
значений
// Возвращает индекс найденного элемента или -1, если искомое значение отсутствует
{
if ((Val < A[0]) || (Val > A[n - 1])) // Отсеиваем заведомо не входящие в массив
значения
return -1;
int a = 0, b = n - 1, c;
while (b >= a)
{
c = (a + b) / 2;
// Находим в интервале [а, b] индекс срединного элемента - с
if (Val > A[c])
// Искомое значение справа от с
a = c + 1;
// Заменяем левую границу интервала поиска
else
if (Val < A[c]) // Искомое значение слева от с
b = c - 1;
// Заменяем правую границу интервала поиска
else
// Val == A[c]
return c;
// Индекс искомого элемента - с
}
return -1;
}
Программа для проверки функций поиска в массивах:
/*
Find.cpp: определяет точку входа для консольного приложения.
Заголовочные файлы arr_common.h, arr_sort.h и my_rand.h должны находиться в папке
этого проекта, либо путь к ним должен быть указан в настройках параметров проекта:
Меню среды: Проект – Свойства – Свойства конфигурации – Каталоги VC++ - Каталоги
включения и добавляем здесь путь к нашим заголовочным файлам
*/
#include
#include
#include
#include
#include
#include
"stdafx.h"
<iostream>
<conio.h>
"arr_common.h"
"arr_sort.h"
"arr_find.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(0, "");
const int N = 1000;
int M[N], V, Ind;
setlocale(0, "");
RandInit(); // Инициализируем датчик случайных чисел (#include "my_rand.h")
cout << "
Проверка алгоритма бинарного поиска.\n";
cout << "
------------------------------------\n";
RandMakeArr(M, N, 1, 1000); // Заполняем массив случайными чиселами (#include
"my_rand.h")
Sort2(M, N, 1); // Сортируем массив М из N элементов (#include "arr_sort.h")
ArrOut(M, N); // Выводим отсортированный массив на экран
for (char b = '1'; b != 27; cout << "\n\t\t\tПродолжим? (нет - Esc)",
b = _getch(), cout << endl)
{
cout << "\nКакое значение надо найти? ";
cin >> V; // Вводим значение для поиска
Ind = Find2(M, N, V); // Поиск V в массиве М из N элементов бинарным
поиском
if (Ind != -1)
cout << "Индекс значения " << V << " равен " << Ind << endl;
else
cout << "Значение " << V << " не найдено" << endl;
}
return 0;
}
Приложение 2. Функции стандартного ввода/вывода в
стиле C (printf, scanf)
Автор: Бардин П.Б.
Введение
Стандартная библиотека C/C++ включает ряд функций для чтения и записи на
консоли (клавиатура и монитор). Эти функции читают и пишут данные, как простой
поток символов.
Понятие потока (stream), использованное в программировании, тесно связано с
обычным, бытовым пониманием этого слова. Поток ввода можно сравнить с трубой,
по которой вода (информация) поступает в бассейн (память компьютера), поток
вывода - с трубой, по которой вода выходит из бассейна. Важной особенностью этой
трубы является то, что в каждый момент времени данные могут двигаться только в
одном направлении. Даже если одна и та же труба используется для ввода и вывода,
это не может происходить одновременно: для переключения направления потока его
нужно остановить, выполнить некие действия и лишь затем направить поток в
обратном направлении. Другой особенностью потока является то, что он почти
никогда не иссякает. Иногда он высыхает, но этот период не может быть долгим,
если система функционирует нормально.
Функция стандартного вывода printf()
Функция printf() является функцией стандартного вывода. С помощью этой функции
можно вывести на экран монитора строку символов, число, значение переменной...
Функция printf() имеет прототип в файле stdio.h
int printf(char *управляющая строка, ...);
В случае успеха функция printf() возвращает число выведенных символов.
Управляющая строка содержит два типа информации: символы, которые
непосредственно выводятся на экран, и спецификаторы формата, определяющие,
как выводить аргументы.
Функция printf() это функция форматированного вывода. Это означает, что в
параметрах функции необходимо указать формат данных, которые будут
выводиться. Формат данных указывается спецификаторами формата. Спецификатор
формата начинается с символа % за которым следует код формата.
Спецификаторы формата:
%с
%d
%i
%e
%E
символ
целое десятичное число
целое десятичное число
десятичное число в виде x.xx e+xx
десятичное число в виде x.xx E+xx
%f
%F
%g
%G
%o
%s
%u
%x
%X
%%
%p
%n
десятичное число с плавающей запятой xx.xxxx
десятичное число с плавающей запятой xx.xxxx
%f или %e, что короче
%F или %E, что короче
восьмеричное число
строка символов
беззнаковое десятичное число
шестнадцатеричное число
шестнадцатеричное число
символ %
указатель
указатель
Кроме того, к командам формата могут быть применены модификаторы l и h.
%ld
%hu
%Lf
печать long int
печать short unsigned
печать long double
В спецификаторе формата, после символа % может быть указана точность (число
цифр после запятой). Точность задаётся следующим образом: %.n<код формата>.
Где n - число цифр после запятой, а <код формата> - один из кодов приведённых
выше.
Например, если у нас есть переменная x=10.3563 типа float и мы хотим вывести её
значение с точностью до 3-х цифр после запятой, то мы должны написать:
printf("Переменная x = %.3f",x);
Результат:
Переменная x = 10.356
Вы также можете указать минимальную ширину поля отводимого для печати. Если
строка или число больше указанной ширины поля, то строка или число печатается
полностью.
Например, если вы напишите:
printf("%5d",20);
то результат будет следующим:
20
Обратите внимание на то, что число 20 напечаталось не с самого начала строки.
Если вы хотите чтобы неиспользованные места поля заполнялись нулями, то нужно
поставить перед шириной поля символ 0.
Например:
printf("%05d",20);
Результат:
00020
Кроме спецификаторов формата данных в управляющей строке могут находиться
управляющие символы:
\b
\f
\n
\r
\t
\v
\"
\'
\\
\0
\a
\N
\xN
\?
BS, забой
Новая страница, перевод страницы
Новая строка, перевод строки
Возврат каретки
Горизонтальная табуляция
Вертикальная табуляция
Двойная кавычка
Апостроф
Обратная косая черта
Нулевой символ, нулевой байт
Сигнал
Восьмеричная константа
Шестнадцатеричная константа
Знак вопроса
Чаще всего вы будете использовать символ \n. С помощью этого управляющего
символа вы сможете переходить на новую строку. Посмотрите примеры программ, и
вы всё поймёте.
Примеры программ.
/* Пример 1 */
#include <stdio.h>
void main(void)
{
int a,b,c; // Объявление переменных a,b,c
a=5;
b=6;
c=9;
printf("a=%d, b=%d, c=%d",a,b,c);
}
Результат работы программы:
a=5, b=6, c=9
/* Пример 2 */
#include <stdio.h>
void main(void)
{
float x,y,z;
x=10.5;
y=130.67;
z=54;
printf("Координаты объекта: x:%.2f, y:%.2f, z:%.2f", x, y, z);
}
Результат работы программы:
Координаты объекта: x:10.50, y:130.67, z:54.00
/* Пример 3 */
#include <stdio.h>
void main()
{
int x;
x=5;
printf("x=%d", x*2);
}
Результат работы программы:
x=10
/* Пример 4 */
#include <stdio.h>
void main(void)
{
printf("\"Текст в кавычках\"");
printf("\nСодержание кислорода: 100%%");
}
Результат работы программы:
"Текст в кавычках"
Содержание кислорода: 100%
/* Пример 5 */
#include <stdio.h>
void main(void)
{
int a;
a=11; // 11 в десятичной равно b в шестнадцатеричной
printf("a-dec=%d, a-hex=%X",a,a);
}
Результат работы программы:
a-dec=11, a-hex=b
/* Пример 6 */
#include <stdio.h>
void main(void)
{
char ch1,ch2,ch3;
ch1='A';
ch2='B';
ch3='C';
printf("%c%c%c",ch1,ch2,ch3);
}
Результат работы программы:
ABC
/* Пример 7 */
#include <stdio.h>
void main(void)
{
char *str="Моя строка.";
printf("Это %s",str);
}
Результат работы программы:
Это Моя строка.
/* Пример 8 */
#include <stdio.h>
void main(void)
{
printf("Здравствуйте!\n"); // После печати будет переход на новую строку - \n
printf("Меня зовут Павел."); // Это будет напечатано на новой строке
}
Результат работы программы:
Здравствуйте!
Меня зовут Павел.
Функция стандартного ввода scanf()
Функция scanf() - функция форматированного ввода. С её помощью вы можете
вводить данные со стандартного устройства ввода (клавиатуры). Вводимыми
данными могут быть целые числа, числа с плавающей запятой, символы, строки и
указатели.
Функция scanf() имеет следующий прототип в файле stdio.h:
int scanf(char *управляющая строка);
Функция возвращает число переменных, которым было присвоено значение.
Управляющая строка содержит три вида символов: спецификаторы формата,
пробелы и другие символы. Спецификаторы формата начинаются с символа %.
Спецификаторы формата:
%c
%d
%i
%e
%h
%o
%s
%x
%p
%n
чтение символа
чтение десятичного целого
чтение десятичного целого
чтение числа типа float (плавающая запятая)
чтение short int
чтение восьмеричного числа
чтение строки
чтение шестнадцатеричного числа
чтение указателя
чтение указателя в увеличенном формате
При вводе строки с помощью функции scanf() (спецификатор формата %s), строка
вводиться до первого пробела!! т.е. если вы вводите строку "Привет мир!" с
использованием функции scanf()
char str[80]; // массив на 80 символов
scanf("%s",str);
то после ввода результирующая строка, которая будет храниться в массиве str будет
состоять из одного слова "Привет". ФУНКЦИЯ ВВОДИТ СТРОКУ ДО ПЕРВОГО
ПРОБЕЛА! Если вы хотите вводить строки с пробелами, то используйте функцию
char *gets( char *buf );
С помощью функции gets() вы сможете вводить полноценные строки. Функция
gets() читает символы с клавиатуры до появления символа новой строки (\n). Сам
символ новой строки появляется, когда вы нажимаете клавишу enter. Функция
возвращает указатель на buf. buf - буфер (память) для вводимой строки.
Пример программы, которая позволяет ввести целую строку с клавиатуры и вывести
её на экран:
#include <stdio.h>
void main(void)
{
char buffer[100]; // массив (буфер) для вводимой строки
gets(buffer); // вводим строку и нажимаем enter
printf("%s",buffer); // вывод введённой строки на экран
}
Ещё одно важное замечание! Для ввода данных с помощью функции scanf(), ей в
качестве параметров нужно передавать адреса переменных, а не сами
переменные. Чтобы получить адрес переменной, нужно поставить перед именем
переменной знак & (амперсанд). Знак & означает взятие адреса.
Что значит адрес? Попробую объяснить. В программе у нас есть переменная.
Переменная хранит своё значение в памяти компьютера. Так вот адрес, который мы
получаем с помощью & это адрес в памяти компьютера, где храниться значение
переменной.
Давайте рассмотрим пример программы, который показывает нам как использовать
&
#include <stdio.h>
void main(void)
{
int x;
printf("Введите переменную x:");
scanf("%d",&x);
printf("Переменная x=%d",x);
}
Теперь давайте вернёмся к управляющей строке функции scanf(). Ещё раз:
int scanf(char *управляющая строка);
Символ пробела в управляющей строке дает команду пропустить один или более
пробелов в потоке ввода. Кроме пробела может восприниматься символ табуляции
или новой строки. Ненулевой символ указывает на чтение и отбрасывание этого
символа.
Разделителями между двумя вводимыми числами являются символы пробела,
табуляции или новой строки. Знак * после % и перед кодом формата
(спецификатором формата) дает команду прочитать данные указанного типа, но не
присваивать это значение.
Например:
scanf("%d%*c%d",&i,&j);
при вводе 50+20 присвоит переменной i значение 50, переменной j - значение 20,
а символ + будет прочитан и проигнорирован.
В команде формата может быть указана наибольшая ширина поля, которая подлежит
считыванию.
Например:
scanf("%5s",str);
указывает необходимость прочитать из потока ввода первые 5 символов. При вводе
1234567890ABC массив str будет содержать только 12345, остальные символы
будут проигнорированы. Разделители: пробел, символ табуляции и символ новой
строки - при вводе символа воспринимаются, как и все другие символы.
Если в управляющей строке встречаются какие-либо другие символы, то они
предназначаются для того, чтобы определить и пропустить соответствующий символ.
Поток символов 10plus20 оператором
scanf("%dplus%d",&x,&y);
присвоит переменной x значение 10, переменной y - значение 20, а символы plus
пропустит, так как они встретились в управляющей строке.
Одной из мощных особенностей функции scanf() является возможность задания
множества поиска (scanset). Множество поиска определяет набор символов, с
которыми будут сравниваться читаемые функцией scanf() символы. Функция scanf()
читает символы до тех пор, пока они встречаются в множестве поиска. Как только
символ, который введен, не встретился во множестве поиска, функция scanf()
переходит к следующему спецификатору формата. Множество поиска определяется
списком символов, заключённых в квадратные скобки. Перед открывающей скобкой
ставиться знак %. Давайте рассмотрим это на примере.
#include <stdio.h>
void main(void)
{
char str1[10], str2[10];
scanf("%[0123456789]%s", str1, str2);
printf("\n%s\n%s",str1,str2);
}
Введём набор символов:
12345abcdefg456
На экране программа выдаст:
12345
abcdefg456
При задании множества поиска можно также использовать символ "дефис" для
задания промежутков, а также максимальную ширину поля ввода.
scanf("%10[A-Z1-5]", str1);
Можно также определить символы, которые не входят во множество поиска. Перед
первым из этих символов ставиться знак ^. Множество символов различает строчные
и прописные буквы.
Напомню, что при использовании функции scanf(), ей в качестве параметров нужно
передавать адреса переменных. Выше был написан код:
char str[80]; // массив на 80 символов
scanf("%s",str);
Обратите внимание на то, что перед str не стоит символ &. Это сделано потому, что
str является массивом, а имя массива - str является указателем на первый элемент
массива. Поэтому знак & не ставиться. Мы уже передаем функции scanf() адрес. Ну,
проще говоря, str это адрес в памяти компьютера, где будет храниться значение
первого элемента массива.
Примеры программ.
Пример 1.
Эта программа выводит на экран запрос "Сколько вам лет?:" и ждёт ввода данных.
Если, например, ввести число 20, то программа выведет строку "Вам 20 лет.". При
вызове функции scanf(), перед переменной age мы поставили знак &, так как
функции scanf() нужны адреса переменных. Функция scanf() запишет введённое
значение по указанному адресу. В нашем случае введённое значение 20 будет
записано по адресу переменной age.
/* Пример 1 */
#include <stdio.h>
void main(void)
{
int age;
printf("\nСколько вам лет?:");
scanf("%d",&age);
printf("Вам %d лет.", age);
}
Пример 2.
Программа калькулятор. Этот калькулятор может только складывать числа. При
вводе 100+34 программа выдаст результат: 100+34=134.
/* Пример 2 */
#include <stdio.h>
void main(void)
{
int x, y;
printf("\nКалькулятор:");
scanf("%d+%d", &x, &y);
printf("\n%d+%d=%d", x, y, x+y);
}
Пример 3.
Этот пример показывает, как установить ширину поля считывания. В нашем примере
ширина поля равна пяти символам. Если вы введёте строку с большим количеством
символов, то все символы после 5-го будут отброшены. Обратите внимание на вызов
функции scanf(). Знак & не стоит перед именем массива name, так как имя массива
name является адресом первого элемента массива.
/* Пример 3 */
#include <stdio.h>
void main(void)
{
char name[5];
printf("\nВведите ваш логин (не более 5 символов):");
scanf("%5s", name);
printf("\nВы ввели %s", name);
}
Пример 4.
Последний пример в этой статье показывает, как можно использовать множество
поиска. После запуска программы введите число от 2 до 5.
/* Пример 4 */
#include <stdio.h>
void main(void)
{
char bal;
printf("Ваша оценка 2,3,4,5:");
scanf("%[2345]", &bal);
printf("\nОценка %c", bal);
}
Приложение 3. Библиотека консольного ввода-вывода
Эта библиотека будет постепенно дополняться новыми функциями.
/*
Это библиотека функций консольного ввода-вывода. Протестирована в среде MS Visual
C++ 2010.
Для ее использования необходимо сохранить этот текст с файле с именем my_conio.h.
Поместить
этот файл в каталог проекта и в тексте программы использовать директиву #include
"my_conio.h"
*/
#pragma once
#include <windows.h> // Для CharToOemA
#include <conio.h>
// Для getch()
#include <iostream>
using namespace std;
//
// Прототипы функций
//
char *Rus(char *sfrom, char *sto);
/*
Вывод текста, содержащего русские символы.
Использование:
char s[100];
cout << Rus("Это текст на русском языке!\n", s);
*/
char *Rus(char *s);
/*
Вывод текста, содержащего русские символы.
Использование:
char s[] = "И это текст на русском языке!\n";
cout << Rus(s);
*/
void out_Text(char *s);
/*
Вывод текста (и русского) без перехода на новую строку.
Использование:
out_Text("Это текст");
Ограничение: длина текста не более 255 символов
*/
void out_Text_ln(char *s);
/*
Вывод текста (и русского) с переходом на новую строку.
Использование:
out_Text_ln("Это текст");
Ограничение: длина текста не более 255 символов
*/
void Pause();
/*
Приостановка выполнения программы
*/
//
// Реализация функций
//
char *Rus(char *sfrom, char *sto)
{
CharToOemA(sfrom, sto);
return sto;
}
char *Rus(char *s)
{
CharToOemA(s, s);
return s;
}
void out_Text(char *s)
{
char S[256];
if (strlen(s) <= 255)
CharToOemA(s, S);
else
CharToOemA("Ошибка. Длина текста больше 255 символов", S);
cout << S;
}
void out_Text_ln(char *s)
{
out_Text(s);
cout << endl;
}
void Pause()
{
out_Text("Для продолжения нажмите любую клавишу . . .\n");
_getch();
}
Приложение 4. Библиотека управления консолью (MyCrt.h)
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
#pragma once;
struct sKeyCode {
wchar_t kc, sc;
};
struct sMouseInf {
char mState;
int x, y;
};
union uKeyOrMouseInf {
sKeyCode KeyCode;
sMouseInf MouseInf;
};
short MaxX(); // Возвращает ширину буфера вывода
short MaxY(); // Возвращает высоту буфера вывода
void ConWidth(int W); // Устанавливает ширину W буфера вывода
void ConHeight(int H); // Устанавливает высоту H буфера вывода
void ConSize(int W, int H); // Устанавливает ширину W и высоту H буфера вывода
void ScrollVert(int P); // Перемещает окно консоли по вертикали на Р строк (при Р > 0 вниз; при Р < 0 - вверх)
void ScrollHor(int P); // Перемещает окно консоли по горизонтали на Р колонок (при Р > 0
- вправо; при Р < 0 - влево)
void ScrSize(int W, int H); // Устанавливает ширину W и высоту H окна консоли
void ScrGoTo(int X, int Y); // Перемещает окно консоли в точку буфера вывода с
координатами (X, Y)
void CursorVisible(bool Visible); // Включает и отключает видимость курсора в окне
консоли
void GoToXY(short x, short y); // Перемещает курсор в точку буфера консоли с координатами
(X, Y)
unsigned short WhereX(); // Возвращает координату Х текущего положения курсора
unsigned short WhereY(); // Возвращает координату Y текущего положения курсора
void WhereXY(unsigned short &x, unsigned short &y); // Возвращает координаты Х и Y
текущего положения курсора
unsigned short GetTextColors(); // Возвращает цветовые аттрибуты буфера вывода в
шестнадцатеричном формате
void TextBackground(unsigned short Color); // Устанавливает цвет фона
void TextForeground(unsigned short Color); // Устанавливает цвет символов
void TextColor(unsigned short Colors); // Устанавливает цвета фона и символов
// Изменяет цветовые аттрибуты на Colors начиная с точки с координатами (X, Y) на участке
длиной len символов
void ChangeTextAttribute(unsigned short Colors, unsigned short x, unsigned short y,
unsigned short len);
void ClrScr(); // Очистка буфера ввода консоли установленным цветом фона
void FillChar(int x, int y, int len, char c); // Начиная с точки (X, Y) выводит len раз
символ С
void ClearEoln(); // Очищает строку от текущей позиции курсора до конца строки
void WriteText(int x, int y, wchar_t s[]); // Выводит текст S в точку с координатами (X,
Y)
void WriteText(int x, int y, wchar_t s[], short Colors); // Выводит текст S в точку с
координатами (X, Y) с цветами Colors
bool ReadKey(wchar_t &c); // Осуществляет чтение кода С нажатой клавиши. Возвращает TRUE,
если нажата обычная клавиша
int ReadKeyOrMouse(uKeyOrMouseInf &KMF); // Обрабатывает события клавиатуры и мыши
// Во всех функциях параметр Colors задает цветовые аттрибуты буфера вывода в
шестнадцатеричном формате.
// Например: 0х1F - определяет следующие цвета 1 - цвет фона (темно-синий), F - цвет
символов (ярко-белый)
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE),
hIn = GetStdHandle(STD_INPUT_HANDLE);
const char LEFT_BTN_CLICK = FROM_LEFT_1ST_BUTTON_PRESSED,
RIGHT_BTN_CLICK = RIGHTMOST_BUTTON_PRESSED,
DBL_CLICK = 3,
H_WHEELE = 4,
V_WHEELE = 5,
MOUSE_MOVE = 6;
void ColorMap()
{
for (int i = 0; i < 16; ++ i)
{
int b = i << 4;
for (int f = 0; f < 16; ++ f)
{
SetConsoleTextAttribute(hOut, b | f);
cout << '*';
}
cout << endl;
}
}
short MaxX()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
return ConInfo.dwSize.X;
}
short MaxY()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
return ConInfo.dwSize.Y;
}
void ConWidth(int W)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
COORD c = {W, ConInfo.dwSize.Y};
SetConsoleScreenBufferSize(hOut, c);
}
void ConHeight(int H)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
if (H < 25)
H = 25;
COORD c = {ConInfo.dwSize.X, H};
SetConsoleScreenBufferSize(hOut, c);
}
void ConSize(int W, int H)
{
if (H < 25)
H = 25;
COORD c = {W, H};
SetConsoleScreenBufferSize(hOut, c);
}
void ScrSize(int W, int H)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
SMALL_RECT WRect = ConInfo.srWindow;
COORD c = GetLargestConsoleWindowSize(hOut);
if (W > c.X)
W = c.X;
if (H > c.Y)
H = c.Y;
if (W > ConInfo.dwSize.X)
W = ConInfo.dwSize.X;
if (H > ConInfo.dwSize.Y)
H = ConInfo.dwSize.Y;
WRect.Right = WRect.Left + W - 1;
WRect.Bottom = WRect.Top + H - 1;
SetConsoleWindowInfo(hOut, true, &WRect);
}
void ScrGoTo(int X, int Y)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
SMALL_RECT WRect = ConInfo.srWindow;
WRect.Right = X + WRect.Right - WRect.Left;
WRect.Bottom = Y + WRect.Bottom - WRect.Top;
WRect.Left = X;
WRect.Top = Y;
SetConsoleWindowInfo(hOut, true, &WRect);
GoToXY(X, Y);
}
void ScrollVert(int P)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
SMALL_RECT WRect = ConInfo.srWindow;
WRect.Top += P;
WRect.Bottom += P;
SetConsoleWindowInfo(hOut, true, &WRect);
GoToXY(WhereX(), WhereY() + P);
}
void ScrollHor(int P)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
SMALL_RECT WRect = ConInfo.srWindow;
WRect.Left += P;
WRect.Right += P;
SetConsoleWindowInfo(hOut, true, &WRect);
GoToXY(WhereX() + P, WhereY());
}
void CursorVisible(bool Visible)
{
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOut, &CursorInfo);
CursorInfo.bVisible = Visible;
SetConsoleCursorInfo(hOut, &CursorInfo);
}
void GoToXY(short x, short y)
{
COORD c = {x, y};
SetConsoleCursorPosition(hOut, c);
}
unsigned short WhereX()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
return ConInfo.dwCursorPosition.X;
}
unsigned short WhereY()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
return ConInfo.dwCursorPosition.Y;
}
void WhereXY(unsigned short &x, unsigned short &y)
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
GetConsoleScreenBufferInfo(hOut, &ConInfo);
x = ConInfo.dwCursorPosition.X;
y = ConInfo.dwCursorPosition.Y;
}
unsigned short GetTextColors()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfo;
if (GetConsoleScreenBufferInfo(hOut, &ConInfo))
return ConInfo.wAttributes;
else
return 0;
}
void TextBackground(unsigned short Color)
{
if (Color >= 16)
return;
Color = Color << 4;
Color = GetTextColors() & 0xFF0F | Color;
SetConsoleTextAttribute(hOut, Color);
}
void TextForeground(unsigned short Color)
{
if (Color >= 16)
return;
Color = GetTextColors() & 0xFFF0 | Color;
SetConsoleTextAttribute(hOut, Color);
}
void TextColor(unsigned short Colors)
{
if (Colors >= 256)
return;
SetConsoleTextAttribute(hOut, Colors);
}
void ChangeTextAttribute(unsigned short Colors, unsigned short x, unsigned short y,
unsigned short len)
{
COORD c = {x, y};
DWORD l;
FillConsoleOutputAttribute( hOut, Colors, len, c, &l );
}
void ClrScr()
{
COORD c = {0, 0};
DWORD Chr;
CONSOLE_SCREEN_BUFFER_INFO ConInfor;
DWORD ConSize;
if (!GetConsoleScreenBufferInfo(hOut, &ConInfor))
return;
ConSize = ConInfor.dwSize.X * ConInfor.dwSize.Y;
if (!FillConsoleOutputCharacter(hOut, (TCHAR) ' ', ConSize, c, &Chr))
return;
if (!FillConsoleOutputAttribute(hOut, ConInfor.wAttributes, ConSize, c, &Chr))
return;
SetConsoleCursorPosition(hOut, c);
}
void FillChar(int x, int y, int len, char c)
{
DWORD Chr;
COORD coor = {x, y};
FillConsoleOutputCharacter(hOut, (TCHAR) c, len, coor, &Chr);
}
void ClearEoln()
{
CONSOLE_SCREEN_BUFFER_INFO ConInfor;
GetConsoleScreenBufferInfo(hOut, &ConInfor);
DWORD Chr, Size = ConInfor.dwSize.X - ConInfor.dwCursorPosition.X;
FillConsoleOutputCharacter(hOut, (TCHAR) ' ', Size, ConInfor.dwCursorPosition,
&Chr);
}
void WriteText(int x, int y, wchar_t s[])
{
GoToXY(x, y);
wcout << s;
}
void WriteText(int x, int y, wchar_t s[], short Colors)
{
GoToXY(x, y);
wcout << s;
ChangeTextAttribute(Colors, x, y, wcslen(s));
}
bool ReadKey(wchar_t &c)
{
bool b = 0;
c = _getwch();
if (c == 224 || !c)
c = _getwch();
else
b = 1;
return b;
}
int ReadKeyOrMouse(uKeyOrMouseInf &KMF)
{
DWORD RealRead;
int Fl = 0;
INPUT_RECORD InBuf;
if (ReadConsoleInput(hIn, &InBuf, 1, &RealRead))
switch(InBuf.EventType)
{
case KEY_EVENT:
if (InBuf.Event.KeyEvent.bKeyDown)
{
KMF.KeyCode.kc = InBuf.Event.KeyEvent.uChar.UnicodeChar;
KMF.KeyCode.sc = InBuf.Event.KeyEvent.wVirtualScanCode;
Fl = 1;
}
break;
case MOUSE_EVENT:
KMF.MouseInf.x = InBuf.Event.MouseEvent.dwMousePosition.X;
KMF.MouseInf.y = InBuf.Event.MouseEvent.dwMousePosition.Y;
KMF.MouseInf.mState = 0;
switch(InBuf.Event.MouseEvent.dwEventFlags)
{
case 0:
if(InBuf.Event.MouseEvent.dwButtonState ==
FROM_LEFT_1ST_BUTTON_PRESSED)
KMF.MouseInf.mState = LEFT_BTN_CLICK;
else
if(InBuf.Event.MouseEvent.dwButtonState ==
RIGHTMOST_BUTTON_PRESSED)
KMF.MouseInf.mState = RIGHT_BTN_CLICK;
break;
case DOUBLE_CLICK:
KMF.MouseInf.mState = DBL_CLICK;
break;
case MOUSE_HWHEELED:
KMF.MouseInf.mState = H_WHEELE;
break;
case MOUSE_MOVED:
KMF.MouseInf.mState = MOUSE_MOVE;
break;
case MOUSE_WHEELED:
KMF.MouseInf.mState = V_WHEELE;
break;
}
Fl = 2;
}
FlushConsoleInputBuffer(hIn);
return Fl;
}
Приложение 5. Библиотека Menu.h и пример ее
использования
Библиотека Menu.h без мыши
// Вариант библиотеки Menu.h без мыши
#include "MyCrt.h"
#include <string.h>
using namespace std;
#pragma once;
struct sMenu {
// Количество команд NumberComands <= 20; Текст команды <= 60 символов
int NormAttr;
// Цвет не выбранного элемента меню
int ActiveAttr;
// Цвет выбранного элемента меню
int SelectedComand;
// Номер выбранного элемента меню (от 1 до
NumberComands)
int NumberComands;
// Количество элементов меню
wchar_t Comands[20][61];
// Тексты элементов меню
int X;
// Положение меню на экране
int Y;
// Положение меню на экране
};
int ComandMaxLen(sMenu &M)
// Возвращает длину самой длинной команды меню
{
size_t Max = wcslen(M.Comands[0]);
for (int i = 1; i < M.NumberComands; ++i)
if (wcslen(M.Comands[i]) > Max)
Max = wcslen(M.Comands[i]);
return Max;
}
void SetActiveComand(sMenu &M, short ActCom)
// Выделяет в меню выбранную команду
{
int CL = ComandMaxLen(M);
ChangeTextAttribute(M.NormAttr, M.X, M.Y + M.SelectedComand - 1, CL);
ChangeTextAttribute(M.ActiveAttr, M.X, M.Y + ActCom - 1, CL);
GoToXY(M.X + CL, M.Y + ActCom - 1);
M.SelectedComand = ActCom;
}
void DisplayMenu(sMenu &M, int X, int Y )
// Выводит меню на экран
{
M.X = X;
M.Y = Y;
for (int i = 0; i < M.NumberComands; ++i)
{
GoToXY(X, Y + i);
wcout << M.Comands[i] << endl;
}
SetActiveComand(M, M.SelectedComand);
}
int MenuNavigator(sMenu &M, int X, int Y, wchar_t &c)
// Осуществляет перемещение по меню и возвращает номер выбранной команды.
// Параметр "с" соответствует коду клавиши, с помощью которой была выбрана команда
{
CursorVisible(false);
DisplayMenu(M, X, Y);
do
{
if (!ReadKey(c))
{
if (c == 72) // Up
if (M.SelectedComand > 1)
SetActiveComand(M, M.SelectedComand - 1);
else
SetActiveComand(M, M.NumberComands);
if (c == 80) // Dn
if (M.SelectedComand < M.NumberComands)
SetActiveComand(M, M.SelectedComand + 1);
else
SetActiveComand(M, 1);
}
}
while (c != 27 && c != 13);
CursorVisible(true);
return M.SelectedComand;
}
int MenuChoice(sMenu &M, int X, int Y, wchar_t &c)
// Чистит экран и выводит меню в точку (X, Y)
{
ClrScr();
return MenuNavigator(M, X, Y, c);
}
int MenuChoice(sMenu &M, wchar_t &c)
{
// Экран не чистится. Выводит меню в точку, где находится курсор
return MenuNavigator(M, WhereX(), WhereY(), c);
}
Библиотека Menu.h с мышью
// Вариант библиотеки Menu.h с подключением мыши
#include "MyCrt.h"
using namespace std;
#pragma once;
struct sMenu {
// Количество команд NumberComands <= 20; Текст команды <= 60 символов
int NormAttr;
// Цвет не выбранного элемента меню
int ActiveAttr;
// Цвет выбранного элемента меню
int SelectedComand;
// Номер выбранного элемента меню (от 1 до
NumberComands)
int NumberComands;
// Количество элементов меню
wchar_t Comands[20][61];
// Тексты элементов меню
int X;
// Положение меню на экране
int Y;
// Положение меню на экране
};
int ComandMaxLen(sMenu &M)
// Возвращает длину самой длинной команды меню
{
size_t Max = wcslen(M.Comands[0]);
for (int i = 1; i < M.NumberComands; ++i)
if (wcslen(M.Comands[i]) > Max)
Max = wcslen(M.Comands[i]);
return Max;
}
void SetActiveComand(sMenu &M, short ActCom)
// Выделяет в меню выбранную команду
{
int CL = ComandMaxLen(M);
ChangeTextAttribute(M.NormAttr, M.X, M.Y + M.SelectedComand - 1, CL);
ChangeTextAttribute(M.ActiveAttr, M.X, M.Y + ActCom - 1, CL);
GoToXY(M.X + CL, M.Y + ActCom - 1);
M.SelectedComand = ActCom;
}
void DisplayMenu(sMenu &M, int X, int Y )
// Выводит меню на экран
{
M.X = X;
M.Y = Y;
for (int i = 0; i < M.NumberComands; ++i)
{
GoToXY(X, Y + i);
wcout << M.Comands[i] << endl;
}
SetActiveComand(M, M.SelectedComand);
}
char KeyProc(sMenu &M, uKeyOrMouseInf KMInf)
// Обработка клавиатуры
{
if (KMInf.KeyCode.sc == 72) // Up
if (M.SelectedComand > 1)
SetActiveComand(M, M.SelectedComand - 1);
else
SetActiveComand(M, M.NumberComands);
if (KMInf.KeyCode.sc == 80) // Dn
if (M.SelectedComand < M.NumberComands)
SetActiveComand(M, M.SelectedComand + 1);
else
SetActiveComand(M, 1);
return char(KMInf.KeyCode.kc);
}
bool PointInRect(COORD C, RECT Rec)
// Возвращает true, если точк с координатами С находится внутри прямоугольной
области Rec
{
return C.X >= Rec.left && C.Y >= Rec.top && C.X <= Rec.right && C.Y <= Rec.bottom;
}
bool MouseInMenu(sMenu &M, uKeyOrMouseInf KMInf)
// Проверка нахождения курсора мыши в области меню
{
COORD C = {KMInf.MouseInf.x, KMInf.MouseInf.y};
RECT R = {M.X, M.Y, M.X + ComandMaxLen(M) - 1, M.Y + M.NumberComands - 1};
return PointInRect(C, R);
}
char MouseProc(sMenu &M, uKeyOrMouseInf KMInf)
// Обработка мыши
{
if ((KMInf.MouseInf.mState == LEFT_BTN_CLICK || KMInf.MouseInf.mState ==
RIGHT_BTN_CLICK ||
KMInf.MouseInf.mState == DBL_CLICK) && MouseInMenu(M, KMInf))
{
int Com = 1;
while (Com <= M.NumberComands && KMInf.MouseInf.y != (M.Y + Com - 1))
++Com;
SetActiveComand(M, Com);
if (KMInf.MouseInf.mState == DBL_CLICK)
return 13;
else
return 0;
}
else
return 0;
}
int MenuNavigator(sMenu &M, int X, int Y, wchar_t &c)
// Осуществляет перемещение по меню и возвращает номер выбранной команды.
// Параметр "с" соответствует коду клавиши, с помощью которой была выбрана команда
{
CursorVisible(false);
DisplayMenu(M, X, Y);
uKeyOrMouseInf KMInf;
int i;
do
{
c = 0;
i = ReadKeyOrMouse(KMInf);
if (i == 1)
c = KeyProc(M, KMInf);
else
if (i == 2)
c = MouseProc(M, KMInf);
}
while (c != 27 && c != 13);
CursorVisible(true);
return M.SelectedComand;
}
int MenuChoice(sMenu &M, int X, int Y, wchar_t &c)
// Чистит экран и выводит меню в точку (X, Y)
{
ClrScr();
return MenuNavigator(M, X, Y, c);
}
int MenuChoice(sMenu &M, wchar_t &c)
{
// Экран не чистится. Выводит меню в точку, где находится курсор
return MenuNavigator(M, WhereX(), WhereY(), c);
}
Пример использования библиотеки Menu.h
// MenuExample.cpp: определяет точку входа для консольного приложения.
//
#include "stdafx.h"
#include <MyCrt.h>
#include <Menu.h>
using namespace std;
void InitMenu(sMenu &M)
{
sMenu B = {
0x9F,
// Цвет не выбранного элемента меню
0x70,
// Цвет выбранного элемента меню
1,
// Начальный номер выбранного элемента меню
7,
// Количество элементов меню
// Тексты элементов меню:
L" Команда 1 ",
L" Команда 2 ",
L" Команда 3 ",
L" Команда 4 ",
L" Команда 5 ",
L" Команда 6 ",
L" Выход "
};
M = B;
}
void InitMenu1(sMenu &M)
{
sMenu B = {
0x9F,
// Цвет не выбранного элемента меню
0x70,
// Цвет выбранного элемента меню
1,
// Начальный номер выбранного элемента меню
2,
// Количество элементов меню
// Тексты элементов меню:
L" Команда 31 ",
L" Команда 32 ",
};
M = B;
}
void ComandExecute1(int Com, wchar_t c)
{
switch (Com)
{
case 1: ;
case 2: ;
ClrScr();
cout << 3 << Com << "
_getwch();
break;
}
}
" << c << endl;
void ComandExecute(int Com, wchar_t c)
{
switch (Com)
{
case 1: ;
case 2: ;
case 4: ;
case 5: ;
case 6: ;
case 7:
ClrScr();
cout << Com << " " << c << endl;
_getwch();
break;
case 3:
cout << "->";
sMenu M1;
InitMenu1(M1);
Com = MenuChoice(M1, c);
if (c != 27)
ComandExecute1(Com, c);
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
setlocale (LC_ALL, ".866");
ConSize(80, 25);
ScrSize(80, 25);
TextColor(0x9F);
ClrScr();
sMenu M;
InitMenu(M);
wchar_t c;
int Key;
do
{
Key = MenuChoice(M, 20, 5, c);
if (c != 27)
ComandExecute(Key, c);
}
while (Key != 7);
return 0;
}
Download