450 likes | 682 Views
Д.з. на 14 апреля. Язык С++. 1. Задача 1: substr – с временным массивом. class string { ... string substr(int from, int len) const; // const !! }; string string::substr(int from, int len) const { char* tmp = new char[len+1]; // Отводим временный массив символов.
E N D
Д.з. на 14 апреля Язык С++ 1
Задача 1: substr – с временным массивом class string { ... string substr(int from, int len) const;// const !! }; string string::substr(int from, int len) const { char* tmp = new char[len+1]; // Отводим временный массив символов. for (int i=0; i<len; i++) // Копируем туда подстроку. tmp[i] = str[i+from]; tmp[len] = '\0'; string res(tmp); // Создаем строку-результат delete [] tmp; // Теперь tmp можно удалить return res; } Язык С++ 2
Задача 1: substr – с доп. конструктором // Вспомогательный конструктор – создает строку данной длины string::string(const char* s, int num) : len(num) { p = new char[num + 1]; for (int i = 0; i < num; i++) p[i] = s[i]; p[num] = '\0'; } // Теперь substr пишется _очень_ просто string string::substr(int from, int num) const { return string(p + from, num); } Язык С++ 3
Задачи на 14 апреля Язык С++ 4
itoa_oct void itoa_oct(char* s, int n) { // Сначала ищем, где будет конец // строки char* p = s; int n1 = n; while (n1 > 0) { p++; // В цикле делим на 8 и n1 /= 8; // сдвигаем указатель. } *p = '\0'; // Сразу ставим '\0' // на конце // Пишем цифры в обратном // порядке. // Цикл похож напервый, но // теперь еще пишем цифры. n1 = n; while (n1 > 0) { p--; *p = n1 % 8 + '0'; n1 /= 8; } } // Пример вызова: char s[20]; int i; cin >> i; itoa_oct(s, i); cout << s; Язык С++ 5 5
itoa_oct –вариантыинтерфейса • Результат – строка string itoa_oct(int n) { char buff[20]; // Можно 12… заполняем buff,как напредыдущем слайде … return string(buff); } // Пример вызова cout << itoa_oct(i); Можно сразу заполнять с конца, от buff+19 ! Язык С++ 6 6
itoa_oct –плохие вариантыинтерфейса char* + динамическая память char* itoa_oct(int n) { char* p = new char[…]; … заполняем … return p; } cout << itoa_oct(i); // Утечка памяти очень плохо: char* + локальная память char* itoa_oct(int n) { char buff[20]; … заполняем … return buff; } Указатель на несуществующую память! Язык С++ 7
class person_info { public: long phone; // Телефон string address;// Адрес person_info(long ph = 0, const string& addr = "") : phone(ph), address(addr) {}// Лучше описать к-р };// по умолчанию // Телефонная книга map<string, person_info> pb; // Пример заполнения pb["Иванов"] = person_info( 3223322, "Липовая ул. 1"); pb["Петров"] = person_info( 2991234, "Невский пр. 22"); // Пример использования cout << pb["Иванов"].address << ", " << pb["Иванов"].phone; // Или так более эффективно p = pb.find("Иванов"); cout << p->second.address << ", " << p->second.phone; Телефонная книга
Задача 1: Частотный словарь map<string, int> freq; string s; … открываем файл … while (f >> s) {// Читаем слово freq[s]++;// Увеличиваем счетчик (или можно find и insert) } // Печатаем ответ map<string, int>::iterator p; for (p = freq.begin(); p != freq.end(); p++) { cout << p->first << " - " << p->second << "\n"; }
Задача 4: треугольники void CTrianglesView::OnDraw(CDC* pDC) { // Начальные значения – примерно // равносторонний преугольник int x1=0, y1=0, x2=1000, y2=0, x3=500, y3=866; // Цикл "Пока не получится очень // маленький треугольник" while ((x1-x2)*(x1-x2)+ (y1-y2)*(y1-y2)>=2 ) { // Рисуем треугольник pDC->MoveTo(x1, y1); pDC->LineTo(x2, y2); pDC->LineTo(x3, y3); pDC->LineTo(x1, y1); // Пересчитываем // координаты точек – теперь // нам нужны середины сторон int x1_ = (x2+x3)/2, y1_ =(y2+y3)/2, x2_ = (x1+x3)/2, y2_ = (y1+y3)/2; x3_ = (x1+x2)/2, y3_ = (y1+y2)/2; x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; x3 = x3_; y3 = y3_; } } Язык С++ 10 10
Задача 5: Sierpinski // Воспомогательная рекурсивная функция void DrawSierpinski(CDC* pDC, int x1, int y1, int x2, int y2, int x3, int y3) { // Если треугольник очень маленький - ничего не делаем if ( (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=2 ) return; // Рисуем треугольник pDC->MoveTo(x1, y1); pDC->LineTo(x2, y2); pDC->LineTo(x3, y3); pDC->LineTo(x1, y1); // Считаем середины int x1_ = (x2+x3)/2, y1_ =(y2+y3)/2, x2_ = (x1+x3)/2, y2_ = (y1+y3)/2, x3_ = (x1+x2)/2, y3_ = (y1+y2)/2; // Вызываем функцию рекурсивно для трех маленьких треугольников DrawSierpinski(pDC, x1, y1,x2_, y2_, x3_, y3_); DrawSierpinski(pDC, x1_, y1_,x2_, y2_, x3, y3); DrawSierpinski(pDC, x1_, y1_,x2, y2, x3_, y3_); } Язык С++ 11 11
Задача 5: Sierpinski - продолжение Еще способ: с помощью случайной последовательности точек Язык С++ 12
Доп.задачи про строки Язык С++ 13
Задача 1: strcpy // Через for void strcpy(char* to, const char* from) { int i; for (i=0; from[i]!='\0'; i++) to[i] = from[i]; to[i] = '\0'; } Замечание:На самом деле strcpy имеет тип char* и возвращает to,как результат. Но мы в примерах для краткости этого не делаем. // С использованием указателей // (и, для разнообразия, через // while) void strcpy(char* to, const char*from) { const char* p1= from; char* p2 = to; while (*p1 != '\0') { *p2 = *p1; p1++; p2++; } p2 = '\0'; } Язык С++ 14
Задача 1: strcpy - продолжение // Самое короткое решение void strcpy(char* to, const char* from) { while (*to++ = *from++); } Язык С++ 15
Задача 2:reverse void reverse (char* str) { char* p = str; char* q = str + strlen(str) – 1;// Последний символ for (;p < q; p++, q--) { // Меняем местами chartmp = *p; *p = *q; *q = tmp; } } Язык С++ 16
Еще про ассоциативные контейнеры Язык С++ 17
multiset и multimap - обзор #include <set> … multiset<int> s; s.insert(6); s.insert(2); s.insert(9); s.insert(6); for(multiset<int>::iterator p = s.begin(); p!=s.end(); p++) cout << *p << " "; // 2 6 6 9 #include <map> … multimap<double, int> m; m.insert(make_pair(4.5, 2)); m.insert(make_pair(4.5, 8)); [] не работает find возвращает первую пару Язык С++ 18
Алгоритмы STL – пока только самые простые Язык С++ 19
Пример • reverse(итератор начала, итератор конца); #include <algorithm> … vector<int> v; … Заполняем v … reverse(v.begin(), v.end()); list<double> l; … Заполняем l … reverse(l.begin(), l.end()); string s = “abcdef”; reverse(s.begin(), s.end()); Язык С++ 20
Алгоритмы STL • #include <algorithm> • Весь интерфейс алгоритмов - через итераторы Схема: Контейнеры Итераторы Алгоритмы "Алгоритмы и контейнеры хорошо работают вместе, потому что ничего не знают друг о друге" Язык С++ 21
Еще пример - sort #include <algorithm> … vector<int> v; … // Заполняем v sort(v.begin(), v.end()); … deque<double> d; … // Заполняем d sort(d.begin(), d.end()); • Замечание: sort работает только для vector и deque Язык С++ 22
Еще пример - accumulate • accumulate – найти сумму #include <numeric>// Не в <algorihtm> !… vector<int> v; … Заполняем v … int sum = accumulate(v.begin(), v.end(), 0); // Ищем сумму Язык С++ 23
Сложные (более-менее) алгоритмы sort binary_search merge max_element, min_elementmax_element(v.begin(), v.end()); возвращает итератор random_shuffle … и еще несколько… Очень простые алгоритмы accumulate reverse copy find fill – заполнить значением … и еще много … Еще некоторые возможности через несколько занятий Подробнее об алгоритмах
Программы для Windows - продолжение Язык С++ 25
Венгерская нотация Charles Simonyi iAbc – целая переменная bAbc – логическая переменная pAbc – указатель sAbc - строка CAbc – класс m_iAbc – поле (целое) m_pAbc – поле (указатель) Язык С++ 26
Классы в MFC можно разделить на такие группы: Классы, которые используются непосредственно CPoint – точка (x, y) CRect – прямоугольник CPen, CBrush, CFont – объекты для рисования (перо, кисть, шрифт) Классы, которые используются, как базовые классыCWnd -окно CView –окно приложения - определяем C…View - переопределям OnDraw Некоторые классы используются и непосредственно, и как базовые CButton – кнопка. Язык С++ 27
Файлы, из которых состоит MFC приложение • Остальные файлы, как правило, можно не смотреть. Часто нужно менять классы: CAbcView – окнодля вывода CAbcApp – ‘приложение’ – действия при начале/конце работы, место для глобальных переменных и т.д. CAbcDoc – будет позже.. Язык С++ 28
Особенности рисования в Windows программах OnDraw вызывается каждый раз, когда надо изобразить окно или часть окна Следовательно: Рисование должно делаться по возможности быстро Желательно никаких операций ввода/вывода, сложных расчетов и т.д. Еще следствия дальше… Язык С++ 29
Пример – программа Circles Картины из кружков. Новые кружки появляются при щелчке мышью Язык С++ 30
Как что-то поменять в окне? Обработка событий. Как добавить реакцию на событие (click)? Добавляем фунцию – обработчик сообщения (инструкции на сайте). Появляется: void CirclesView::OnLButtonDown(UINT nFlags, CPoint point) { … что надо делать при щелчке левой кнопкой … } Язык С++ 31
Как что-то поменять в окне? Попытка 1 (наеправильная) Что делать при обработке события, чтобы поменять картинку? void CirclesView::OnLButtonDown(UINT nFlags, CPoint point){ …откуда то взяли pDC … pDC->Ellipse(point.x – 10, point.y – 10,// Рисуем кружок point.x + 10, point.y + 10); } Плохо: картинка пропадет при перерисовке. Язык С++ 32
void OnDraw(CDC* pDC) { for (int i = 0; i < m_circles.size(); i++) { pDC->Ellipse(m_circles[i].x – 10, m_circles[i].y – 10, m_circles[i].x + 10, m_circles[i].y + 10); } OnLButtonDown: добавляем круг m_circles.push_back(point); Плохо: При щелчке ничего не будет изменяться. Как что-то поменять в окне. Попытка 2 (почти правильная). • Мы должны всегда быть готовы перерисовать картинку • Значит, все данные об изображении должны храниться в памяти. • Храним информацию о картинке в CCirclesView class CCirclesView { … vector<CPoint> m_circles; • Рисование очень простое Язык С++ 33
Invalidate() – запрос на перерисовку окна. OnLButtonDown: добавляем круг (Правильный вариант) void CCirclesView::OnLButtonDown( UINT nFlags, CPoint point) { m_circles.push_back(point); Invalidate();// Запрос на } // перерисовку Схема обработки сообщения: При обработке сообщения, как правило, надо: Поменять информацию о картинке Сообщить системе, что надо перерисовать картинку (Invalidate()) Замечания: Изображение моргает… InvalidateRect и т.д. Обычно пишут сложнее – на следующем занятии (Document/View) Invalidate. Как что-то поменять в окне. Теперь правильно (хотя можно и улучшить) Язык С++ 34
Шаблоны функций Язык С++ 35
Зачем нужны шаблоны? int max(int x, int y) { if (x < y) return y; else return x; } ... тоже для double ... ... тоже для short ... ... тоже для time ... и т.д. template <class T> Т max(T x, T y) { if (x < y) return y; else return x; } // Пример вызова int i, j, k; ... k = max(i, j); Генерируется: int max(int x, int y){ if (x<y) …} Язык С++ 36
Синтаксис шаблоновфункций, замечания double x, y, z; ... z = max(x, y); Генерируется: double max(double x, double y) { if (x<y) …} Синтаксис template <параметры> <описание функции> Замечания: Параметров м.б. несколько: template <class T1, class T2> void copy(T1* to, T2* from, int n) { for(int i = 0; i < n; i++) to[i] = from[i]; } double a[100]; int b[100]; copy(a, b, 100); typename T - то же, что class T Язык С++ 37
Генерация шаблона (instantiation) Параметры шаблона должны выводиться из параметров вызова функции int i,j; max(i, j) T == int М.б. не напрямую, через указатели, ссылки и т.д. double a[100]; int b[100]; copy(a, b, 100); T1 = double, T2 = int Так будет ошибка: template <class T> void f(int i)// T нет в параметрах{ T x; … } f(5); // Could not deduce.. // Не вывести тип T Можно явно задавать параметр f<double>(5); // OK Для функций - редко. Язык С++ 38
Порядок подбора функции double x; inti; max(x, i); // Ошибка Порядок подбора функции Обычная функция, без преобразований Шаблон, без преобразований Обычная функция, с преобразованиями Никогда: шаблон с преобразованиями! Что же делать? max(x, (double)i) max<double>(x, i) Язык С++ 39
Что будет, если тип "не подходит" шаблону? complex c1, c2; max(c1, c2) // Ошибка: оператор< не определен Диагностика м.б. не очень понятная concepts в C++ 0x time t1, t2; max(t1, t2) ОК, если задать оператор < Язык С++ 40
Перегрузка шаблона функции. char s1[] = "abc"; char s2[] = "klm"; cout << max(s1, s2); // Не то сравнение! Специализация char* max(char* x, char* y) { if (strcmp(x,y) <0) return x; else return y; } Тут было обсуждение того, почему такое определение max для char плохо с точки зрения поддержки константности (константных строк и т.д.), и как это можно исправить. Язык С++ 41
Замечания Может увеличится размер программы (code bloat) Обычно часто используете и редко пишете свои шаблоны. Язык С++ 42
Задачи на 28 апреля Язык С++ 43
Задачи на 28 апреля Для программы Circles реализовать удаление кружков (например, правой кнопкой) * Для программы Circles реализовать перетаскивание кружков с места на место. Шаблон функции swp, которая меняет местами два объекта одного типа.double x = 1.1, y = 2.2;swp(x, y);cout << x << y; // 2.2 1.1(Замечание: вообще-то лучше бы назвать ее swap, но такая функция уже есть стандартная). * Специализация swp для mystring (т.е. того string, который мы писали).string s1 = "abc";strings2 = "klm";swp(s1, s2);// klm abcПояснение: swp из пункта 3 будет, скорее всего, работать и для строк. Зачем же его тогда специализировать? Дело в том, что можно написать специализацию, которая работает гораздо быстрее(Подсказка: просто поменять местами отдельно указатели и отдельно длины). Язык С++ 44
Задачи на 28апреля Еще подсказка: если хотите, для простоты можете объявить все поля string как public. Это немного упростит задачу. Опишите функцию, которая для данного вектора целых чисел ищет сумму всех его элементов, кроме максимального и минимального.(Будем для простоты считать, что и максимальный и минимальный встречаются в векторе только один раз). Если получится, пожалуйста, решите эту задачу используя стандартные алгоритмы.(Т.е. желательно самим никаких циклов не писать) Язык С++ 45