- •Глава 2 36
- •1 Задание 1 62
- •Лабораторная работа №1
- •Краткие теоретические сведения
- •1.1Создание консольного приложения
- •1.2Отладка программы
- •1.2.1Установка точек останова (Add breakpoint)
- •2.2Идентификаторы
- •2.3Ключевые слова
- •2.4Знаки операций
- •2.5Константы
- •2.6Комментарии
- •2.7.1Понятие типа данных
- •2.7.2Основные типы данных
- •2.7.3Целый тип (int).
- •2.7.4Символьный тип (char).
- •2.7.5Логический тип (bool).
- •2.7.6Вещественный тип (float, double и long double).
- •2.8Переменные
- •2.9Функции и объекты ввода/вывода
- •2.9.1Основные функции ввода/вывода в стиле с:
- •2.10Операции
- •2.10.2Операция определения размера sizeof
- •2.10.4Деление (/) и остаток от деления (%).
- •2.10.8Логические операции (&& и ||).
- •2.10.10 Условная операция (?:).
- •2.11Выражения
- •2.11.1Преобразование типов в выражении.
- •Задание к лабораторной работе №1
- •Контрольные вопросы к лабораторной работе №1
- •1.1Оператор «выражение»
- •1.2Операторы ветвления
- •1.2.1Условный оператор if... Else
- •1.2.2Об условиях в операторе if
- •1.2.3Оператор выбора switch
- •1.3Операторы передачи управления
- •1.3.1Оператор goto
- •1.3.2Оператор break
- •2 Тестирование программ
- •Домашнее Задание
- •Задание к лабораторной работе №2
- •1Задание 1
- •2Задание 2
- •Содержание отчета
- •2Операторы цикла
- •2.1Цикл с предусловием (while)
- •2.2Цикл с постусловием (do … while)
- •2.3Цикл с параметром for
- •3Дополнительные операторы передачи управления
- •3.1Оператор break
- •3.2Оператор continue
- •4Вложенные циклы
- •Домашнее Задание
- •Задание к лабораторной работе №3
- •1Задание 1
- •2Задание 2
- •Содержание отчета
- •Контрольные вопросы к лабораторной работе №3
- •4Программа пузырьковой сортировки
- •Домашнее Задание
- •Задание к лабораторной работе №4
- •Содержание отчета
- •Контрольные вопросы к лабораторной работе №4
- •0 Строка
- •1 Строка
- •5 Строка
- •2Ввод и вывод многомерных массивов
- •Домашнее Задание
- •Задание к лабораторной работе №5
- •4Ссылки
- •5Динамическое распределение памяти
- •5.1Использование стандартных функций malloc и free
- •5.2Использование операторов new и delete
- •Домашнее Задание
- •Задание к лабораторной работе № 6
- •Содержание отчета
- •Контрольные вопросы к лабораторной работе №6
- •Лабораторная работа №7 отладка программы краткие теоретические сведения
- •6Отладочные пункты меню
- •7Элементы отладки
- •7.1Контрольные точки
- •7.1.1Контрольные точки в исходном коде
- •7.1.2Адресные контрольные точки
- •7.1.3Контрольные точки данных
- •7.2Команда Run to Cursor
- •7.3Команда Pause
- •8Наблюдение за переменными
- •8.1Быстрый просмотр данных
- •9Инспектор отладки
- •9.1Инспекция локальных переменных
- •10Другие инструменты отладки
- •10.1Диалог Evaluate/Modify
- •10.2Окно cpu
- •10.3Стек вызовов
- •10.4Команда Go to Address
- •10.5Команда Program Reset
- •Задание на лабораторную работу №7
- •Контрольные вопросы к лабораторной работе №7
- •Приложение I
- •Приложение II Блоки схем алгоритмов согласно гост 19.002 – 80 и 19.003 – 80
- •Приложение III Оформление алгоритма программы в виде блок-схемы
- •Приложение IV Базовая программа для выполнения лабораторных работ
- •Приложение V
- •Приложение VI
- •Список используемых источников
Домашнее Задание
Изучите теоретические сведения текст программы по заданию на лабораторную работу. Программа записывается в «черновом» варианте в лекционной тетради. Комментарии должны составлять не менее 10% от текста. Студенты, не выполнившие домашнего задания, не допускаются к выполнению лабораторной работы.
Задание к лабораторной работе №5
Задание 1
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму положительных элементов в четных строках;
2).номера столбцов, не содержащих отрицательных элементов.
Задание 2
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму положительных элементов в нечетных строках;
2) количество строк, не содержащих ни одного нулевого элемента;
Задание 3
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму положительных элементов в четных столбцах;
2) количество столбцов, не содержащих ни одного нулевого элемента;
Задание 4
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму положительных элементов в нечетных столбцах;
2) количество столбцов, содержащих хотя бы один нулевой элемент;
Задание 5
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму отрицательных элементов в четных строках;
2) произведение элементов в тех строках, которые не содержат отрицательных элементов.
Задание 6
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму отрицательных элементов в нечетных строках;
2) сумму элементов в тех столбцах, которые не содержат отрицательных элементов.
Задание 7
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму отрицательных элементов в четных столбцах;
2) сумму элементов в тех строках, которые содержат хотя бы один отрицательный элемент.
Задание 8
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сумму отрицательных элементов в нечетных столбцах;
2) сумму элементов в тех столбцах, которые содержат хотя бы один отрицательный элемент.
Задание 9
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) максимальный элемент на главной диагонали;
2) сумму модулей элементов, расположенных выше главной диагонали.
Задание 10
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) минимальный элемент на главной диагонали;
2) количество строк, среднее арифметическое элементов которых меньше заданной величины, введенной с клавиатуры.
Задание 11
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) максимальный элемент среди элементов, расположенных выше главной диагонали;
2) номера строк, содержащих хотя бы один нулевой элемент.
Задание 12
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) максимальный элемент среди элементов, расположенных ниже главной диагонали;
2) номера столбцов, сумма элементов в которых равна нулю.
Задание 13
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) минимальный элемент в матрице и указать строку и столбец, где он находится;
2) количество строк, содержащих хотя бы один нулевой элемент.
Задание 14
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) максимальный элемент в матрице и указать строку и столбец, где он находится;
2) количество отрицательных элементов в тех строках, которые содержат хотя бы один нулевой элемент.
Задание 15
Ввести с клавиатуры вещественную матрицу размерностью 55. Определить:
1) сроку и столбец, где находится элемент, значение которого равно значению, введенному с клавиатуры;
2) сумму элементов в тех строках, которые не содержат отрицательных элементов.
Содержание отчета
Отчет выполняется по выбору преподавателя либо в редакторе Word, либо в черновом варианте в лекционной тетради. Отчет должен содержать:
Листинг программы на языке Си, решающей задачи в соответствии с вариантом (номером компьютера) задания;
Результаты тестирования программы.
Контрольные вопросы к лабораторной работе №5
Изобразите структуру двумерного массива.
Как инициализировать двумерный массив ? Как упростить инициализацию, если часть элементов массива нулевые ?
Запишите цикл ввода с клавиатуры массива B[3][4].
Что означают операторы cout.width(10); cout.precision(3); cout<<fixed; ?
ЛАБОРАТОРНАЯ РАБОТА №6
Указатели. Динамическое распределение памяти
КРАТКИЕ ТЕОРЕТИЧЕСКИЕ СВЕДЕНИЯ
3Указатели
Любой объект программы (переменная, массив, функция и т. д.) имеет имя и занимает в памяти определенную область. Местоположение объекта в памяти определяется его адресом. Обращение к объекту можно осуществить по его имени или косвенно, через адрес. Обращение к объекту через адрес осуществляется с помощью переменной-указателя, связанного с объектом. Указатель хранит адрес объекта (или, иначе, адрес ячейки памяти, с которой начинается объект).
Для описания указателей используется операция косвенной адресации *. Например, указатель целого типа uk описывается так :
int *uk.
Унарная операция &, примененная к некоторой переменной, показывает, что нам нужен адрес этой переменной, а не ее текущее значение. Если переменная uk объявлена как указатель, то оператор присваивания
uk=&x
означает: "взять адрес переменной x и присвоить его значение переменной указателю uk". Теперь к переменной x можно обратиться как *uk.
В одной программе можно переопределять указатель, присваивая ему разные адреса. Тогда одна и та же переменная будет использована для обращения к разным объектам. Такой стиль обращений используется, однако, редко.
Чаще, указатели используются при работе с массивами, символьными строками, зарезервированными областями памяти и объектами, память для которых выделяется динамически во время выполнения программы (п. 2.3).
Итак, указатели предназначены для хранения адресов областей памяти. В C++ различают три вида указателей – указатели на объект, на функцию и на void, отличающиеся свойствами и набором допустимых операций. Указатель не является самостоятельным типом, он всегда связан с каким-либо другим конкретным типом объекта.
Указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа (основного или составного). Объявление указателя на объект (в дальнейшем называемого просто указателем) имеет вид:
тип *имя;
где тип – тип объекта, на который ссылается указатель. Он может быть любым, кроме ссылки и битового поля, причем тип может быть к этому моменту только объявлен, но еще не определен (следовательно, в структуре, например, может присутствовать указатель на структуру того же типа). Символ "звездочка" сообщает компилятору, что объявленная переменная является указателем. Независимо от типа объекта, для указателя резервируется два или четыре байта в зависимости от используемой модели памяти.
Пример объявления указателей на переменные целого типа:
int *pi, *pbi, *pci;
Звездочка относится непосредственно к имени. Поэтому для того, чтобы объявить несколько указателей, требуется ставить ее перед именем каждого из них.
Существует соглашение: имя указателя начинать с буквы p. Это облегчает чтение программы.
При объявлении указателя надо стремиться выполнить его инициализацию, то есть присвоение начального значения. Непреднамеренное использование неинициализированных указателей – распространенный источник ошибок в программах, который может привести к аварийному событию. Инициализатор записывается после имени указателя либо в круглых скобках, либо после знака равенства:
тип *имя указателя = инициализирующее выражение;
тип *имя указателя (инициализирующее выражение);
Существуют следующие способы инициализации указателя:
1.Присваивание указателю адреса существующего объекта:
– с помощью операции получения адреса:
int a = 5; // целая переменная
int *р = &а; //в указатель записывается адрес а
int *р (&а); // в указатель записывается адрес а другим способом
– с помощью значения другого инициализированного указателя p:
int a = 5;
int *р = &а;
int *pr = р; //pr тоже указатель на a
– с помощью имени массива :
int b[10]; // массив
int * pb = b; // присваивание адреса первого элемента массива
2. Присваивание указателю адреса области памяти в явном виде:
char *pv = (char *)0xB8000000;
Здесь 0xB8000000 – шестнадцатеричная константа (начальный адрес видеопамяти ПЭВМ ), (char *) – обязательная операция приведения типа: константа преобразуется к типу указателя ( char *). Таким образом, определяется, что в эту ячейку памяти будет записан код переменной типа char.
3. Присваивание пустого значения:
int *psuxx = NULL;
int *prulez = 0;
В первой строке используется константа NULL, определенная в некоторых заголовочных файлах С как указатель, равный нулю. Рекомендуется использовать просто 0, так как это значение типа int будет правильно преобразовано стандартными способами в соответствии с контекстом. Поскольку гарантируется, что объектов с нулевым адресом нет, пустой указатель можно использовать для проверки, ссылается указатель на конкретный объект или нет.
После определения указателя и его инициализации адресом переменной или адресом области памяти, указатель можно использовать для записи и чтения значения, находящегося по этому адресу. Для этого применяется операция разыменования ' * ' ( получение значения через указатель ). Пример:
int a; // целая переменная
int *р = &а; //в указатель записывается адрес а
*p = 5; //через операцию разыменования указателя переменной a присвоено значение 5
cout<< *p; // вывод значения переменной a через указатель
но
cout<< p; // вывод адреса переменной a
Выражение *p обладает в данном случае правами имени переменной a и может использоваться везде, где допустимо использование имен объектов того типа, к которому относиться указатель.
С помощью указателя можно записать и считать значение непосредственно из ячейки памяти с заданным адресом:
char *pv = (char *)0xB8000000;// присваивание указателю адреса области памяти в явном виде
*pv = '+'; // запись в ячейку с адресом 0xB8000000 символа +
char v = *pv; // присваивание v значения из ячейки с адресом
0xB8000000, значение будет представлено в символьном виде
Можно определить неизменяемый (константный) указатель. При инициализации ему присваивается значение адреса, которое невозможно изменить. То есть константный указатель всегда связан с конкретным фиксированным адресом участка основной памяти и является как бы его именем. Определение константного указателя имеет следующий формат:
тип *const имя указателя инициализатор;
Пример:
char *const key_byte = (char*)1047;
Значение указателя key_byte невозможно изменить, он всегда указывает на байт с адресом 1047.
Содержимое участка памяти связанного с константным указателем с помощью разыменования можно читать и изменять.
char *const key_byte = (char*)1047;
cout<<"\nbyte key: "<< *key_byte;
*key_byte = 'Ё';
cout<<"\nbyte key: "<< *key_byte;
Попытку изменить значение самого константного указателя, т.е. операцию вида
key_byte = NULL;
не допустит компилятор и выдаст сообщение об ошибке.
Можно определить указатель на константу. Формат определения:
тип const *имя указателя инициализатор;
В этом случае значение переменной, хранящейся по адресу связанному с указателем невозможно изменить через операцию разыменования. Пример:
const int zero = 0; //определение константы
int const *pconst = &zero; //указатель на константу 0
Операторы вида
*pconst = 1;
cin>>*pconst;
недопустимы, так как каждый из них – попытка изменить значение константы 0.
Однако операторы
pconst = &a;
pconst = NULL;
допустимы, так как разрывают связь указателя pconst с константой 0, но не меняют значение этой константы.
Можно определить константный указатель на константу. После инициализации такого указателя невозможно изменить ни адреса, связанного с указателем, ни значения записанного по этому адресу с помощью разыменования указателя. Например:
const float pi = 3.141593;
float const *const ppi = π
Можно определить указатель на указатель и т.д. сколько нужно раз. В следующей программе определены такие указатели и с их помощью выполнен доступ к значению переменной:
int i = 77;
int *pi = &i;
int **ppi = π
int ***pppi = &ppi;
cout<<"i = "<< ***pppi;
Указатель на тип void применяется и тех случаях, когда конкретный тип объекта, адрес которого требуется хранить, не определен (например, если в одной и той же переменной в разные моменты времени требуется хранить адреса объектов различных типов).
Указателю на void можно присвоить значение указателя любого типа, а также сравнивать его с любыми указателями, но перед выполнением каких-либо действий с областью памяти, на которую он ссылается, требуется преобразовать его к конкретному типу явным образом. Возможности связывания указателя void * с объектами разных типов показаны в следующей программе:
void *pv;
int i = 77;
float f = 2.3456;
cout<<RUS("\nНачальное значение pv = ")<< pv;
pv = &i; //работаем с переменной типа int
cout<<"i = "<< *(int *)pv; //перед разыменованием явное приведение типа указателя к типу int
pv = &f; // работаем с переменной типа float
cout<<"f = "<< *(float *)pv; //перед разыменованием явное приведение типа указателя к типу float