Лабораторная работа № 6. Двумерные массивы
Продолжительность – 4 часа.
Максимальный рейтинг – 8 баллов.
Цель работы
Освоить способ динамического захвата и освобождения памяти под двумерные массивы данных (матрицы) – при помощи оператора new и посредством функций malloc() и calloc(). Повторить понятия, операции и закрепить умения и навыки матричной алгебры. Уяснить практическую разницу и сходство в языке С++ понятий «массив» и «указатель». Повысить навыки отладки программного кода на С++, трассировки программы и просмотра значений переменных в окне Watch.
Задание на лабораторную работу
1. Написать, отладить и протестировать программу, выполняющую следующие операции с одномерными и многомерными массивами данных (в соответствии со своим вариантом, см. Таблица 6)
2. Во втором столбце таблицы индивидуальных заданий (Таблица 6) – способ выделения памяти под матрицу: 1 – хранение матрицы в памяти построчно в виде одномерного массива (как на Рис. 18); 2 – массив указателей, содержащий адреса строк матрицы (как на Рис. 19).
3. Операции выделения памяти под матрицы и вектора, вывод на экран, операции матричной арифметики, освобождение памяти и т.п. организовать в виде подпрограмм (функций).
4. При выполнении операции обращения к элементам матрицы обеспечить защиту от выхода за границы диапазона строк и столбцов.
5. При выполнении операций матричной алгебры размерность вектора и второй матрицы задать самостоятельно таким образом, чтобы была возможность эти операции производить. Организовать в подпрограммах проверку корректности размерностей матриц: при произведении – проверять сцепленность матриц, при сложении – совпадение размерностей.
6. При демонстрации преподавателю работающей программы необходимо провести пошаговую трассировку указанного преподавателем участка программы с комментариями производимых программой действий. При трассировке адреса динамических переменных и их значения необходимо выводить в окне Watch.
7. По выполненной лабораторной работе подготовить отчет, включающий блок-схемы алгоритмов процедур и рисунок, отражающий распределение памяти под матрицу. Отчет в обязательном порядке снабдить комментариями.
8. Повышенный балл выставляется за выполнение программы с контролем адресов и выделяемой под динамические объекты памяти.
Варианты индивидуальных заданий к лабораторной работе содержит Таблица 6.
Таблица 6. Варианты индивидуальных заданий к лабораторной работе №
| cпособ выделения памяти
| тип данных элементов матрицы
| размерность массива А
[NxM]
| операции с вектором х
| операции с матрицами
А и В
| вычислить
|
1.
|
| double
| [6,6]
| 3x*A
| А+2*B
| сумму элементов основной диагонали
|
2.
|
| unsigned long
| [6,5]
| A*2x
| A-4*B
| сумму элементов последнего столбца
|
3.
|
| int
| [5,5]
| x*3A
| 2*(A+B)
| произведение элементов основной диагонали
|
4.
|
| unsigned int
| [4,5]
| 4A*x
| 3*(A-B)
| произведение элементов последнего столбца
|
5.
|
| long
| [3,5]
| 4x*A
| 2*A+3*B
| сумму элементов основной диагонали
|
6.
|
| unsigned long
| [2,5]
| A*5x
| 3*A-2*B
| произведение элементов первой строки
|
7.
|
| float
| [6,4]
| x*2A
| B-3*A
| сумму элементов первой строки
|
8.
|
| double
| [5,4]
| 3A*x
| B+4*A
| минимальный элемент последней строки
|
9.
|
| int
| [4,4]
| 4x*A
| 3*B-A
| удвоенную сумму элементов основной диагонали
|
10.
|
| unsigned int
| [3,4]
| A*6x
| 5*B+2*A
| максимум сумм элементов строк
|
11.
|
| float
| [2,4]
| x*5A
| 3*(В+A)
| максимальный элемент первой строки
|
12.
|
| double
| [6,3]
| 3A*x
| 4*(B-A)
| минимум сумм элементов строк
|
13.
|
| int
| [5,3]
| 4x*A
| 3*B-2*A
| максимальный элемент последней строки
|
14.
|
| unsigned int
| [4,3]
| A*4x
| 5*B-4*A
| максимум сумм элементов столбцов
|
15.
|
| float
| [3,3]
| x*3A
| А+3*B
| утроенное произведение элементов основной диагонали
|
16.
|
| double
| [2,3]
| 2A*x
| A-5*B
| минимальный элемент первой строки
|
17.
|
| long
| [6,2]
| 6x*A
| 4*(A+B)
| минимум сумм элементов в столбцах
|
18.
|
| unsigned long
| [5,2]
| A*5x
| 2*(A-B)
| максимум произведений элементов по столбцам
|
19.
|
| float
| [4,2]
| x*4A
| 4*A+3*B
| минимальный элемент первого столбца
|
20.
|
| double
| [3,2]
| 3A*x
| 3*A-4*B
| максимум произведений элементов по строкам
|
21.
|
| int
| [2,2]
| 2x*A
| B-5*A
| сумму элементов дополнительной диагонали
|
22.
|
| unsigned int
| [3,3]
| A*3x
| B+2*A
| минимальный элемент последнего столбца
|
23.
|
| float
| [3,4]
| x*4A
| 4*B-A
| минимум произведений элементов в столбцах
|
24.
|
| double
| [3,5]
| 5A*x
| 3*B+2*A
| максимальный элемент последнего столбца
|
25.
|
| long
| [3,6]
| 6x*A
| 2*(В+A)
| утроенную сумму элементов первого столбца
|
26.
|
| unsigned long
| [4,4]
| A*5x
| 5*(B-A)
| сумму элементов дополнительной диагонали
|
27.
|
| float
| [4,5]
| x*4A
| 6*B-3*A
| максимальный элемент первого столбца
|
28.
|
| double
| [4,6]
| 3A*x
| 2*B-3*A
| минимум произведений элементов в строках
|
Работа со строками
- Эй, очкарик! Как пройти в библиотеку?
- С:WINDОWS\Sуstеm32\SYSТЕМ.dll
Строки в языке С++ позволяют работать с символьными данными и текстом.
Символьный массив
Строку символов можно хранить в виде массива элементов типа char. Переменная типа char хранит в себе 1 символ, точнее – код 1 символа. Размер массива символов для хранения такой строки должен быть на 1 больше, т.к. последний элемент массива содержит NULL (пустая переменная без значения), который обозначает символ конца строки.
Пример:
char name[50]; cin>>name; cout<<"Hello "<<name<<endl;
|
При использовании строк такого типа необходимо помнить, что компилятор языка С работает с массивами как с указателями: присваивает и сравнивает лишь адреса массивов, но не содержимое, например в результате работы данного фрагмента программы:
char name1[5]= {'к','у','-','к','у'}; char name2[5]= {'к','у','-','к','у'}; if (name1==name2) { cout << "строки равны" << endl; } else { cout << "строки НЕ равны" << endl; }
|
на экран будет выведено: "строки НЕ равны", так как полностью идентичные строки name1 и name2 имеют разные адреса в памяти.
Поэтому программисту необходимо брать на себя написание функций поэлементного (в цикле) сравнения строк, присваивания значений и объединения строк, поиска в строках символов и т.п. Кроме того, сложностью при работе со строками такой архитектуры является необходимость постоянно контролировать размер массива и невозможность его изменять.
6.2. Библиотека <string.h>
К счастью, имеется возможность использовать готовые подпрограммы для работы со строковыми переменными. Прототипы функций работы со строками содержатся в файле string.h (см. Таблица 7). Все функции работают со строками, завершающимися нулевым байтом '\0'. Для функций, возвращающих указатели, в случае ошибки возвращается NULL. Типизированный модификатор size_t определен как тип unsigned.
Таблица 7 Функции для работы со строками
Функция
| Описание
|
strcat
| char *strcat(char *dest, const char *src); конкатенация (склеивание) строки src с dest
|
strncat
| char *strncat(char *dest, const char *src, size_t maxlen); добавить не более n символов из src в dest
|
strchr
| char *strchr(const char *s, int c); найти первое вхождение символа с в строку s и вернуть указатель на найденное
|
strrchr
| char *strrchr(const char *s, int c); найти последнее вхождение символа c в строку s и вернуть указатель на найденное
|
strcmp
| int strcmp(const char *s1, const char *s2); сравнить две строки. Возвращаемое значение меньше 0, если s1 лексикографически (алфавитно) предшествует s2. Возвращается 0, если s1=s2, и возвращается число больше нуля, если s1 больше s2.
|
strncmp
| int strncmp(const char *s1, const char *s2, size_t n); сравнить две строки, учитывая не более n первых символов
|
stricmp
| int stricmp(const char *s1, const char *s2); сравнить две строки, считая латинские символы нижнего и верхнего регистров эквивалентными
|
strnicmp
| int strnicmp(const char *s1, const char *s2, size_t n); сравнить две строки по первым n символам, считая латинские символы нижнего и верхнего регистров эквивалентными
|
strcpy
| char *strcpy(char *dest, const char *src); копировать строку src в dest, включая завершающий нулевой байт
|
strncpy
| char *strncpy(char *dest, const char *src, size_t n); копировать не более n символов из src в dest
|
strdup
| char *strdup(const char *s); дублирование строки с выделением памяти
|
strlen
| size_t strlen(const char *s); возвращает длину строки в символах
|
strlwr
| char *strlwr(char *s); преобразовать строку в нижний регистр (строчные буквы)
|
strupr
| char *strupr(char *s); преобразовать строку в верхний регистр (заглавные буквы)
|
strrev
| char *strrev(char *s); инвертировать (перевернуть) строку
|
strnset
| char *strnset(char *s, int ch, size_t n); установить n символов строки s в заданное значение ch
|
strset
| char *strset(char *s, int ch); установить все символы строки s в заданное значение ch
|
strspn
| size_t strspn(const char *s1, const char *s2); ищет начальный сегмент s1, целиком состоящий из символов s2. Вернет номер позиции, с которой строки различаются.
|
strсspn
| size_t strspn(const char *s1, const char *s2); ищет начальный сегмент s1, целиком состоящий из символов, НЕ входящих в s2. Вернет номер позиции, с которой строки различаются.
|
strstr
| char *strstr(const char *s1, const char *s2); найти первую подстановку строки s2 в s1 и вернуть указатель на найденное
|
strtok
| char *strtok(char *s1, const char *s2); найти следующий разделитель из набора s2 в строке s1
|
strerror
| char *strerror(int errnum); сформировать в строке сообщение об ошибке, состоящее из двух частей: системной диагностики и необязательного добавочного пользовательского сообщения
|
Пример: дублирование строки с выделением памяти.
char *dup_str, *string = "abcde"; dup_str = strdup(string);
|
Пример иллюстрирует действие функции strtok, позволяющей разбивать строку на лексемы:
char input[16] = "abc,d"; char *p; /* strtok помещает нулевой байт вместо разделителя лексем, если поиск был успешен */ p = strtok(input, ","); printf("%s\n", p); //будет выведено "abc"; /* второй вызов использует NULL как первый параметр и возвращает указатель на следующую лексему */ p = strtok(NULL, ","); printf("%s\n", p); //будет выведено "d"
|
Разумеется, число выделяемых лексем и набор разделителей могут быть любыми. В коде, приведенном ниже, лексемы могут разделяться пробелом, запятой или горизонтальной табуляцией, а прием и синтаксический разбор строк завершается при вводе пустой строки.
#include <string.h> #include <stdio.h> #define BLANK_STRING ""
void main(void) { char *token, buf[81],*separators = "\t,. "; int i; puts("Вводите строки\n\Завершение - нажатие ENTER.\n"); while(strcmp(gets(buf),BLANK_STRING)!=0) { i = 0; token = strtok(buf, separators); while(token!= NULL) { printf("Лексема %d - %s\n", i, token); token = strtok(NULL, separators); i++; } } }
|
Воспользуйтесь поиском по сайту: