Л5_для Teams. Лабораторная работа 5. Обработка одномерных массивов Цель работы
Скачать 64.92 Kb.
|
Лабораторная работа №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 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 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 a[i]=StrToInt(StringGrid1->Cells[i][0]); //Удаление отрицательных элементов из массива А for(i=0; i if(a[i]>=0) a[kol++] = a[i]; StringGrid2->ColCount = kol; StringGrid2->Show(); // Показать компоненту Label3->Show(); //Вывод результата в таблицу StringGrid2 for(i=0; i } 5.3.2. Пример создания консольного приложенияТекст программы может иметь следующий вид (обратите внимание на то, что функция main используется в простейшей форме – без параметров и не возвращает результатов): . . . #include #include 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 a[i] = random(21)-10; // Заполнение массива А случайными числами printf("%4d", a[i]); } //Удаление отрицательных элементов из массива А for(i=0; i if(a[i]>=0) a[kol++] = a[i]; puts("\n Rezult massiv A"); for(i=0; i puts("\n Press any key ... "); getch(); } С заполненным случайными числами массивом А результат программы может быть следующим: 5.4. Индивидуальные заданияНаписать программу по обработке одномерных массивов. Размеры массивов вводить с клавиатуры. Предусмотреть возможность ввода данных как с клавиатуры, так и с использованием функции random(). При создании оконного приложения скалярный (простой) результат выводить в виде компоненты Label, а массивы вводить и выводить с помощью компонент StringGrid. В одномерном массиве, состоящем из n вводимых с клавиатуры целых элементов, вычислить: Произведение элементов массива, расположенных между максимальным и минимальным элементами. Сумму элементов массива, расположенных между первым и последним нулевыми элементами. Сумму элементов массива, расположенных до последнего положительного элемента. Сумму элементов массива, расположенных между первым и последним положительными элементами. Произведение элементов массива, расположенных между первым и вторым нулевыми элементами. Сумму элементов массива, расположенных между первым и вторым отрицательными элементами. Сумму элементов массива, расположенных до минимального элемента. Сумму целых частей элементов массива, расположенных после последнего отрицательного элемента. Сумму элементов массива, расположенных после последнего элемента, равного нулю. Сумму модулей элементов массива, расположенных после минимального по модулю элемента. Сумму элементов массива, расположенных после минимального элемента. Сумму элементов массива, расположенных после первого положительного элемента. Сумму модулей элементов массива, расположенных после первого отрицательного элемента. Сумму модулей элементов массива, расположенных после первого элемента, равного нулю. Сумму положительных элементов массива, расположенных до максимального элемента. Произведение элементов массива, расположенных между первым и последним отрицательными элементами. Лабораторная работа №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 a[i] = new double [m]; // и под элементы . . . for(i=0; i 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 b = new double[n]; // Заполнение массивов А и В элементами из таблиц StringGrid1 и StringGrid2 for(i=0; i for(j=0; j b[i]=StrToFloat(StringGrid2->Cells[0][i+1]); } // Умножение строки матрицы А на вектор В и вывод результата s в StringGrid3 for(i=0; i for(s=0, j=0; j StringGrid3->Cells[0][i+1] = FloatToStrF(s, ffFixed,8,2); } } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { for(int i=0; i delete []a; delete []b; ShowMessage("Память освобождена!"); Close(); } 4.3.2. Пример создания консольного приложенияТекст программы может иметь следующий вид: . . . void main() { double **a, *b, s; int i, j, n; puts("Input size N < 10"); scanf("%d",&n); a = new double*[n]; // Захват памяти под указатели for(i=0; i b = new double[n]; // Захват памяти под элементы puts("\nInput Massiv A:"); for(i=0; i for(j=0; j puts("\nInput Massiv B:"); for( i=0; i puts("\nMassiv Y:"); for(i=0; i for(s=0, j=0; j s+=a[i][j]*b[j]; printf(" %8.2lf ", y[i]); } puts("\nPress 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 найти сумму элементов, лежащих ниже главной диагонали, и произведение элементов, лежащих выше главной диагонали. |