
- •Происхождение языка с
- •Язык среднего уровня
- •Структурированный язык
- •Язык программирования
- •Компиляторы против интерпретаторов
- •Вид программ на с
- •Библиотеки и компоновка
- •Раздельная компиляция
- •Карта памяти с-программы
- •Переменные, константы, операторы и выражения
- •Идентификаторы
- •Типы данных
- •Модификаторы типов
- •Модификаторы доступа
- •Объявление переменных
- •Локальные переменные
- •Формальные параметры
- •Глобальные переменные
- •Спецификаторы хранения
- •Статические переменные
- •Статические локальные переменные
- •Статические глобальные переменные
- •Регистровые переменные
- •Оператор присваивания
- •Многочисленное присваивание
- •Преобразование типов при присваивании
- •Инициализация переменных
- •Константы
- •Символьные константы с обратным слэшем
- •Операторы
- •Арифметические операторы
- •Увеличение и уменьшение
- •Операторы отношения и логические операторы
- •Битовые операторы
- •Оператор ?
- •Операторы указания & и *
- •Оператор 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
- •Операторы препроцессора # и ##
- •Предопределенные макросы
- •Комментарии
Оператор присваивания
Общий вид оператора присваивания следующий:
имя_переменной = выражение; где выражение может быть как простой одиночной константой, так и сложной комбинацией переменных, операторов и констант. Как в Бейсике и Фортране, в С используется знак равенства для отображения операции присваивания (не так, как в Паскале или Модуле-2, где используется конструкция :=). В левой части оператора присваивания должна стоять переменная, а не функция или константа.
Многочисленное присваивание
С позволяет присваивать нескольким переменным одни и те же значения путем использования многочисленных присваиваний в одном операторе. Например, данный фрагмент программы присваивает переменным х, у и z значение 0:
х = у = z = 0;
В профессиональных программах переменным часто присваиваются стандартные значения с использованием данного метода.
Преобразование типов при присваивании
Преобразование типов предназначено для ситуации, в которой переменные одного типа смешиваются с переменными другого типа. Когда возникает подобная ситуация в операторе присваивания, используется правило преобразования типов: значение справа (выражение) от оператора присваивания преобразуется к типу объекта, стоящего слева (целевой переменной). Это демонстрируется следующим примером: int х; char ch; float f; void func(void) { ch = х; /* 1 */ х = f; /* 2 */ f = ch; /* 3 */ f = x; /* 4 */ }
В строке 1 левые, старшие, биты целочисленной переменной х обрубаются, оставляя в ch младшие 8 битов. Если х содержит число между 256 и 0, то ch и х будут иметь одинаковое значение Иначе значение ch будет содержать только младший набор битов переменной х. В строке 2 х получает целую часть переменной f. В строке 3 f получает 8-битное целое число, хранящееся в ch преобразованное к формату с плавающей точкой. В строке 4 f получает значение целочисленной переменной х, преобразованное к формату с плавающей точкой.
Когда происходит преобразование из целого числа к символу, из длинного целого — к целому и из целого — к короткому целому, то старшие биты будут потеряны. Когда используется 16-битное целое, это означает, что 8 бит будут потеряны при преобразовании от целого к символу и 16 бит будут потеряны при преобразовании от длинного целого к целому.
Таблица содержит все преобразования типов. Следует помнить два важных момента, которые могут повлиять на переносимость создаваемого кода:
Таблица: Обычные результаты преобразования типов |
||
Целевой тип |
Исходный тип |
Возможные потери информации |
signed char |
unsigned char |
Если значение > 127, то результат станет отрицательным числом |
char |
short int |
Старшие 8 бит |
char |
int (16 бит) |
Старшие 8 бит |
char |
int (32 бита) |
Старшие 24 бита |
short int |
int (16 бит) |
Нет |
short int |
int (32 бита) |
Старшие 16 бит |
int (16 бит) |
long int |
Старшие 16 бит |
int (32 бита) |
long int |
Нет |
float |
double |
Точность, результат округляется |
double |
long double |
Точность, результат округляется |
Преобразование из int в float или из float в double и тому подобное не добавляет точности. Такого рода преобразования только изменяют формат представления значения.
Некоторые компиляторы С (и процессоры) всегда трактуют переменные типа char как положительные, независимо от того, какое значение было при преобразовании к целому или плавающему типам. Другие компиляторы могут трактовать переменную типа char как знаковую, где числа, большие, чем 127, трактуются как отрицательные (как делает Borland С++). В целом следует использовать переменные типа char для символов, a int, short int или signed char когда необходимо избежать проблем с переносимостью.
Для получения преобразования, не указанного в таблице, надо просто пошагово преобразовывать типы, пока не получится нужный тип. Например, для преобразования из double в int сначала следует преобразовать double в float, а затем float в int.
При использовании компьютерного языка типа Паскаль, где запрещено автоматическое преобразование типов, можно подумать, что С — слишком скользкий язык. Следует помнить, что С разрабатывался для облегчения жизни программистов, предоставляя возможность работать на нем, а не на ассемблере. С этой целью С позволяет осуществлять такие преобразования типов.