- •Передачу параметров в функцию по значению, а не по ссылке (при этом передача по ссылке эмулируется с помощью указателей);
- •Области действия имён; (область видимости переменной).
- •Достоинства:
- •Представление целых чисел в эвм
- •Основные типы данных, операции над ними.
- •Операции
- •Преобразование типов
- •Особенности операций для вещественных чисел
- •3.1. Операторы и блоки.
- •3.2. Оператор if – else
- •3.3. Конструкция else-if.
- •3.4. Оператор switch
- •3.5. Циклы while и for
- •3.6. Цикл do-while
- •3.7. Операторы break и continue
- •3.8. Оператор goto и метки
- •3.9. Оператор return
- •Инвариант
- •Указатели
- •Массивы
- •Связь между указателями и массивами
- •Представление в эвм
- •Создание указателя на массив
- •Инициализация массивов
- •Операции над указателями
- •Замечание! 2 указателя нельзя суммировать, но можно прибавлять константу. Сравнивать допустимо только с указателями того же типа или с null
- •Метод барьера в линейном поиске
- •Метод барьера при быстрой сортировке массива
- •Сортировка методом вставки. В отсортированной части массива последний элемент – барьер.
- •Процедуры
- •Локальные и глобальные переменные
- •Локальные переменные
- •Глобальные переменные
- •Средний и наихудший случай
- •Дополнительно (то же самое)
- •Анализ эффективности алгоритмов не должен зависеть от:
- •Временная сложность алгоритма
- •Некоторые свойства временной сложности алгоритма (функции f(n) )
- •Характеристики рекурсии
- •Виды рекурсии
- •Когда не нужно применять рекурсию
- •Применение эвристик.
- •Метод ветвей и границ (доп. Из Wikipedia)
- •Алгоритм Неймана.
- •Линейный конгруэнтный метод
- •Выбор параметров, выбор модуля и множителя.
- •Сдвиг на несколько символов: Если не совпадает , то сдвигаем образ вправо до последнего его стоп-символа. Если «стоп-символа» вообще нет в образе, то образ смещается за этот символ.
- •Вопросы на экзамен по информатике:
- •Перевести отрицательное целое число (он любое может назвать) в дополнительный код.
- •Есть ли смысл применять метод барьера в поиске подстроки в строке?
- •Задачи на экзамене:
- •Задача о Ханойских башнях
- •Бинарный поиск элемента в массиве
- •Сумма цифр в числе
- •Число различных элементов в символьном массиве
- •Сгенерировать все перестановки в целочисленном массиве (Билет 1).
- •Функция, возвращающая I и j такие, чтобы сумма эл-тов в I-ой строке равнялась сумме в j-ом столбце.
- •Есть одномерный массив целых чисел и нужно построить функцию, получающую на вход вещественное число X и возвращающую индекс элемента, который ближе всего к этому числу.
- •Функция strcpy (char *s1, char *s2) , билет 12.
- •Реализация strcat(); Билет 7.
- •Билет 5. Функция, выдаёт частное и остаток от деления X на y, нельзя пользоваться / и % .
- •Метод генерации случайной перестановки ( Тасование Фишера-Йетса).(не ок)
Билет 1. Концепция языка Си, его достоинства и недостатки.
Концепция: Си создавался с одной важной целью: сделать более простым написание больших программ с минимумом ошибок по правилам процедурного программирования*, не добавляя на итоговый код программ лишних накладных расходов для компилятора.
*(Когда выполнение программы сводится к последовательному выполнению операторов с целью преобразования исходного состояния памяти, то есть значений исходных данных, в заключительное, то есть в результаты. Задачи разбиваются на шаги и решаются шаг за шагом).
Язык СИ является процедурным языком программирования, т.е. он предоставляет возможность программисту определять каждый шаг в процессе решения задачи. Особенность таких языков программирования состоит в том, что задачи разбиваются на шаги и решаются шаг за шагом. Используя процедурный язык, программист определяет языковые конструкции для выполнения последовательности алгоритмических шагов. Последовательно выполняемые операторы можно собрать в подпрограммы. Он относится к императивной парадигме программирования.
// Парадигма программирования - совокупность идей и понятий, определяющих стиль написания компьютерных программ (подход к программированию).
//Императивное программирование - описывает процесс вычисления в виде инструкций, изменяющих состояние программы. Императивная программа очень похожа на приказы, выражаемые повелительным наклонением в естественных языках, то есть это последовательность команд, которые должен выполнить компьютер.
//Декларативное - Декларативный стиль программирования (декларативное программирование) представляет собой совокупность утверждений, описывающих фрагмент предметной области или сложившуюся ситуацию; описывается результат (его свойства), а не методы его достижения.
Программируя в декларативном стиле, программист должен описать, что нужно решать.
Си имеет некоторые особенности:
Простую языковую базу, из которой вынесены в библиотеки многие существенные возможности, вроде математических функций или функций управления файлами;
Возможность типизации данных. Имеется система типов, предохраняющая от бессмысленных операций (попытка деления числа на строку и так далее.).
Язык Си имеет слабую типизацию данных, поскольку имеет неявное приведение типов, что делает его менее типобезопасным.
- Неявное приведение – выполняется компилятором, при осуществлении арифметических операций, при выполнении операций сравнения и при присваивании переменные разных типов неявно приводятся к одному типу. Возможна потеря точности – отсекается дробная часть
-Явное приведение – выполняется программистом. X = (int)y.
Тип представляет собой классификацию информационных сущностей (например, таких как значения или выражения), определяющую возможность их использования. Понятие имеет несколько определений, которые могут частично пересекаться или приводить к тождественному содержанию. Наиболее принципиально различимых, хотя и не противоречащих друг другу, определений два: декларативное — тип есть множество допустимых значений, которые могут принимать данные, принадлежащие к этому типу и процедурное — тип определяется поведением, т.е. набором действий, которые можно осуществлять над данными, принадлежащими к этому типу.
Использование препроцессора для, например, определения макросов и включения файлов с исходным кодом;
Препроцессор осуществляет подготовку программы к компиляции, включает содержимое одних файлов в другие, заменяет в тексте исходного кода имена констант на их значения, удаляет символы конца строки, замена комментариев на пустые строки. Что-то препроцессор делает по умолчанию, а какие-то его действия программируются с помощью специальных директив в исходном коде. Директивы препроцессора начинаются со знака # и заканчиваются переходом на новую строку.
#define макросов (#define pr printf(“\n”)) Операторы препроцессора могут появляться в любом месте программы и их действие распространятся на весь исходный файл.
Условная компиляция В общем виде директива #if выглядит таким образом:
#if константное выражение
последовательность операторов
#endif
Если находящееся за #if константное выражение истинно, то компилируется код, который находится между этим выражением и #endif. В противном случае этот промежуточный код пропускается. Директива #endif обозначает конец блока #if. Например,
/* Простой пример #if. */
#include <stdio.h>
#define MAX 100
int main(void)
{
#if MAX>99
printf("Компилирует для массива, размер которого больше 99.\n");
#endif
return 0;
}
Это программа выводит сообщение на экран, потому что МАХ больше 99. В этом примере показано нечто очень важное. Значение выражения, находящегося за директивой #if, должно быть вычислено во время компиляции. Поэтому в этом выражении могут находиться только ранее определенные идентификаторы и константы, — но не переменные.
Непосредственный доступ к памяти компьютера через использование указателей.
Передачу параметров в функцию по значению, а не по ссылке (при этом передача по ссылке эмулируется с помощью указателей);
Области действия имён; (область видимости переменной).
Обозначает область программы, в пределах которой идентификатор (имя) некоторой переменной продолжает быть связанным с этой переменной и возвращать её значение. За пределами области видимости тот же самый идентификатор может быть связан с другой переменной, либо быть свободным (не связанным ни с какой из них). Локальные (объявляются внутри функции и не доступны вне ее) и глобальные переменные.
Структуры и объединения — определяемые пользователем собирательные типы данных, которыми можно манипулировать как одним целым; Структуру можно использовать как тип данных для переменной.
Переносимость
Стандарт языка Си говорит, что программа может быть, как переносимой, так и не переносимой в случае, если она использует системные функции операционной системы.
C переносимый, поэтому в нём базовые целочисленные типы (short, int и др.) не имеют строго установленного размера, а зависят от платформы. Однако эти типы не были бы переносимы, если бы их размеры были совершенно произвольные: стандарт устанавливает минимальные диапазоны принимаемых значений для всех базовых целочисленные типов.
Делается ставка на хорошо прослеживаемые тенденции и культуру создания компактных библиотек, которые представляют собой легковесные абстракции простых типов. Сравните это с объектно-ориентированными языками, где в базах кода зачастую развиваются огромные взаимозависимые интерфейсы из сложных типов, где аргументы и возвращаемые типы оказываются сложнее. Такая сложность становится фрактальной: каждый тип является классом, определенным в контексте методов с аргументами и возвращаемыми типами, которые, в свою очередь, также могут быть сложными возвращаемыми типами. ОО системы типов не провоцируют такую фрактальную сложность, но они повышают вероятность ее возникновения. C также не исключает возможности свернуть на кривую дорожку, но сделать это сложнее. В C обычно создаются более простые и неглубокие типы с меньшим количеством зависимостей. Они проще для понимания и для отладки.
Системное программирование. Вид программирования, который заключается в работе с системным ПО. Благодаря близости по скорости выполнения программ, написанных на Си, к языку ассемблера, этот язык получил широкое применение при создании системного программного обеспечения и прикладного программного обеспечения. Язык программирования Си оказал существенное влияние на развитие индустрии программного обеспечения, а его синтаксис стал основой для таких языков программирования как C++, C#, Java и D.
Универсальность. Универсальность языка Си обусловлена тем, что компиляторы существуют почти под все операционные системы.
Язык «высокого» уровня. Характеризуется краткостью выражений, современными управляющими конструкциями и структурами данных, богатым набором операций. Не слишком объёмный, но отсутствие в нём каких-либо ограничений делает его более удобным, чем языки, считающиеся более мощными.
Структурное программирование - в соответствии с данной методологией любая программа строится без использования оператора goto из трёх базовых управляющих структур: последовательность, ветвление, цикл; кроме того, используются подпрограммы. При этом разработка программы ведётся пошагово, методом «сверху вниз». Для удобства – «синтаксический сахар», например, массивы и указатели.
Недостатки: В связи со сравнительно низким уровнем языка многие случаи неправильного использования опасных элементов не обнаруживаются и не могут быть обнаружены ни при компиляции, ни во время исполнения. Это часто приводит к непредсказуемому поведению программы. Иногда в результате неграмотного использования элементов языка появляются уязвимости в системе безопасности. Но использования многих таких элементов можно избежать. Чаще всего источником ошибки является обращение к несуществующему элементу массива. Несмотря на то, что Си непосредственно поддерживает статические массивы, он не имеет средств проверки индексов массивов (проверки границ). Частный случай такой ошибки называется ошибкой переполнения буфера. Ошибки такого рода приводят к большинству проблем с безопасностью.
Возможны ошибки из-за слабой типизации.
Другим потенциальным источником опасных ситуаций служит механизм указателей. Указатель может ссылаться на любой объект в памяти, и неправильное использование указателей может порождать непредсказуемые эффекты. К примеру, в результате неверных арифметических операций над указателем, указывать в произвольное место памяти; работа с таким указателем на незащищённых платформах это может привести к порче произвольных данных в памяти, причём эта порча может проявиться в самые произвольные моменты времени и намного позже момента порчи. Также, область динамической памяти, на которую ссылается указатель, может быть освобождена (и даже выделена после этого под другой объект) — такие указатели называются «висячими». Или, наоборот, после манипуляций с указателями на область динамической памяти может не остаться ссылок, и тогда эта область, называемая «мусором» (garbage), никогда не будет освобождена, что может приводить к «утечкам памяти» в программе.
Проблемой является также то, что автоматически и динамически создаваемые объекты не инициализируются и они могут содержать значения, оставшееся в памяти от ранее удалённых объектов. Такое значение полностью непредсказуемо, оно меняется от одной машины к другой, от запуска к запуску, от вызова функции к вызову. Если программа использует такое значение, то результат будет непредсказуемым и не обязательно проявится сразу.
Ещё одной распространённой проблемой является то, что память не может быть использована снова, пока она не будет освобождена программистом с помощью функции free(). В результате программист может случайно забыть освобождать эту память, но продолжать её выделять, занимая всё большее и большее пространство. Это обозначается термином утечка памяти. Наоборот, возможно освободить память слишком рано, но продолжать её использовать. Из-за того, что система выделения может использовать освобождённую память по-другому, это ведёт к непредсказуемым последствиям.
Характерным недостатком языка стала относительно высокая сложность изучения по сравнению с языками Паскаль и Бейсик. Язык Си предъявляет достаточно высокие требования к квалификации использующего его программиста.
