- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор sizeof
- •Оператор «запятая»
- •Операторы [ ] u ()
- •Приоритеты в с
- •Выражения
- •Преобразование типов в выражениях
- •Принудительные преобразования
- •Пробелы и круглые скобки
- •Сокращенные операторы в с
- •Операторы управления программой
- •Истина и ложь в с
- •Операторы выбора
- •Вложенные if
- •Лесенка if-else-if
- •Оператор ?
- •Вложенные операторы switch
- •Вариации цикла for
- •Бесконечный цикл
- •Циклы for без тела
- •Метки и goto
- •Функции
- •Оператор return
- •Выход из функции
- •Возвращаемые значения
- •Значения, возвращаемые функцией main()
- •Правила видимости для функций
- •Аргументы функции
- •Передача по значению и передача по ссылке
- •Создание передачи по ссылке
- •Передача массивов в функции
- •Аргументы функции main()
- •Функции, возвращающие нецелые значения
- •Использование прототипов функции
- •Прототипы стандартных библиотечных функций
- •Создание прототипов функций, не имеющих параметров
- •Возврат указателей
- •Рекурсия
- •Сопоставление классического и современного объявления параметров
- •Указатели на функции
- •Особенности реализации
- •Параметризированные функции и функции общего назначения
- •Эффективность
- •Массивы
- •Одномерный массив
- •Создание указателя на массив
- •Передача одномерных массивов в функции
- •Двумерные массивы
- •Массивы строк
- •Многомерные массивы
- •Индексация с помощью указателей
- •Размещение массивов
- •Инициализация массива
- •Инициализация безразмерных массивов
- •Пример программы игры в крестики-нолики
- •Указатели
- •Указатели - это адреса
- •Переменные-указатели
- •Операторы для работы с указателями
- •Выражения с указателями
- •Присваивание указателей
- •Арифметические действия с указателями
- •Сравнение указателей
- •Динамическое выделение и указатели
- •Указатели на константы
- •Указатели на константы
- •Указатели на константы
- •Указатели и массивы
- •Указатели на символьные массивы
- •Массивы указателей
- •Указатели на указатели - многочисленное перенаправление
- •Инициализация указателей
- •Указатели на функции
- •Проблемы, связанные с указателями
- •Структуры, объединения и определяемые пользователем типы
- •Структуры
- •Доступ к членам структуры
- •Присваивание структур
- •Массивы структур
- •Программа инвентаризации
- •Передача структур в функции
- •Передача членов структур в функции
- •Передача всей структуры в функцию
- •Указатели на структуры
- •Объявление указателя на структуру
- •Использование указателей на структуру
- •Массивы и структуры в структурах
- •Битовые поля
- •Объединения
- •Перечисления
- •Использование sizeof для обеспечения переносимости
- •Ввод, вывод, потоки и файлы
- •Потоки и файлы
- •Текстовые потоки
- •Двоичные потоки
- •Консольный ввод/вывод
- •Чтение и запись символов
- •Чтение и запись строк: gets() и puts()
- •Форматированный консольный ввод/вывод
- •Печать символов
- •Вывод чисел
- •Вывод адресов
- •Спецификатор %n
- •Модификаторы формата
- •Спецификатор минимума ширины поля
- •Спецификатор точности
- •Выровненный вывод
- •Работа с другими типами данных
- •Модификаторы * u #
- •Спецификаторы формата
- •Ввод чисел
- •Ввод беззнаковых целых
- •Чтение отдельных символов с помощью scanf()
- •Чтение строк
- •Ввод адреса
- •Спецификатор %n
- •Использование множества сканирования
- •Пропуск нежелательных специальных символов
- •Обычные символы в управляющей строке
- •В scanf() следует передавать адреса
- •Модификаторы формата
- •Подавление ввода
- •Файловая система ansi с
- •Указатель на файл
- •Открытие файла
- •Запись символа
- •Чтение символа
- •Использование fopen(), getc(), putc() и fclose()
- •Использование feof()
- •Две расширенные функции: getw() и putw()
- •Работа со строками: fgets() и fputs()
- •Fseek() и произвольный доступ
- •Удаление файлов
- •Работа с консолью
- •Препроцессор и комментарии
- •Директивы условной компиляции
- •Использование defined
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Метки и goto
Хотя goto уже давно не рекомендуют использовать, он по-прежнему используется в программах. Мы не будем рассматривать целесообразность его использования с точки зрения элегантности управления программой. Следует заметить, что не существует таких ситуаций, где он был бы единственным решением. Общепринято, что он может быть полезен в некоторых ситуациях, goto используется довольно редко. (В языках типа С, имеющих богатый набор структур управления и предоставляющих дополнительные элементы управления типа break и continue, в нем нет необходимости.) Большинство программистов знают, что goto может легко запутать программу и сделать ее практически нечитабельной. Тем не менее, бывают моменты, когда goto не только не усложняет программу, но даже ее упрощает.
goto требует наличия меток для работы. Метка - это корректный идентификатор С, завершаемый двоеточием. Метка должна находиться в той же функции, что и goto. Например, цикл от 1 до 100 может быть записан с использованием goto и меток следующим образом: х = 1; loop1: х++; if (х < 100) goto loop1;
Одним из хороших способов использования goto является выход из нескольких уровней вложения. Например: for(...) { for (...) { while (...) { if (...) goto stop; ... } } } printf("error in program\n"); Уничтожение goto приведет к необходимости выполнения дополнительных проверок. Простой оператор break здесь не работает, поскольку он может выйти только из самого нижнего цикла.
Если проверяется каждый цикл, то код будет выглядеть следующим образом: done = 0; for(...) { for(...) { while (...) { if (...) { done = 1; break; } ... if(done) break; } if(done) break; }
Следует использовать goto как можно реже. Но если без него код трудно читать или критична cкорость работы программы, то использование goto может быть наилучшим выходом.
Функции
Функции - это базовые блоки С, в которых выполняются все операции. Стандартный вид функций следующий: спецификатор_типа имя_функции (список параметров) { тело функции } Спецификатор_типа определяет тип возвращаемого функцией значения с помощью оператора return. Это может быть любой допустимый тип. Если тип не указан, предполагается, что функция возвращает целочисленные значения. Список параметров - это разделенный запятыми список переменных, получающий значение аргументов при вызове функции. Функция может быть без параметров и в таком случае список параметров содержит ключевое слово void.
Оператор return
Оператор return имеет два назначения. Во-первых, немедленный выход из функции. То есть он осуществляет выход в вызывавший функцию код. Во-вторых, может использоваться для возврата значения. Здесь рассмотрены оба назначения.
Выход из функции
Имеется два способа окончания работы функции и передачи управления вызывающему коду. Первый способ предполагает достижение последнего оператора функции, после чего работа функции заканчивается при встрече }. (Конечно, фигурной скобки на самом деле нет в объектном коде, но никто не мешает нам так думать.) Например, следующая функция выводит на экран строку: void pr_reverse(char *s) { register int t; for(t=strlen(s) -1; t > -1; t-) printf ("%c", s [t]); } После отображения строки функция ничего не делает, поэтому управление передается вызвавшему ее коду.
Тем не менее, не многие функции используют данный метод окончания своего выполнения. Большинство функций используют оператор return для окончания выполнения с целью возврата значения или упрощения кода функции и увеличения его эффективности путем создания нескольких точек выхода. Важно запомнить, что функция может иметь несколько операторов return. Например, функция, показанная ниже, возвращает или индекс первого появления подстроки, указываемой в s1, в строке, указываемой в s2, или —1, если не обнаружено совпадений: int find_substr (char *s1, char *s2) { register int t; char *p, *p2; for(t=0; s1[t]; t++) { p = &s1[t]; p2 = s2; while (*p2 && *p2==*p) { p++; p2++; } if(!*p2) return t; } return -1; }
Надо обратить внимание, как два оператора return упрощают функцию.
