C++ - занятие 2 1
Какие типы вы бы использовали? height // рост salary // зарплата за месяц (в рублях) grade// средний балл charshort longint unsigned long long floatdouble Я бы написал так: int height; int salary; // (м.б. lo ng?? м.б. double ??) double grade;// (м.б. float?) 2
Можно ли так написать? Чему будут равны i, j, k? int i=3; int j=2; int k=1; 1. i %= j; 2. i = j++ > 0 || k++ > 0; 3. (i *= 10) += j; 4. i = (int n = 2)*j; 5. i = '9' - '0'; 6. i = k++ / k++; 7. i += sizeof(j++); // i = 1 // i = 1; j = 3; k = 1; // j = 32 // ошибка // i = 9 // результат не определен // i = 7 (но вообще-то зависит от компилятора), j = 2 3
Д.з. 4
Задача 1: 1/ / /5 2 … #include using namespace std; int main() { int n; cin >> n; double sum = 0; int sign = 1; for (int i = 1; i
Задача 2: Произведение до 0 // Найти произведение чисел пока != 0 int p = 1; for (;;) { int n; cin >> n; if (n == 0) break; p *= n; } 6
Задача 4: Количество элементов до первого нуля Без указателей int i = 0; for (; a[i] != 0; i++) ; cout
Еще про операторы 8
switch switch ( ocenka ) { case 1: case 2: cout
Пустой оператор ; while (a[i++] != 0); 10
Еще про массивы 11
12 Честно говоря, вместо массивов удобнее использовать тип vector Забегая вперед, вообще-то удобнее всего писать так: #include // Это в самом начале … vector v(10); // Тоже массив из 10 чисел v[5] = 7; … Но это мы пройдем позже
13 Многомерные массивы? Используются массивы массивов int c[10][10];// Так определяем c[i][j] = 0;// Так используем
Еще разное 14
Самые частые простые ошибки 1. if (i = 0) if (i == 0) 2. f; f(); 15
Скобки if (i > 0 && i < n) *p++ == *(p++) 16
Указатели 17
18 Ошибки при работе с указателями p = nullptr; *p = 5; 2. int* p; *p = 5;// Wild pointer 3. delete p; *p = 5; 4. p = q; … delete p; … *q = 5; Dangling pointers
19 Ошибки при работе с динамической памятью int* p = new int; p = nullptr; 2. p = new int; … p = new int; Memory leak (утечка памяти)
Еще про delete p = 0; // Или p = nullptr … delete p; // OK, если p == 0 // – ничего не делает
Указатели и массивы Адресная арифметика 21
22 Указатели и массивы int a[100]; int* p; p = a; // a – адрес нулевого эл-та (&a[0]) p + n; // на n ячеек вперед p - n; // на n ячеек назад p += n p -= n p++ p p1 – p2 // Сколько ячеек между p1 и p2? if (p1 < p2) p[i] // Как бы считаем p началом массива // p[i] тоже, что *(p+i)
Зачем это все? С указателями можно работать, как с массивами int* p = new int[k]; p[3] = 1; С массивами можно работать с помощью указателей int a[100]; for (int* p = а; p < a + 100; p++) s += *p; 23
Замечания Равенства: &a[i] то же, чтоа+i &a[0]то же, чтоа Операции с массивами не отличаются (почти) от указателей А в чем все-таки отличаются? 24
Функции 25
Функция - пример int 1 max(int i, int j 2 ) { int result = i; if ( i < j ) result = j; return 3 result; } int k = max(m, n); Замечания: 1. тип результата 2. описания параметров разделяются запятыми 3. выход из функции 26
Как в C++ описать функцию, которая ничего не возвращает? Любую функцию можно вызывать, как процедуру - результат просто не используется void f(int i) { if (i>0) { cout
Еще возможности Передача параметров по ссылке void twice(int& i) { i *= 2; } int& - примерно то же, что var в Паскале (подробнее позже) Объявление функции (прототип) void f(int i, int j); … cout
Массивы, как параметры 29
Что будет, если массив передать, как параметр? int arr[100]; … cout
Массив, как параметр - продолжение int sum(int *a) // Или, просто как замечание, можно { // написать так s = 0; for (int* p = a; p < a+100; p++) s += *p; return s; } int sum(int a[])// транслируется в int sum(int* a) Замечание о длине массива: А можем мы как-то в функции узнать длину массива? Ну и что тогда делать? Передавать длину в качестве доп. параметра или использовать vector и т.д. 31
Дополнительные возможности для функций 32
33 inline inline int square(int i) { return i*i; } n = square(k); // n = k*k; Что-то вроде макроподстановки Это просто совет.. Когда компилятор не послушает совета?
Параметры по умолчанию void f(int i, int j = 55) { … } f(3) f(3, 55) Замечания: Умолчания могут быть для нескольких параметров Нельзя опускать параметры в середине (только в конце) Вопрос: где писать – в объявлении (прототипе) или в описании?
Перегрузка (overload) void f(int i) {… } void f(double j) { … } OK, компилятор различит: f(5);// Первая функция f(3.14);// Вторая функция Может перегружаться с разным количеством аргументов void f(int i) { … } void f(int i, int j) { … } f(5);// Первая функция f(7, 8);// Вторая функция
Всегда ли можно перегружать функции? int f(int i) { … } double f(int i) { … } Будет ошибка при вызове int f(int i) { … } int f(int i, int j = 0) { … } Тоже будет ошибка при вызове Компилятор должен однозначно понимать, какая функция вызывается
Ссылки 37
38 Ссылки int a[100]; int& k = a[5]; k++; // тоже, что a[5]++; cout
Применения ссылок 1. Синоним для быстрого доступа к объекту а[7].abc.b[88]; int& k = а[7].abc.b[88]; 2. Параметры по ссылке – аналог var в Pascal void dbl(int& i) { i *= 2; } int m = 10; dbl(m); // При вызове dbl выполняется int& i = m; 39
Применения ссылок - продолжение 3. Функции, возвращающие lvalue Что такое lvalue? 11x+1sin(x)true xa[i]*px.abc lvalue – то, у чего есть адрес (или можно сказать - то, что может писаться слева от равенства, но это не совсем точно) 40
Применения ссылок - продолжение int& f(int* a)// Функция, возвращающая lvalue {// (просто для примера, совершенно бессмысленная) return a[5]; } int arr[100]; cout
Сложные типы 42
Как определять сложные типы? a - массив из 10 укaзателей на int Массив из 10 указателей на int a a[10] *(a[10]) int *(a[10]); // Или int *a[10]; 43
Как читать сложные типы? int (*a)[10]; а *a*a (*a)[10] int (*a)[10]; a – это указатель на массив из 10 int 44
typedef Синтаксис: typedef описание переменной; typedef unsigned long ulong; typedef int* my_array[10]; my_array a; // то же, что int* a[10]; Замечание - typedef не определяет новый тип – просто сокращенную запись для существующего типа void f(unsigned long i) { … } void f(ulong j) // Ошибка - {// у функций одинаковые …// параметры } 45
Д.з. 46
Задачи 1. Описать функцию reverse. Параметр: массив чисел. Переставляет первые n чисел в обратном порядке. (n – параметр) Желательно реализовать с помощью арифметики указателей (не используя []) (И *(a+i) тоже не используя…) 2.Треугольный массив Массив указателей: int* a[10]; а. Отвести динамич.массивы длины 1, 2, 3… и запомнить указатели в массиве. б. Инициализировать массивы так: в каждом массиве последний элемент (на диагонали) 1, остальные 0. в. Напечатать массив. 3. Изменение параметров без ссылок (старинный способ:) Опишите функцию, которая удваивает данное число. В качестве параметра передается указатель на число. Пример вызова: int i = 5; twice(&i); … // теперь i == а – массив из чисел. Сначала несколько положительных, потом только нули. Найти количество положительных. Это можно сделать гораздо быстрее, чем просто просматривать все элементы подряд. Попробуйте, пожалуйста придумать такой способ. 47