
- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор 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
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Указатели на константы
Модификатор const может использоваться для защиты объекта от возможного изменения со стороны функции. То есть, когда указатель передается в функцию, функция может модифицировать оригинал переменной, на которую указывает указатель. Если указатель определен как const, то функция не сможет модифицировать объект. Например, функция sp_to_dash() в следующей программе выводит дефис вместо каждого пробела в передаваемой строке. То есть строка «this is а test» будет напечатана как «this-is-a-test». Использование const при объявлении параметра гарантирует, что код функции не может модифицировать объект, на который указывает параметр. #include <stdio.h> void sp_to_dash(const char *str); int main(void) { sp_to_dash ("this is a test"); return 0; } void sp_to_dash (const char *str) { while(*str) { if(*str == ' ') printf ("%c", '-'); else printf("%c", *str); str++; } } Если написать sp_to_dash() таким образом, чтобы она модифицировала строку, то она не будет компилироваться. Например, если написать sp_to_dash() /* Это неверно */ void sp_to_dash (const char *str) { while(*str) { if(*str == ' ') *str = '-'; /* невозможно выполнить */ printf("%c", *str); str++; } } то возникнет ошибка времени компиляции.
Многие функции в стандартных библиотеках используют const при объявлении своих параметров. Это гарантирует сохранность объектов, на которые указывают параметры.
Указатели на константы
Модификатор const может использоваться для защиты объекта от возможного изменения со стороны функции. То есть, когда указатель передается в функцию, функция может модифицировать оригинал переменной, на которую указывает указатель. Если указатель определен как const, то функция не сможет модифицировать объект. Например, функция sp_to_dash() в следующей программе выводит дефис вместо каждого пробела в передаваемой строке. То есть строка «this is а test» будет напечатана как «this-is-a-test». Использование const при объявлении параметра гарантирует, что код функции не может модифицировать объект, на который указывает параметр. #include <stdio.h> void sp_to_dash(const char *str); int main(void) { sp_to_dash ("this is a test"); return 0; } void sp_to_dash (const char *str) { while(*str) { if(*str == ' ') printf ("%c", '-'); else printf("%c", *str); str++; } } Если написать sp_to_dash() таким образом, чтобы она модифицировала строку, то она не будет компилироваться. Например, если написать sp_to_dash() /* Это неверно */ void sp_to_dash (const char *str) { while(*str) { if(*str == ' ') *str = '-'; /* невозможно выполнить */ printf("%c", *str); str++; } } то возникнет ошибка времени компиляции.
Многие функции в стандартных библиотеках используют const при объявлении своих параметров. Это гарантирует сохранность объектов, на которые указывают параметры.
Указатели и массивы
Массивы и указатели тесно связаны между собой. Рассмотрим следующий фрагмент: char str [80], *p1; p1 = str; Здесь p1 устанавливается на первый элемент массива str. Если необходимо получить доступ к пятому элементу str, то следует написать str[4] или * (p1 +4) Оба оператора возвращают пятый элемент. Следует помнить, что индексация массивов начинается с нуля, поэтому для индексации str используется 4. К указателю p1 добавляется 4 для получения пятого элемента, поскольку p1 указывает на первый элемент str. (Надо помнить, что имя массива без индекса возвращает начальный адрес массива, то есть адрес первого элемента.)
С предоставляет два метода доступа к элементам массива. Это важно, поскольку арифметические действия с указателями могут выполняться быстрее, чем индексация массива. Поскольку скорость работы программы часто играет важную роль, использование указателей для доступа к элементам довольно типично в С.
Рассмотрим две упрощенные версии стандартной библиотечной функции puts() для демонстрации данных методов. Один вариант использует индексацию массива, а другой - указатели. Функция puts() выводит строку на стандартное устройство вывода: /* Использование массива */ int puts (const char *s) { register int t; for(t=0; s [t]; ++t) putchar (s [t]); return 1; } /* использование указателя */ int puts (const char *s) { while (*s) putchar (*s++); return 1; } Профессиональные программисты могут найти вторую версию более легкой для чтения и понимания, фактически, версия с указателями демонстрирует типичный способ написания подпрограмм в С.