Похожие презентации:
Второй (весенний) семестр 2022-2023 уч. год
1.
Второй (весенний) семестр 2022-2023 уч.годЛекции + упражнения (лабораторные – 1 р/неделю)
Будет 7 классных + 3 домашних работы
Домашняя работа - 3 балла, если сдана в срок. При опоздании вычитается
один балл, через 2 недели ещё балл, и так далее. Если студент
продемонстрировал частично сделанную задачу до дедлайна, то за неё
дают +1 бонусный балл.
Классная работа (недоделанная) может быть (и должна!) за неделю
доделана до “отлично” (не ниже и не выше) дома за +1 балл максимум.
Бонусные пункты задания дома не выполняются и баллы не приносят.
Итоги семестра - зачет с оценкой (если иное не будет объявлено
лектором). Предварительно по баллам 24+ «отлично», 20+ «хорошо»,
15+ «удовлетворительно»
2.
Рекомендации по прошлому семеструЧитайте задания внимательно и выполняйте по пунктам то, что требуется.
Ставьте комментарии, через пол-года некоторые программы становятся чужими
Отлаживайте небольшие куски кода. «Лучшее – враг хорошего». Сделали –
проверьте корректность. Идите шаг за шагом.
Повторяющиеся действия ВСЕГДА оформляйте в виде функций.
Не экономьте на переменных, делайте идентификаторы «понятными».
«Изящные» приемы (когда одна строка заменяет несколько) часто скрывают
ошибки.
Избегайте GOTO и тп. Пишите «елочкой» с отступами.
3.
Visual Studio 2022 - https://visualstudio.microsoft.com/ru/По принятому стандарту используем VS Community edition – бесплатную
интегрированная среда разработки (IDE, Integrated Development Environment) для
создания desktop (компьютеры Windows/MAC) или мобильных приложений (Android,
iOS), веб-приложений и облачных служб.
В этом семестре будем использовать
бесплатную графическую библиотеку
labengine, дополнительные сведения по
ней выложены в группе в VK
Данная библиотека работает только с VS
под Windows
4.
Шпаргалка для памяти#include <stdio.h> // подключение библиотек
#include <locale.h>
#include <malloc.h>
#pragma warning(disable:4996) // обойти предупреждения
#define _CRT_SECURE_NO_WARNINGS
#setlocale(LC_TYPE, “Russian”); // параметры ввода/вывода «по-русски»
printf(“Указатель: %p; целое число: %d \n”, pInt, x); // %d или %i
int iArr[N] = { 0 }; // объявить массив целых чисел с инициализацией элементов
5.
Указатели – информация из лекцийПо указателям было три лекции, материалы сохранены по
ссылке https://disk.yandex.ru/d/5oGvD5N6FmRhJQ
Повторите и потренируйтесь:
лекция 9.
Указатели - базовые понятия, указатели и массивы.pdf
лекция 10.
Указатели, работа с памятью.pdf
лекция 11.
Указатели, продолжение.pdf
6.
Указатели, определенияУказателем можем считать переменную, которая хранит адрес
области памяти (вспомним последнюю работу DMP – выводили
значения указателей “%p” и видели нечто вроде “012FFE38”).
В области памяти мб. записано значение переменной
(константы, элемента массива) или функция, или новый
указатель.
Для определения указателя следует указать тип объекта, ссылку на
который содержит указатель, и символ звездочки.
double *pDub;
int *pInt;
// указатель на переменную типа double
// указатель на переменную in
Доп. ссылки: https://metanit.com/cpp/c/5.1.php
https://learnc.info/c/pointers.html
7.
Указатели, инициализацияint iSample = 10;
int *iPtr;
iPtr = &iSample;
// определяем переменную типа int
// определяем указатель на int
// присваиваем указателю получает адрес переменной
Например, iSample заняла в памяти 4
ячейки памяти по 1 байту c адресами, как
на рисунке. Адрес &iSample = 0060FEA8,
iPtr = 0060FEA8
Теперь присвоим *iPtr = 100.
Какое значение станет в iSample?
Нельзя сделать так:
int *iPtr2;
// определяем НОВЫЙ указатель на int
*iPtr2 = 10;
// некорректная операция - iPtr не инициализирована
8.
Указатели, разыменованиеint x = 42;
int *p = &x;
9.
Указатели, операции и типыПеременная, которая обозначает массив одновременно является его адресом:
int iArr[20];
// iArr == &iArr – значение iArr совпадает со значением &iArr
pIntArr = iArr; // также можно было бы iPtr = &iArr или iPtr = &iArr[0]
for (int j=0; j<20; j++) {
*(iArr+j) = j; // используем запись через указатель
}
pIntArr += 10; // Чему равно *pIntArr ?
Какие утверждения истинны:
(pIntArr == (iArr + 9)) или (pIntArr == (iArr + 10)) или (pIntArr == (iArr + 11)) ?
Аналогично можно вычитать числа (применять инкремент и/или декремент)
НЕЛЬЗЯ после объявления массива int iArr[20] выполнить, напр iArr++ или
присвоить iArr новое значение, iArr константа
10.
Указатели – формально и фактическиУказатели имеют одинаковый тип и размер в байтах. Даже, если они
указывают на различные типы данных (аналогично обычным переменным –
один тип, но разные значения).
Формально указатель хранится в переменной типа size_t, размер
занимаемой указателем ячейки памяти зависит от разрядности системы.
Фактически указатель - это переменная целочисленного типа.
Что нельзя делать с указателями?
Указатели поддерживают арифметические операции (в шестнадцатиричном
формате). Операция iPtr = iPtr + N присвоит iPtr значение
iPtr+N*sizeof(тип_на_который_указывает_указатель) или в нашем примере
iPtr + N*4 (байт, считаем, что int занимает 4 байта).
Пусть iPtr = 0060FEA8, присвоим новое значение: iPtr += 10
iPtr = 0060FEA8 + sizeof(int)*10 = 0060FEA8 + 4010 = 0060FEA8 + 2816 =
= 0060FED0
(sizeof(int)*10 = 4 * 10 = 4010 = 2816 )
11.
Задание 11. Проверьте, что установлена 32разр платформа решения
2. Объявите переменные типа double и int, присвойте им значения
3. Объявите два указателя на переменные double и int
4. Сделайте так, чтобы указатели содержали значения адресов объявленных
и инициализированных переменных
5. Выведите на экран значения указателей, количество байт в каждом
указателе
6. Выведите на экран значения переменных, количество байт для каждой
переменной
7. Присвойте значения переменным через указатели и выведите новые
значения
8. Перейдите в 64разр платформу, снова выведите данные
12.
Указатель на указательПеременная-указатель фактически хранит некое число (которое является
адресом области памяти). У этой ячейки памяти также есть свой адрес.
Другими словами, существует «указатель на указатель»
int i1 = 10, i2 = 20;
int *pInt1;
int **ppInt1;
pInt1 = &i1;
ppInt1 = &Int1; // Верно следующее: *pInt1 == **ppInt1 == 10
pInt1 = &i2;
Чему равно **ppInt1 ?
13.
Указатели и функции// описание ф-ии:
void somefunc(int *pInt) {…}
// инициализация переменных
….int i0 = 5;
int *pSomeInt = &i0; …. ;
// вызов ф-ии
somefunc(&pSomeInt);
Если somefunc изменит *pSomeInt (те.
изменит значение в ячейке памяти,
адрес которой есть значение pSomeInt),
то после вызова i0 получит НОВОЕ
ЗНАЧЕНИЕ
Функция может возвращать указатель,
созданный в «куче»
int *RetPointerTo (….) {
int *ptr = calloc(n, sizeof(int)); …..;
return ptr;}
Но не может вернуть локальную
переменную int ptr[n]; … return ptr;
14.
Задание 21. Напишите функцию PlusArr, которая получает на вход указатели на
массивы iLArr1, iLArr2 и длину (одинаковую для обоих), а возвращает
указатель на массив, созданный динамически внутри функции, элементы
которого – сумма соотв. элементов переданных массивов
2. Создайте 2 массива Arr1 и Arr2 одинаковой длины (размер и тип элементов
выберите сами) и заполните их значениями по своему усмотрению
3. Выведите оба массива на экран (значения друг под другом)
4. Вызовите функцию PlusArr и выведите полученные значения - результат
сложения под соотв. слагаемыми
5. Измените полученный массив, увеличив его на один элемент, заполните
последний элемент суммой всех чисел, снова выведите на экран массив
15.
Задание 2 – указания, памяткаhttps://learnc.info/c/memory_allocation.html: #include <malloc.h>
size – РАЗМЕР в БАЙТАХ
void *malloc(size_t size);
void *calloc(size_t number, size_t size);
void *realloc(void *memblock, size_t size);
void free(void *memblock);
1. Создаем динамический массив внутри функции. Аргумент - размер в байтах. Если мы
знаем количество элементов и тип элементов массива – как вычислить общий размер
в байтах?
2. При вызове ф-ий создания массивов (изменения размера) корректным является
приведение типов. Например, int* p = (int*)malloc(size)
3. Также корректным является проверка на создание массива. Если операция закончилась
неудачно, то возвращается значение NULL.
Можем ли написать проверку так: if (p) { … } ?
4. При вызове realloc() возможен также возврат новой ссылки на массив, как NULL – те.
возможна тн. «утечка памяти», если мы потеряем старый указатель. Перед realloc лучше
запомнить старый указатель
5. Для того, чтобы узнать размер динамического массива в байтах, можно использовать
_msize(void *memblock). Возвращает размер в байтах. А как узнать количество
элементов?
16.
Указатели на функцииЛюбая функция интерпретируется, как некая область памяти, куда
записаны команды для исполнения. Вызов функции есть
сохранение текущего состояния программы (памяти)
переход для выполнения команд по адресу функции (те. по адресу
ПЕРВОГО БАЙТА области памяти, которая выделена для функции)
выполнение команд (как будто движение по массиву, но не
элементов, а команд)
возврат по адресу, следовавшему после вызова функции
(восстановление состояния)
17.
Описание указателя на функциюПоскольку у каждой функции есть свой адрес, мы можем использовать
его, как указатель на функцию. Например, void (*SomeFunc) (void);
<тип> (*<идентификатор>)(<параметры>);
#include <stdio.h>
int main(void) {
void (*message)(void);
void hello(void) {
printf(“Hello, world\n”);
} // hello
void goodbye() {
printf(“Goodbye, world\n”);
} // goodbye
}
message=hello;
message();
message=goodbye;
message();
return 0;
// main
18.
Задание 31. Напишите 2 функции (сумма и разность), выполняющие арифметические
операции с двумя числами. На вход – два числа одного типа (напр, int),
возвращаемое значение аналогично
2. Создайте в основной программе main указатель на функцию, соотв.
созданным функциям
3. Вызовите с помощью указателя первую и вторую функции с одинаковыми
значениями переменных, выведите результаты
4. Выведите значения аргументов, с которыми выводили ф-ии
5. Измените ф-ии, чтобы они принимали адреса переменных. Пусть вторая
функция еще и обменивает значения переменных.
6. Вызовите новые функции с теми же значениями. Результаты не должны
отличаться.
7. Выведите снова переданные значения, значения должны быть изменены