Основы программирования в среде Builder C++
Особенность создания оконного и консольного приложений. Анализ реализации разветвляющихся и циклических алгоритмов. Обработка одномерных и двухмерных динамических массивов. Разработка структур с использованием файлов. Суть построения графиков функций.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | методичка |
Язык | русский |
Дата добавления | 27.04.2015 |
Размер файла | 756,2 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Работу программы проверить для a = 0,1; b = 1,0; h = 0,1; значение параметра n выбрать в зависимости от задания.
1. ,
.
2.
.
3.
.
4.
.
5.
.
6..
7. ,
.
8. ,
.
9. ,
.
10.
.
11. ,
.
12. ,
.
13. ,
.
14. ,
.
15. ,
.
16.
.
4. Функции пользователя
Цель работы: познакомиться с механизмом составления и организации взаимодействия пользовательских функций, составить и отладить программу.
4.1 Краткие теоретические сведения
Подпрограмма - это именованная и определенным образом оформленная группа операторов, вызываемая по мере необходимости.
В языке С++ в качестве подпрограмм используют функции, которые должны быть декларированы до их первого использования. Предварительное описание функции называется прототипом, который обычно размещается в начале программы (*.cpp) либо в заголовочном файле (*.h) и сообщает компилятору о том, что далее в программе будет приведен ее полный текст, т.е. реализация.
Описание прототипа имеет следующий вид:
тип_результата ID_функции (список типов параметров);
а определение функции имеет следующую структуру:
тип_результата ID_функции (список параметров)
{
код функции
return результат;
}
Результат возвращается из функции в точку вызова при помощи оператора return и преобразуется к типу, указанному в заголовке функции. Если тип функции не указан, то по умолчанию устанавливается тип int, если же функция не возвращает результата, то следует указать пустой тип void. Список параметров состоит из перечня типов и ID параметров, разделенных запятыми.
Из функции можно передать только одно значение, при необходимости возвратить несколько - в списке параметров используют указатели.
Пример реализации функции, определяющей наименьшее из двух целых чисел:
int Min_x_y(int x, int y) {
return (x<y) ? x : y;
}
Вызов функции имеет следующий формат:
ID_функции(список аргументов);
где в качестве аргументов можно использовать константы, переменные, выражения (их значения перед вызовом функции будут компилятором определены). Аргументы списка вызова должны совпадать со списком параметров вызываемой функции по количеству и порядку следования параметров, а типы аргументов при передаче будут преобразованы к указанным в функции типам параметров.
Вызов предыдущей функции может иметь вид: min = Min_x_y(a, b);
Область действия переменных
Область действия переменной - это правила, которые устанавливают, какие данные доступны из текущего места программы, и определяют переменные двух типов: глобальные и локальные.
Глобальные переменные объявляются вне какой-либо функции и могут быть использованы в любом месте программы, но перед их первым использованием они должны быть объявлены и инициализированы. Область действия глобальных переменных - вся программа с момента их объявления. При объявлении глобальные переменные обнуляются.
Область действия локальных переменных - это блоки, где они объявлены. К локальным относятся и формальные параметры в заголовке функций пользователя с бластью действия - кодом функции. При выходе из блока значения локальных переменных теряются.
В языке С каждая переменная принадлежит одному из четырех классов памяти - автоматической (auto), внешней (extern), статической (static) и регистровой (register). Тип памяти указывается перед спецификацией типа, например, register int a; или static double b; По умолчанию устанавливается класс auto и переменные размещаются в стеке.
Указатель на функцию
Функции могут быть использованы в качестве формальных параметров, для этого используется указатель на функцию. Например, указатель р на функцию, возвращающую результат типа double и имеющую два параметра doublet и int, объявляется следующим образом:
double (*p)(double, int);
Используя операцию typedef, тип такого указателя может быть объявлен так
typedef double (*TFun)(double, int);
4.2 Пример выполнения задания
Написать программу вычисления выбранной функции, вид которой в свою очередь передается в качестве параметра в функцию вывода (Out_Rez).
4.2.1 Создание оконного приложения
Панель диалога с полученными результатами представлена на рис. 4.1, а текст программы может иметь следующий вид:
#include "math.h"
//------------ Декларация типа указателя на функции -------------------------
typedef double (*TFun)(double);
//------------Декларации прототипов функций Пользователя ---------------
double fun1(double);
double fun2(double);
void Out_Rez(TFun, double, double, double, TMemo*);
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Edit1->Text="0,1"; Edit2->Text="3"; Edit3->Text="0,3";
Memo1->Clear(); Memo2->Clear();
RadioGroup1->ItemIndex=0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double a, b, h;
a = StrToFloat(Edit1->Text);
b = StrToFloat(Edit2->Text);
h = StrToFloat(Edit3->Text);
switch(RadioGroup1->ItemIndex) {
case 0: Out_Rez (fun1,a,b,h,Memo1); break;
case 1: Out_Rez (fun2,a,b,h,Memo2); break;
}
}
Рис. 4.1
//---------- Реализации функций Пользователя ---------------------------------
double fun1( double r){
return 2*exp(r*r);
}
double fun2(double r) {
return pow(sin(r), 2);
}
void Out_Rez (TFun f,double xn,double xk,double h,TMemo *mem) {
for(double x=xn; x<=xk; x+=h)
mem->Lines->Add(" x = "+FloatToStrF(x,ffFixed,8,2)+
" y = "+FloatToStrF(f(x),ffFixed,8,4));
}
4.2.2 Создание консольного приложения
Текст программы может выглядеть следующим образом:
. . .
typedef double (*TFun)(double); // Декларация типа указателя на функцию
double fun1(double); // Декларации прототипов функций
double fun2(double);
void Out_Rez (TFun,double,double,double);
void main()
{
double a, b, h;
puts("Input a,b,h");scanf("%lf%lf%lf", &a, &b, &h);
puts("\n\t Function - 2*exp(x)");Out_Rez (fun1,a,b,h);
puts("\n\t Function - sin(x)*sin(x)");Out_Rez (fun2,a,b,h);
puts("\n Press any key ... ");
getch();
}
//---------- Реализации функций пользователя ---------------------------------
double fun1( double r){
return 2*exp(r*r);
}
double fun2(double r) {
return pow(sin(r), 2);
}
void Out_Rez (TFun f,double xn,double xk,double h) {
for(double x=xn; x<=xk; x+=h)
printf(" x = %5.2lf, y = %8.4lf\n",x,f(x));
}
Результат выполнения программы:
4.3 Индивидуальные задания
По заданию лабораторной работы №3 написать программу расчета выбранной функции Y(x), или S(x) (желательно и |Y(x)-S(x)|), вид которой в свою очередь передается в качестве параметра в функцию вывода (Out_Rez).
5. Обработка одномерных массивов
Цель работы: изучить составной тип данных - массив, основные свойства компоненты StringGrid. Написать и отладить программу с использованием одномерных массивов.
5.1 Общие теоретические сведения
Массив - конечная последовательность данных одного типа. Массив - объект сложного типа, каждый элемент которого определяется именем (ID) и целочисленным значением индекса (номера), по которому к элементу массива производится доступ. Рассмотрим одномерные массивы.
Внимание! Индексы массивов в языке С/С++ начинаются с 0.
В программе одномерный массив декларируется следующим образом:
тип ID массива [размер];
где размер - указывает количество элементов в массиве. Размер массива может задаваться константой или константным выражением. Для использования массивов переменного размера существует отдельный механизм - динамическое выделение памяти.
Примеры декларации массивов:
int a[5];
double b[4] = {1.5, 2.5, 3.75};
в целочисленном массиве а первый элемент а[0], второй - а[1], …, пятый - а[4]. Для массива b, состоящего из действительных чисел, выполнена инициализация, причем элементы массива получат следующие значения: b[0]=1.5, b[1]=2.5, b[2]=3.75, b[3]=0.
В языке С/С++ не проверяется выход индекса за пределы массива. Корректность использования индексов элементов массива должен контролировать программист.
Примеры описания массивов:
const Nmax=10; - задание максимального значения;
typedef double mas1[Nmax*2]; - описание типа одномерного массива;
mas1 a; - декларация массива а типа mas1;
int ss[10]; - массив из десяти целых чисел.
Элементы массивов могут использоваться в выражениях так же, как и обычные переменные, например:
f = 2*a[3] + a[Ss[i] + 1]*3;
a[n] = 1 + sqrt(fabs(a[n-1]));
5.2 Создание оконного приложения
Компонента StringGrid
При работе с массивами ввод и вывод значений обычно организуется с использованием компоненты StringGrid, предназначенной для отображения информации в виде двухмерной таблицы, каждая ячейка которой представляет собой окно однострочного редактора (аналогично окну Edit). Доступ к информации осуществляется с помощью элемента Cells[ACol][ARow] типа AnsiString, где целочисленные значения ACol, ARow указывают позицию элемента.
Внимание! Первый индекс ACol определяет номер столбца, а второй ARow - номер строки в отличие от индексов массива.
В инспекторе объектов значения ColCount и RowCount устанавливают начальные значения количества столбцов и строк в таблице, а FixedCols и FixedRows задают количество столбцов и строк фиксированной зоны. Фиксированная зона выделена другим цветом и обычно используется для надписей.
5.3 Пример выполнения задания
Удалить из массива А размером N, состоящего из целых чисел (положительных и отрицательных), все отрицательные числа. Новый массив не создавать. Для заполнения массива использовать фунцию random(kod) - генератор случайных равномерно распределенных целых чисел от 0 до (int)kod.
5.3.1 Пример создания оконного приложения
Значение N вводить из Edit, значения массива А - из компоненты StringGrid. Результат вывести в компоненту StringGrid.
Панель диалога и результаты выполнения программы приведена на рис. 5.1.
Рис. 5.1
Настройка компоненты StringGrid
На закладке Additional выберите пиктограмму , установите компоненты StringGrid1 и StringGrid2 и отрегулируйте их размеры. В инспекторе объектов для обоих компонент установите значения ColCount равными 2, RowCount равными 1, т.е. по два столбца и одной строке, а значения FixedCols и FixedRows равными 0. Значение ширины клетки столбца DefaultColWidth равным 40.
По умолчанию в компоненту StringGrid ввод данных разрешен только программно. Для разрешения ввода данных с клавиатуры необходимо в свойстве Options строку goEditing для компоненты StringGrid1 установить в положение true.
Текст функций-обработчиков может иметь следующий вид:
. . .
int n = 4;
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
randomize();// Изменение начального адреса для random()
Edit1->Text=IntToStr(n);
StringGrid1->ColCount=n;
for(int i=0; i<n;i++) // Заполнение массива А случайными числами
StringGrid1->Cells[i][0] = IntToStr(random(21)-10);
Label3->Hide(); // Скрыть компоненту
StringGrid2->Hide();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
n=StrToInt(Edit1->Text);
if(n>10){
ShowMessage("Максимальное количество 10!");
n=10;
Edit1->Text = "10";
}
StringGrid1->ColCount=n;
for(int i=0; i<n;i++)
StringGrid1->Cells[i][0]=IntToStr(random(21)-10);
Label3->Hide();
StringGrid2->Hide();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
int i, kol = 0, a[10]; // Декларация одномерного массива
//Заполнение массива А элементами из таблицы StringGrid1
for(i=0; i<n;i++)
a[i]=StrToInt(StringGrid1->Cells[i][0]);
//Удаление отрицательных элементов из массива А
for(i=0; i<n;i++)
if(a[i]>=0) a[kol++] = a[i];
StringGrid2->ColCount = kol;
StringGrid2->Show(); // Показать компоненту
Label3->Show();
//Вывод результата в таблицу StringGrid2
for(i=0; i<kol;i++) StringGrid2->Cells[i][0]=IntToStr(a[i]);
}
5.3.2 Пример создания консольного приложения
Текст программы может иметь следующий вид (обратите внимание на то, что функция main используется в простейшей форме - без параметров и не возвращает результатов):
. . .
#include <stdio.h>
#include <conio.h>
void main()
{
int a[10],n, i, kol=0;
randomize(); // Изменение начального адреса для random()
printf("Input N (<=10) ");
scanf("%d", &n);
puts("\n Massiv A");
for(i=0; i<n;i++) {
a[i] = random(21)-10; // Заполнение массива А случайными числами printf("%4d", a[i]);
}
//Удаление отрицательных элементов из массива А
for(i=0; i<n;i++)
if(a[i]>=0) a[kol++] = a[i];
puts("\n Rezult massiv A");
for(i=0; i<kol;i++) printf("%4d", a[i]);
puts("\n Press any key ... ");
getch();
}
С заполненным случайными числами массивом А результат программы может быть следующим:
5.4 Индивидуальные задания
Написать программу по обработке одномерных массивов. Размеры массивов вводить с клавиатуры. В консольном приложении предусмотреть возможность ввода данных как с клавиатуры, так и с использованием функции random().
При создании оконного приложения скалярный (простой) результат выводить в виде компоненты Label, а массивы вводить и выводить с помощью компонент StringGrid.
В одномерном массиве, состоящем из n вводимых с клавиатуры целых элементов, вычислить:
1. Произведение элементов массива, расположенных между максимальным и минимальным элементами.
2. Сумму элементов массива, расположенных между первым и последним нулевыми элементами.
3. Сумму элементов массива, расположенных до последнего положительного элемента.
4. Сумму элементов массива, расположенных между первым и последним положительными элементами.
5. Произведение элементов массива, расположенных между первым и вторым нулевыми элементами.
6. Сумму элементов массива, расположенных между первым и вторым отрицательными элементами.
7. Сумму элементов массива, расположенных до минимального элемента.
8. Сумму модулей элементов массива, расположенных после последнего отрицательного элемента.
9. Сумму элементов массива, расположенных после последнего элемента, равного нулю.
10. Сумму модулей элементов массива, расположенных после минимального по модулю элемента.
11. Сумму элементов массива, расположенных после минимального элемента.
12. Сумму элементов массива, расположенных после первого положительного элемента.
13. Сумму модулей элементов массива, расположенных после первого отрицательного элемента.
14. Сумму модулей элементов массива, расположенных после первого элемента, равного нулю.
15. Сумму положительных элементов массива, расположенных до максимального элемента.
16. Произведение элементов массива, расположенных между первым и последним отрицательными элементами.
6. Обработка двухмерных динамических массивов
Цель работы: изучить понятие «указатель», правила создания и приемы обработки динамических массивов на примере двухмерного массива.
6.1 Краткие теоретические сведения
Особенности применения указателей
Обращение к объектам любого типа в языке C может проводиться по имени, как мы до сих пор делали, и по указателю (косвенная адресация).
Указатель - это переменная, которая может содержать адрес некоторого объекта в памяти компьютера, например, адрес другой переменной. Через указатель, установленный на переменную, можно обращаться к участку оперативной памяти (ОП), отведенной компилятором под ее значение. приложение алгоритм массив файл
Указатель объявляется следующим образом:
тип * ID указателя;
Перед использованием указатель должен быть инициирован либо конкретным адресом, либо значением NULL (0) - отсутствие указателя.
С указателями связаны две унарные операции: & и *. Операция & означает «взять адрес», а операция разадресации * - «значение, расположенное по адресу», например:
int x,*y;// х - переменная типа int , у - указатель типа int
y = &x; // y - адрес переменной x
*y = 1; // по адресу y записать 1, в результате x = 1
При работе с указателями можно использовать операции сложения, вычитания и сравнения, причем выполняются они в единицах того типа, на который установлен указатель.
Операции сложения, вычитания и сравнения (больше/меньше) имеют смысл только для последовательно расположенных данных - массивов. Операции сравнения «==» и «!=» имеют смысл для любых указателей, т.е. если два указателя равны между собой, то они указывают на одну и ту же переменную.
Связь указателей с массивами
Указатели и массивы тесно связаны между собой. Идентификатор массива является указателем на его первый элемент, т.е. для массива int a[10], выражения a и a[0] имеют одинаковые значения, т.к. адрес первого (с индексом 0) элемента массива - это адрес начала размещения его элементов в ОП.
Пусть объявлены - массив из 10 элементов и указатель типа double:
double a[10], *p;
если p = a; (установить указатель p на начало массива a), то следующие обращения: a[i] , *(a+i) и *(p+i) эквивалентны, т.е. для любых указателей можно использовать две эквивалентные формы доступа к элементам массива: a[i] и *(a+i). Очевидна эквивалентность следующих выражений:
&a[0] &(*p) p
Декларация многомерного массива:
тип ID[размер 1][размер 2]…[размер N];
причем быстрее изменяется последний индекс, т.к. многомерные массивы размещаются в ОП в последовательности столбцов, например, массив целого типа, состоящий из двух строк и трех столбцов (с инициализацией начальных значений)
int a[2][3] = {{0,1,2},{3,4,5}};
в ОП будет размещен следующим образом:
a[0][0]=0, a[0][1]=1, a[0][2]=2, a[1][0]=3, a[1][1]=4, a[1][2]=5.
Если в списке инициализаторов данных не хватает, то соответствующему элементу присваивается значение 0.
Указатели на указатели
Связь указателей и массивов с одним измерением справедливо и для массивов с бульшим числом измерений.
Если рассматривать предыдущий массив (int a[2][3];) как массив двух массивов размерностью по три элемента каждый, то обращение к элементу а[i][j] соответствует эквивалентное выражение *(*(а+i)+j), а объявление этого массива с использованием указателей будет иметь вид
int **а;
Таким образом, имя двухмерного массива - ID указателя на указатель.
Динамическое размещение данных
Для создания массивов с переменной размерностью используется динамическое размещение данных, декларируемых указателями.
Для работы с динамической памятью используются стандартные функции библиотеки alloc.h:
void *malloc(size) и void *calloc(n, size) - выделяют блок памяти размером size и nsize байт соответственно; возвращают указатель на выделенную область, при ошибке - значение NULL;
void free(bf); - освобождает ранее выделенную память с адресом bf.
Другим, более предпочтительным подходом к динамическому распределению памяти является использование операций языка С++ new и delete.
Операция new возвращает адрес ОП, отведенной под динамически размещенный объект, при ошибке - NULL, а операция delete освобождает память.
Минимальный набор действий, необходимых для динамического размещения одномерного массива действительных чисел размером n:
double *а;
. . .
а = new double[n];// Захват памяти для n элементов
. . .
delete []а; // Освобождение памяти
Минимальный набор действий, необходимых для динамического размещения двухмерного массива действительных чисел размером nm:
int i, n, m; // n, m - размеры массива
double **a;
a = new double *[n]; // Захват памяти под указатели
for(i=0; i<n; i++) a[i] = new double [m]; // и под элементы
. . .
for(i=0; i<n; i++) delete []a[i]; // Освобождение памяти
delete []a;
Для современных компиляторов (версий старше «6») для освобождения памяти достаточно записать только delete []a;
6.2 Пример выполнения задания
Рассчитать значения вектора , где А - квадратная матрица размером NN, а Y и B - одномерные массивы размером N. Элементы вектора Y определяются по формуле
.
6.2.1 Пример создания оконного приложения
Значение N вводить из Edit, А и B - из компонент StringGrid. Результат вывести в компоненту StringGrid.
Панель диалога и результаты выполнения программы приведена на рис. 6.1.
Рис. 6.1
Настройка компонент StringGrid
Для компоненты StringGrid1 значения ColCount и RowCount установите равными, например, 3 - три столбца и три строки, а FixedCols и FixedRows - 1.
Так как компоненты StringGrid2 и StringGrid3 имеют только один столбец, то у них ColCount = 1, RowCount = 3, а FixedCols = 0 и FixedRows = 1.
В свойстве Options строку goEditing для компонент StringGrid1 и StringGrid2 установите в положение true.
Для изменения размера n используется функция-обработчик EditChange, полученная двойным щелчком по компоненте Edit.
Текст программы может иметь следующий вид:
. . .
//---------------------- Глобальные переменные -------------------
int n = 3;
double **a, *b; // Декларации указателей
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Edit1->Text=IntToStr(n);
StringGrid1->ColCount = n+1; StringGrid1->RowCount = n+1;
StringGrid2->RowCount = n+1; StringGrid3->RowCount = n+1;
// Ввод в левую верхнюю ячейку таблицы названия массивов
StringGrid1->Cells[0][0] = "Матрица A";
StringGrid2->Cells[0][0] = "Массив B";
StringGrid3->Cells[0][0] = "Массив Y";
for(int i=1; i<=n;i++){
StringGrid1->Cells[0][i]="i="+IntToStr(i);
StringGrid1->Cells[i][0]="j="+IntToStr(i);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1Change(TObject *Sender)
{
int i;
n=StrToInt(Edit1->Text);
StringGrid1->ColCount = n+1; StringGrid1->RowCount = n+1;
StringGrid2->RowCount = n+1; StringGrid3->RowCount = n+1;
for(i=1; i<=n;i++){
StringGrid1->Cells[0][i]="i="+IntToStr(i);
StringGrid1->Cells[i][0]="j="+IntToStr(i);
}
/---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double s;
int i,j;
a = new double*[n]; // Захват памяти под указатели
for(i=0; i<n;i++) a[i] = new double[n]; // Захват памяти под элементы
b = new double[n];
// Заполнение массивов А и В элементами из таблиц StringGrid1 и StringGrid2
for(i=0; i<n;i++) {
for(j=0; j<n;j++) a[i][j]=StrToFloat(StringGrid1->Cells[j+1][i+1]);
b[i]=StrToFloat(StringGrid2->Cells[0][i+1]);
}
// Умножение строки матрицы А на вектор В и вывод результата s в StringGrid3
for(i=0; i<n;i++){
for(s=0, j=0; j<n;j++) s += a[i][j]*b[j];
StringGrid3->Cells[0][i+1] = FloatToStrF(s, ffFixed,8,2);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
delete []a;
delete []b;
ShowMessage("Память освобождена!");
Close();
}
6.2.2 Пример создания консольного приложения
Текст программы может иметь следующий вид:
. . .
void main()
{
double **a, *b, s;
int i, j, n;
printf(" Input size N : "); scanf("%d",&n);
a = new double*[n]; // Захват памяти под указатели
for(i=0; i<n;i++)
a[i] = new double[n]; // Захват памяти под элементы
b = new double[n];
puts("\n Input Massiv A:");
for(i=0; i<n;i++)
for(j=0; j<n;j++) scanf("%lf", &a[i][j]);
puts("\n Input Massiv B:");
for( i=0; i<n;i++) scanf("%lf", &b[i]);
puts("\n Massiv Y:");
for(i=0; i<n;i++){
for(s=0, j=0; j<n;j++) s+=a[i][j]*b[j];
printf(" %8.2lf ", s);
}
delete []a;
delete []b;
puts("\n Delete !");
puts("\n Press any key ... ");
getch();
}
При вводе значений элементов массивов в одной строке через пробелы должен получиться следующий результат:
6.3 Индивидуальные задания
Написать программу по обработке динамических массивов. Размеры массивов вводить с клавиатуры. При создании оконного приложения скалярный (простой) результат выводить в виде компоненты Label, а массивы вводить и выводить с помощью компонент StringGrid, в которых 0-й столбец и 0-ю строку использовать для отображения индексов массивов.
1. Из матрицы размером NM получить вектор B, присвоив его k-му элементу значение 0, если все элементы k-го столбца матрицы нулевые, иначе 1.
2. Из матрицы размером NM получить вектор B, присвоив его k-му элементу значение 1, если элементы k-й строки матрицы упорядочены по убыванию, иначе 0.
3. Из матрицы размером NM получить вектор B, присвоив его k-му элементу значение 1, если k-я строка матрицы симметрична, иначе значение 0.
4. Задана матрица размером NM. Определить количество «особых» элементов матрицы, считая элемент «особым», если он больше суммы остальных элементов своего столбца.
5. Задана матрица размером NM. Определить количество элементов матрицы, у которых слева находится элемент больше его, а справа - меньше.
6. Задана матрица размером NM. Определить количество различных значений матрицы, т.е. повторяющиеся элементы считать один раз.
7. В матрице размером NM упорядочить строки по возрастанию их первых элементов.
8. В матрице размером NM упорядочить строки по возрастанию суммы их элементов.
9. В матрице размером NM упорядочить строки по возрастанию их наибольших элементов.
10. Определить, является ли квадратная матрица симметричной относительно побочной диагонали.
11. Задана матрица размером NM. Определить количество элементов матрицы, у которых слева находится элемент меньше его, а справа - больше.
12. В квадратной матрице найти произведение элементов, лежащих выше побочной диагонали.
13. В квадратной матрице найти максимальный среди элементов, лежащих ниже побочной диагонали.
14. В матрице размером NM поменять местами строку, содержащую элемент с наибольшим значением со строкой, содержащей элемент с наименьшим значением.
15. Из матрицы размером n получить матрицу размером n-1 путем удаления строки и столбца, на пересечении которых расположен элемент с наибольшим по модулю значением.
16. В матрице размером n найти сумму элементов, лежащих ниже главной диагонали, и произведение элементов, лежащих выше главной диагонали.
7. Использование строк
Цель работы: изучить особенности строковых данных, правила работы с компонентами ListBox и СomboBox. Написать и отладить программу работы со строками.
7.1 Общие теоретические сведения
Строки как одномерные массивы символов
В языке С/С++ строка - это одномерный массив символов, заканчивающийся нулевым байтом, каждый бит которого равен нулю, при этом для нулевого байта определена константа ґ\0ґ (признак окончания строки или нуль-терминатор).
Для строки, состоящей из 80 символов, в описании массива необходимо указать размер 81, т.к. последний байт отведится под нуль-терминатор.
Напомним, что строковая константа - это набор символов, заключенных в кавычки, например, “Лабораторная работа по строкам” (ґ\0ґ не указывается).
Строки можно инициализировать при декларации, например:
char S1[10] = ”123456789”, S2[ ] = ”12345”;
в последнем случае размер строки устанавливается по фактическому количеству.
Операции над строками рекомендуется выполнять с использованием стандартных библиотечных функций, рассмотрим наиболее часто используемые функции библиотеки string.h:
1) strcpy(S1, S2) - копирует содержимое строки S2 в строку S1;
2) strcat(S1, S2) - присоединяет строку S2 к строке S1 и помещает ее в массив, где находилась строка S1, при этом строка S2 не изменяется; нулевой байт, который завершал строку S1, заменяется первым символом строки S2;
3) strcmp(S1, S2) - сравнивает строки S1 и S2 и возвращает значение =0, если строки равны, т.е. содержат одно и то же число одинаковых символов; значение <0, если S1<S2; и значение >0, если S1>S2.
4) strlen(S) - возвращает длину строки, т.е. количество символов, начиная с первого (S[0]) и до нуль-терминатора, который не учитывается.
5) strstr(S1, S2) - указывает первое появление подстроки S2 в строке S1.
6) преобразование строки S в число (библиотека stdlib.h): целое - (int) atoi(S); длинное целое - (long) atol(S); действительное - (double) atof(S);
при возникновении ошибки данные функции возвращают значение 0;
7) преобразование числа V в строку S: целое - itoa(int V, char S, int kod); длинное целое - ltoa(long V, char S, int kod); значение параметра kod определяет выбор системы счисления для преобразования и находится в диапазоне 2kod36, для отрицательных чисел kod = 10.
7.2 Создание оконного приложения
Тип AnsiString
Тип AnsiString является основным строковым классом в Builder.
Часто используемые методы этого класса: с_str() - преобразование строки AnsiString в массив символов; Delete() - удаление символов, SubString() - копирование подстроки; Pos() - поиск позиции; Length() - определение длины строки.
Компонента ListBox
Данная компонента представляет собой список, элементы которого выбираются при помощи клавиатуры или мыши. Список элементов задается свойством Items, методы Add, Delete и Insert которого используются для добавления, удаления и вставки строк, соответственно. Объект Items хранит строки списка. Для определения номера выделенного элемента используется свойство ItemIndex.
Компонента ComboBox
Список ComboBox - комбинация списка ListBox и редактора текста Еdit, поэтому практически все свойства аналогичны. Для работы с окном редактирования используется свойство Text, как в Edit, а для работы со списком выбора - свойство Items, как в ListBox. Cуществует пять модификаций компоненты, определяемых ее свойством Style, выбрав в котором модификацию csSimple, раскрываем список, потянув его за нижнюю кромку (захватив ее мышью).
Компонента-кнопка BitBtn
Компонента BitBtn расположена на странице Additonal и представляет собой разновидность стандартной кнопки Button. Ее отличие - наличие изображения на поверхности, определяемое свойством Glyph. Кроме того, свойство Kind задает одну из 11 стандартных разновидностей кнопок, нажатие любой из них, кроме bkCustom и bkHelp, закрывает окно и возвращает в программу результат mr*** (например, bkOk - mrOk). Кнопка bkClose закрывает главное окно и завершает работу программы.
Обработка событий
Обо всех происходящих в системе событиях, таких, как создание формы, нажатие кнопки мыши или клавиатуры и т.д., ядро Windows информирует окна путем посылки соответствующих сообщений. Среда Builder позволяет принимать и обрабатывать большинство таких сообщений. Каждая компонента содержит обработчики сообщений на странице Events инспектора объектов.
Для создания обработчика события необходимо выделить нужную компоненту, далее на странице Events выбрать обработчик и двойным щелчком кнопкой мыши в белом (пустом) окошке в текст программы будет вставлена соответствующая функция. Например, выделив компоненту Form1 и выбрав обработчик OnActivate, будет вставлена функция …FormActivate(…) { }.
Каждая компонента имеет свой набор обработчиков событий, однако некоторые из них присущи большинству компонент. Рассмотрим наиболее часто применяемые события:
OnActivate - форма получает это событие при активации;
OnCreate - возникает при создании формы (Form), в обработчике события задаются действия, которые должны происходить в момент создания формы;
OnKeyPress - возникает при нажатии клавиши клавиатуры, параметр Key типа WORD содержит ASCII-код нажатой клавиши (Enter имеет код 13, Esc - 27) и обычно используется, когда необходима реакция на нажатие одной из клавиш;
OnKeyDown - возникает при нажатии клавиши клавиатуры, обработчик этого события получает информацию о нажатой клавише и состоянии клавиш Shift, Alt и Ctlr, а также о нажатой кнопке мыши;
OnKeyUp - является парным событием для OnKeyDown и возникает при отпускании ранее нажатой клавиши;
OnClick - возникает при нажатии кнопки мыши в области компоненты, а OnDblClick - при двойном щелчке кнопкой мыши в области компоненты.
7.3 Пример выполнения задания
Написать программу подсчета числа слов в строке, содержащей пробелы.
7.3.1 Создание оконного приложения
Для ввода строк и работы с ними использовать компоненту ComboBox. Ввод строки заканчивать нажатием клавиши Enter, для выхода использовать кнопку «Close». Панель диалога с результатами программы может иметь вид, представленный на рис. 7.1.
В тексте программы приведем только функции-обработчики:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormActivate(TObject *Sender)
{
Form1->ComboBox1->SetFocus(); // Передача фокуса ComboBox1
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBox1KeyDown(TObject *Sender, WORD &Key,TShiftState Shift)
{
if (Key == 13) {
ComboBox1->Items->Add(ComboBox1->Text);
// Строка из окна редактирования заносится в ComboBox1
ComboBox1->Text=""; // Очистка окна
}
}
//------------ Обработка нажатия кнопки мыши --------------------
void __fastcall TForm1::ComboBox1Click(TObject *Sender)
{
int n, i, nst;
nst = ComboBox1->ItemIndex;// Определение номера строки
String st = ComboBox1->Items->Strings[nst]; // Запись выбранной строки st
if (st[1] != ' ') n = 1; // Здесь и ниже ' ' - пробел
else n = 0;
for(i=1; i<st.Length(); i++) // Просмотр символов строки st
if(st[i] == ' ' && st[i+1] != ' ') n++;
Edit1->Text = IntToStr(n); // Вывод числа слов в Edit1
}
Рис. 7.1
7.3.2 Создание консольного приложения
Для ввода строки, содержащей пробелы используем функцию gets (см. лаб.раб. №1).
Текст функции main() может иметь следующий вид:
#include <string.h>
void main()
{
int n, i, nst, len;
char st[81];
puts(" Input string ");
gets(st);
if (st[0] != ' ') n = 1; // Здесь и ниже ' ' - пробел
else n = 0;
len = strlen(st);
for(i=1; i<=len; i++) // Просмотр символов строки
if(st[i] == ' ' && st[i+1] != ' ') n++;
printf("\n Words = %d", n); // Вывод количества слов
puts("\nPress any key ... ");
getch();
}
Результат выполнения представленной программы будет иметь следующий вид:
7.4 Индивидуальные задания
В оконном приложении исходные данные вводить из компоненты Edit в ListBox (заканчивать нажатием Enter). Скалярный результат выводить в компоненту Label. Для выхода из программы использовать кнопку «Close».
1. В строке, состоящей из групп нулей и единиц, разделенных пробелами, найти количество групп с пятью цифрами.
2. В строке, состоящей из групп нулей и единиц, найти и вывести на экран самую короткую группу.
3. В строке, состоящей из групп нулей и единиц, подсчитать количество символов в самой длинной группе.
4. В строке, состоящей из групп нулей и единиц, найти и вывести на экран группы с четным количеством символов.
5. В строке, состоящей из групп нулей и единиц, подсчитать количество единиц в группах с нечетным количеством символов.
6. Из строки, состоящей из букв, цифр, запятых, точек, знаков + и - , выделить подстроку, которая соответствует записи целого числа.
7. Из строки, состоящей из букв, цифр, запятых, точек, знаков + и - , выделить подстроку, задающую вещественное число с фиксированной точкой.
8. Из строки, состоящей из букв, цифр, запятых, точек, знаков + и - , выделить подстроку, задающую вещественное число с плавающей точкой.
9. Дана строка символов, состоящая из цифр, разделенных пробелами. Вывести на экран числа этой строки в порядке возрастания их значений.
10. Дана строка символов, состоящая из цифр, разделенных пробелами. Вывести четные числа этой строки.
11. Дана строка, состоящая из слов на английском языке, разделенных пробелами. Вывести на экран эти слова в порядке алфавита.
12. Дана строка, состоящая из слов, разделенных пробелами. Вывести на экран порядковый номер слова, содержащего k-ю позицию, если в k-й позиции пробел, то - номер предыдущего слова. Значение k ввести с клавиатуры.
13. Дана строка, состоящая из слов, разделенных пробелами. Разбить исходную строку на две подстроки, причем первая длиной k символов, если на k-ю позицию попадает слово, то его следует отнести ко второй строке. Значение k вводится с клавиатуры.
14. Дана строка, состоящая из слов, разделенных пробелами. Вывести на экран порядковый номер слова максимальной длины и номер позиции строки с которой оно начинается.
15. Дана строка, состоящая из слов, разделенных пробелами. Вывести на экран порядковый номер слова минимальной длины и количество символов в этом слове.
16. В строке символов посчитать количество скобок различного вида.
8. Обработка структур с использованием файлов
Цель работы: изучить правила создания и обработки данных структурного типа с использованеием файлов; правила работы с компонентами OpenDialog и SaveDialog; написать и отладить программу по созданию файлов.
8.1 Теоретические сведения
Структура объединяет логически связанные данные разных типов. Структурный тип данных определяется описанием шаблона:
struct Рerson {
char Fio[30];
double sball;
};
Объявление переменных созданного структурного типа:
Person Stud, *p_Stud;
Обращение к элементам структур производится посредством:
1) операции принадлежности ( . ) в виде:
ID_структуры . ID_поля или (*указатель) . ID_поля
2) операции косвенной адресации (->) в виде:
указатель -> ID_поля или &(ID_структуры) . ID_поля
Для приведенного выше примера
1) Stud.Fio = “Иванов А.И.”; //Инициализация данных
Stud.sball = 5.75;
2)р_Stud -> Fio = “Иванов А.И.”;
р_Stud -> sball =5.75;
В языке C/С++ файл рассматривается как поток (stream), представляющий собой последовательность считываемых или записываемых байт. При этом последовательность записи определяется самой программой.
Работа с файлами
Файл - это набор данных, размещенный на внешнем носителе и рассматриваемый в процессе обработки и пересылке как единое целое. Прототипы большинства функций по обработке файлов описаны в библиотеках stdio.h и io.h.
Прежде чем работать с файлом, его нужно открыть для доступа, т.е. создать и инициализировать область данных, которая содержит информацию о файле: имя, путь и т.д. В языке С/С++ это выполняет функция fopen(), которая связывает физический файл на носителе с логическим именем в программе. Логическое имя - это указатель на файл, т.е. на область памяти, где хранится информация о файле. Указатели на файлы необходимо декларировать:
FILE *указатель на файл;
Формат функции
fopen( “строка 1” , “строка 2” );
в строке 1 указывается место, в которое мы собираемся поместить файл, например: “d:\\work\\sved.txt” - файл с именем sved.txt, который будет находиться на диске d, в папке work; если путь к файлу не указывать, то он будет размещен в рабочей папке проекта.
В строке 2 указывается код открытия файла:
w - для записи, если файла с заданным именем нет, то он будет создан, если же такой файл существует, то перед открытием прежняя информация уничтожается;
r - для чтения; если файла нет, то возникает ошибка;
a - для добавления новой информации в конец;
r+, w+ - возможны чтение и запись информации;
a+ - то же, что и для a, только запись можно выполнять в любое место файла, доступно и чтение файла.
По умолчанию файл открывается в текстовом режиме (t), указав b - файл открывается в двоичном режиме.
Если при открытии файла произошла ошибка, функция fopen возвращает значение NULL.
После работы доступ к файлу необходимо закрыть с помощью функции fclose(указатель файла), например, fclose ( f );
Для закрытия нескольких файлов введена функция: void fcloseall(void);
Приведем пример минимального набора операторов, необходимых для корректной работы с файлом:
#include <stdio.h>
. . .
FILE *f_my;
if( ! ( f_my = fopen(“rez.txt”, “r+t” ) ) ) {
puts(“\n Ошибка открытия файла!”);
// В оконном режиме - ShowMessage("Ошибка открытия файла");
return;
}
. . . / Работа с файлом
fclose(f_my);
. . .
Для работы с текстовыми файлами в консольном приложении удобнее всего пользоваться функциями fprintf() и fscanf(), параметры и выполняемые действия аналогичны функциям printf() и scanf(), (см. лаб.раб.№1), только первым параметром добавлен указатель файла, к которому применяется данная функция.
Функции работы с текстовыми файлами удобны при создании результирующих файлов для отчетов по лабораторным и курсовым работам.
Для создания баз данных удобнее пользоваться функциями работы с бинарными файлами. Рассмотрим некоторые из них, обозначив указатель файла - fp (FILE *fp;):
1) int fread(void *ptv, int size, int n, fp) - считывает n блоков по size байт каждый из файла fp в область памяти, на которую указывает ptv (необходимо заранее отвести память под считываемый блок);
2) int fwrite(void *ptv, int size, int n, fp) - записывает n блоков по size байт каждый из области памяти, на которую указывает ptv в файл fp;
3) int fileno(fp) - возвращает значение дескриптора файла fp (дескриптор -число, определяющее номер файла);
4) long filelength(int дескриптор) - возвращает длину файла в байтах;
5) int chsize(int дескриптор, long pos) - выполняет изменение размера файла fp, признак конца файла устанавливается после байта с номером pos;
6) int fseek(fp, long size, int kod) - выполняет смещение указателя на size байт в направлении признака kod: 0 - от начала файла; 1 - от текущей позиции; 2 - от конца файла;
7) long ftell(fp) - возвращает значение указателя на текущую позицию файла fp (-1 - ошибка);
8) int feof(указатель файла) - возвращает ненулевое значение при правильной записи признака конца файла;
9) int fgetpos(указатель файла, long *pos) - определяет значение текущей позиции pos файла; при успешном завершении возвращает значение 0.
8.2 Создание оконного приложения
Компоненты OpenDialog и SaveDialog
Компоненты OpenDialog и SaveDialog находятся на странице Dialogs. Все компоненты этой страницы невизуальны, т.е. не видны при работе программы, поэтому их размещают в любом месте формы. Обе компоненты имеют идентичные свойства.
После вызова компоненты появляется стандартное диалоговое окно, с помощью которого выбирается имя программы и путь к ней. В случае успешного завершения диалога имя выбранного файла и его размещение содержaтся в FileName. Для выбора файлов, отображаемых в окне просмотра, используется свойство Filter, а для изменения заголовка окна - используется свойство Title.
8.3 Пример выполнения задания
Написать программу обработки файла, содержащего информацию о рейтинге студентов. Каждая запись должна содержать Ф.И.О. и полученный балл рейтинга. Вывести информацию, отсортированную в порядке увеличения рейтинга. Результаты выполнения программы сохранить в текстовом файле. При работе с файлом должны быть выполнены следующие действия: создание, просмотр, добавление новой записи, сортировка, сохранение результатов.
8.3.1 Создание оконного приложения
Настройка компонент OpenDialog и SaveDialog
На странице Dialogs выбрать пиктограммы , для установки компонент OpenDialog и SaveDialog соответственно.
Для выбора нужных файлов установить фильтры следующим образом: выбрав компоненту, дважды щелкнуть кнопкой мыши по правой части свойства Filter инспектора объектов, и в появившемся окне Filter Editor, в левой части записать текст, характеризующий выбор, в правой части - маску. Для OpenDialog1 установить значения маски, как показано на рис. 8.1. Формат *.dat означает, что будут видны все файлы с расширением dat, а формат *.* - будут видны все файлы (с любыми именами и расширениями).
Рис. 8.1
Для того чтобы файл автоматически записывался с расширением dat, в свойстве DefaultExt записать требуемое расширение - .dat.
Аналогичным образом настраивается SaveDialog1 для текстового файла, который будет иметь расширение .txt.
Работа с программой
Форма может иметь вид, представленный на рис. 8.2.
Кнопку «Создать» нажимаем только при первом запуске программы или, если захотим заменить прежнюю информацию на новую, в окне Memo1 отображается путь и имя созданного файла.
Заполнив оба поля информацией, нажимаем кнопку «Добавить», после чего введенная информация отображается в окне Memo1.
Для работы с уже созданным файлом нажимаем кнопку «Открыть» - в Memo1 выводится содержимое всего файла, после чего можно добавлять новые данные в конец этого файла, не уничтожая предыдущие.
При нажатии кнопки «Сортировать» в Memo1 выводятся записи, сортированные по возрастанию рейтинга.
Подобные документы
Разработка приложения "Ведомость начисления заработной платы" в среде программирования C++Builder. Алгоритм и сценарий работы программы. Проектирование интерфейса пользователя. Написание программных модулей и результаты тестирования данной программы.
курсовая работа [597,4 K], добавлен 31.01.2016Визуальное проектирование и событийное программирование. Повышение производительности программиста при использовании RAD-систем. Составление алгоритмов, разработка приложения для решения прикладных задач на примере консольных приложений C++ Builder 6.
курсовая работа [258,7 K], добавлен 30.10.2013Организация файлов и доступ к ним. Файловые операции. Программирование с использованием встроенных функций ввода-вывода; линейных, разветвляющихся и циклических вычислительных процессов с использованием If-else, оператора выбора Case; массивов и матриц.
курсовая работа [5,8 M], добавлен 24.05.2014Основные операции над матрицами. Формирование матрицы из файла. Ввод матрицы с клавиатуры. Заполнение матрицы случайными числами. Способы формирования двухмерных массивов в среде программирования С++. Произведение определенных элементов матрицы.
курсовая работа [537,0 K], добавлен 02.06.2015Понятие массива и правила описания массивов в программах на языке С. Рассмотрение основных алгоритмов обработки одномерных массивов. Примеры программ на языке С для всех рассмотренных алгоритмов. Примеры решения задач по обработке одномерных массивов.
учебное пособие [1,1 M], добавлен 22.02.2011Основные типы циклов программирования. Методы применения специальных функций break, continue и цикла while. Обработка массивов информации. Условия применения циклических алгоритмов на языке программирования С++. Инициализация одномерного массива.
курсовая работа [1,7 M], добавлен 06.01.2014Разработка и реализация типовых алгоритмов обработки одномерных массивов на языке Delphi. Максимальный и минимальный элемент массива. Значение и расположение элементов массива. Элементы массива, находящиеся перед максимальным или минимальным элементом.
лабораторная работа [12,8 K], добавлен 02.12.2014Ознакомление с особенностями программной реализации алгоритмов преобразования одномерных массивов. Исследование развития вычислительной техники, которое подразумевает использование компьютерных и информационных технологий. Изучение интерфейса программы.
курсовая работа [1,0 M], добавлен 02.06.2017Краткая характеристика интегрированной среды Turbo Pascal. Принципы программирования разветвляющихся алгоритмов, циклических структур, задач обработки символьных данных, множеств. Правила записи данных в текстовый файл. Понятие явной и косвенной рекурсии.
учебное пособие [1,5 M], добавлен 10.12.2010Обработка сложных структур данных как одна из наиболее распространенных возможностей применения языка программирования С++. Преимущества использования подпрограмм. Передача параметров, одномерных и двумерных массивов, функции и их возврат в функцию.
курсовая работа [1,1 M], добавлен 24.11.2013