8 Стиль кода, указатели, ссылки.pptx
- Количество слайдов: 27
Занятие 8 Курс "Основы программирования"
План занятия 1. Что такое стиль кода – code style? 2. Ключевые моменты 3. Особенности оформления кода 4. Указатели и ссылки
Code Style • Облегчает понимание кода • Облегчает поддержку кода ( «ремонт» ) • Упрощает взаимодействие кодеров
Ключевые моменты • #0: Следуйте корпоративным правилам • Кодировка – UTF-8, Unicode / Юникод • Именование на чистом английском • Именование переменных отражает суть • Имена умеренной длины • Единообразный код всего проекта
Особенности функций • Функция – глагол • У каждой функции одна задача: решить. Уравнение( … ); вывести. На. Экран( … ); Вместо: решить. Уравнение. Вывести. На. Экран( … );
Имена – важны • Имена – повсюду: всё кроме значков… • Хорошее именование превращает программу в книгу. Примеры: + Month. Revenue. calculate() + Month. Revenue. export() - compute. Month. Revenue. And. Do. Export()
Комментарии • Помогают читать программу • Используются в авто-документации • Помогают осмыслить свои действия
Пробелы 1. Отступы с помощью табов 2. На конце строки нет пробелов 3. if/else/for/while/try всегда имеют фигурные скобки, а тело на новой строке 4. Пробелы по обе стороны от инвертирования: if ( ! name) { 5. В тернарном выражении пробелы по обе стороны от символов ‘? ’ и ‘: ’
Пробелы 6. Между оператором и скобокой должен быть пробел: while ( ), if ( ), for ( ); 7. Между функцией и скобкой не должно быть пробелов: $. each( ) 8. Перед открывающейся фигурной скобкой должен быть пробел: for () {, function() { 9. В пустых строках сохранять отступы
Пробелы 10. Между методами объектов должно быть два переноса строки 11. Математические и логические операторы должны обрамляться пробелами: 2 + 3, 5 || 3 12. После запятой всегда должен быть пробел 13. В начале и конце массивов и объектов должны быть пробелы: не так: var arr = [2, 3]; а так: var arr = [ 2, 3 ]; 14. Выравнивание пробелами
Комментарии • Комментарии писать в начале строки • В однострочном комментарии в начале должен стоять пробел • Комментарий должен начинаться с большой буквы • То, что планируется переписать или исправить, помечать комментарием вида: // TODO: Временный костыль // HACK: Знаю что так нельзя // FIX: Обходим глобальные недоработки
Именование • Использовать camel. Case • Переменные и функции – начинать имя с маленькой буквы • Названия классов – с большой буквы • Константы должны быть в uppercase: var MAX_VALUE = 100;
Общее • KR-нотация для фигурных скобок • Сначала свойства, потом методы • Нет круглых скобок за return: return 0, не return (0) • Код делится на секции переносами строк • Объекты с ≥ 3 свойств – многострочно
Что такое хорошо // Конструктор для объектов 2 D вектора function Vec 2() { var v = { x: 0, y: 0 , length: function () { return Math. sqrt(v. x * v. x + v. y * v. y); }, }; return v; } var a = Vec 2(), b = Vec 2();
Понятие ссылки var a = Vec 2(), // a – ссылка на первый Vec 2 b = Vec 2(); // b ссылается на второй То есть сам объект лежит где-то в памяти, а ссылки лишь знают о том где лежит их объект. И это знание в них можно менять. var a = b = с = a; // c ссылается тоже на первый Vec 2 b; // теперь a ссылается на второй Vec 2 c; // теперь b ссылается на первый Vec 2
Ссылки на самом деле ссылаются на области памяти, var с = a; a = b; b = c; b. x = 3; Содержимое 0 x 100 dc 013 ( x = ) 0 0 x 100 dc 014 ( y = ) 0 ( x = ) 0 0 x 100 dc 016 ( y = ) 0 0 x 100 dc 017 … 0 x 100 dc 018 … 0 x 100 dc 019 … 0 x 100 dc 01 a b = Vec 2(); Адрес 0 x 100 dc 015 var a = Vec 2(), … 0 x 100 dc 01 b …
Зачем нужны ссылки? Для того чтобы не копировать объект каждый раз, передавая его в другое место. Например: function modify(mas) { mas[1] = 2; } var a = [ 11, 3, 4, <10 млн. >, 55, 7 ]; modify(a); console. log( a[1] ); // 2
Связность памяти • Много ссылок могут ссылаться на один и тот же объект (место в памяти). • Объект нужно удалять из памяти, если на него никто не ссылается. • Если ссылаться на уже удалённый из памяти объект то это будет ошибкой.
Указатели в С (pointer) • В отличие от JS, C позволяет работать с памятью напрямую • В том числе можно обратиться к любой ячейке памяти на свой выбор • Переменные предназначенные для хранения номеров ячеек (а не данных) называются указателями • Чтобы создать такую переменную, используем символ *: int *p; Переменная p может хранить номера ячеек памяти, содержащих целые числа.
Работа с указателями int a = 10, b = 3; // переменные a и b int *p; // переменная-указатель на ячейку с int p = &a; // p указывает на a *p = 6; // изменим значение a через указатель p = &b; // p указывает на b *p = 8; // изменим значение b через указатель p = 0; // p больше ни на что не указывает *p = 2; // ошибка, по адресу 0 нет переменной
Неявное высвобождение в JS var a = { x: 1, y: 2 }; // в а ссылка на этот объект var b = a; // и b теперь тоже на него ссылается a = 53; // теперь в a лежит 53, а не ссылка на объект // b всё ещё ссылается на объект «{ x: 1, y: 2 }» b = “строка”; // b тоже перестаёт ссылаться на объект // никому больше не нужен объект «{ x: 1, y: 2 }» // поэтому он удаляется, память, ранее // занятая, освобождается под новые объекты
Выделение памяти в С struct v 2 { int x, y; }; // описываем тип v 2 *p; // создаём указатель, для ячеек типа v 2 p = new v 2; // выделить память, получить указатель (*p). x = 5; // либо *p и доступ через. как обычно p->y = 40; // либо доступ через стрелку // теперь очистить память – действие обратное new delete p; // освободить область памяти, выделенную // на том месте куда ссылался указатель p // это не происходит само по себе!
Но мы же обходились без них! int a[10]; // так можно int count; scanf(“%i”, &count); int b[count]; // а так нельзя! int c[10000000]; // не влезет в стек! int *p = new int[10000000]; // ok! int *p 2 = new int[count]; // ok! delete [] p; // обязательно освободить память delete [] p 2;
Реализуем авто-удаление в С++ class Ref. Int. Array { int *data; // собственно массив храним тут int *refs; // счётчик ссылок на данный массив void clear() { delete [] data; delete refs; } public: Ref. Int. Array(); Ref. Int. Array(int *array); // конструктор ~Ref. Int. Array() { if(!--(*refs)) clear(); } // операции копирования и присвоения Ref. Int. Array(Ref. Int. Array &other); void operator =(Ref. Int. Array &other); // операции индексирования int operator[](int idx) const { return data[idx]; } int &operator[](int idx) { return data[idx]; } };
Методы Ref. Int. Array: : Ref. Int. Array() { data = 0; refs = new int; *refs = 1; } Ref. Int. Array: : Ref. Int. Array(int *array) { data = array; refs = new int; *refs = 1; } Ref. Int. Array: : Ref. Int. Array(Ref. Int. Array &other) { data = other. data; refs = other. refs; (*refs)++; } void Ref. Int. Array: : operator =(Ref. Int. Array &other) { if(data == other. data) return; if(!--(*refs)) clear(); data = other. data; refs = other. refs; (*refs)++; }
Тестируем Ref. Int. Array int main() { Ref. Int. Array ria; { int count; scanf("%i", &count); Ref. Int. Array tmp = Ref. Int. Array(new int[count]); ria = tmp; } ria[4] = 81; printf("0 ria[4] = %in", ria[4]); Ref. Int. Array ria 2 = ria; ria = Ref. Int. Array(); printf("1 ria 2[4] = %in", ria 2[4]); ria 2 = ria 2; printf("2 ria 2[4] = %in", ria 2[4]); ria 2 = Ref. Int. Array(); return 0; }
Увиденного не развидеть