
- •Структура программы на языке Си. Этапы выполнения программы
- •1.1. Алфавит языка Си
- •1.2. Лексемы
- •1.3. Идентификаторы и ключевые слова
- •1.4. Знаки операций
- •1.5. Литералы (константы)
- •1.6. Комментарии
- •1.7. Общая структура программы на языке Си.
- •1.8. Функциональная и модульная декомпозиции
- •1.9. Этапы обработки программы.
- •1.10. Роль препроцессора.
- •1.11. Ошибки
- •2. Переменные и константы. Типы данных
- •2.1. Основные типы данных
- •2.2. Декларация (объявление) объектов
- •2.3. Константы в программах
- •2.4. Целочисленные константы
- •2.5. Константы вещественного типа
- •2.6. Символьные константы
- •2.7. Строковые константы
- •3. Обзор операций
- •3.1. Операции, выражения
- •3.2. Арифметические операции
- •3.3. Операции сравнения
- •3.4. Логические операции
- •4. Операции (продолжение).
- •4.1. Операция присваивания
- •Примеры недопустимых выражений:
- •4.2. Сокращенная запись операции присваивания
- •4.3. Преобразование типов операндов бинарных операций
- •4.4. Преобразование типов при присваивании.
- •4.5. Операция явного приведения типа
- •4.6. Операция «,» (запятая)
- •5. Стандартная библиотека языка Си
- •5.1. Стандартные математические функции
- •5.2. Потоковый ввод-вывод
- •5.3. Консольные функции вывода данных на экран
- •5.4. Консольные функции ввода информации
- •5.5. Ввод-вывод в оконных приложениях.
- •Советы по программированию
- •6. Операторы языка с.
- •7. Составление разветвляющихся алгоритмов
- •7.1. Условные операторы
- •If (выражение) оператор;
- •If (выражение) оператор 1 ;
- •If (выражение 1) оператор 1;
- •If (выражение 2) оператор 2;
- •If (выражение 3) оператор 3;
- •7.2. Оператор выбора альтернатив (переключатель)
- •7.3. Условная операция «? :»
- •8. Составление циклических алгоритмов
- •8.1. Оператор с предусловием while
- •8.2. Оператор цикла с постусловием do – while
- •8.3. Оператор цикла с предусловием и коррекцией for
- •8.4. Вложенные циклы.
- •9. Операторы передачи управления.
- •9.1. Оператор безусловного перехода goto
- •9.2. Операторы continue, break и return
- •10. Массивы
- •10.1. Одномерные массивы
- •10.2. Примеры алгоритмов, использующих одномерные массивы.
- •10.3. Многомерные массивы
- •10.4. Примеры алгоритмов, использующих двумерные массивы.
- •10.5. Компонента StringGrid
- •11. Размещение данных и программ в памяти пэвм
- •11.1. Общие понятия.
- •11.2. Кодирование целых чисел.
- •11.3. Кодирование вещественных чисел.
- •11.4. Кодирование символов.
- •Примеры кодов символов:
- •Стандартная часть таблицы символов (ascii)
- •Дополнительная часть таблицы символов
- •11.5. Операция sizeof
- •11.6. Побитовые логические операции. Операции над битами
- •11.7. Кодирование программы.
- •11.8. Регистры
- •12.1. Строки как нуль-терминированные массивы char.
- •12.2. Русификация консольных приложений.
- •12.3. Строки как переменные типа AnsiString.
- •12.4. Преобразования строковых типов.
- •12.5. Тип String в консольных приложениях.
- •13. Функции пользователя и классы памяти.
- •13.1. Сущность и предназначение функций.
- •13.2. Определение и вызов функции.
- •13.3. Прототип функции.
- •13.4. Область видимости.
- •13.5. Классы памяти объектов в языке Cи.
- •13.6. Разбиение программы на модули.
- •14. Структуры и объединения
- •14.1. Понятие структуры
- •14.2. Декларация структурного типа данных
- •14.3. Объявление структурных переменных
- •14.4. Обращение к полям структуры
- •14.5. Операции со структурой как единым целым
- •14.6. Вложенные структуры
- •14.7. Массивы структур
- •14.8. Размещение структурных переменных в памяти
- •14.9. Битовые поля
- •14.10. Объединения
- •15. Генерация псевдослучайных чисел.
- •16. Файлы в языке с
- •16.1. Типы файлов.
- •16.2. Открытие файла
- •16.3. Закрытие файла
- •16.4. Запись - чтение информации
- •А) Посимвольный ввод-вывод
- •Б) Построчный и форматированный ввод-вывод
- •В) Блоковый ввод-вывод
- •Int fflush(file *stream);
- •16.5. Текстовые файлы
- •16.6. Перенаправление стандартного ввода-вывода
- •16.7. Бинарные файлы
- •16.8. Дополнительные полезные функции
- •16.9. Простейший пример создания собственной базы данных
- •17. Указатели
- •17.1. Определение указателей
- •17.2. Связь указателей и массивов.
- •17.3. Операции над указателями (косвенная адресация)
- •17.4. Операции над указателями (косвенная адресация)
- •17.5. Массивы указателей.
- •17.6. Указатели на указатели.
- •17.7 . Указатели как параметры функций.
- •Void f1(int, const double *);
- •17.8 . Указатели на структуры
- •17.9. Ссылка
- •17.10. Указатели на функции
- •Id_функции(список аргументов);
- •18. Работа с динамической памятью
- •18.1. Динамическое выделение и освобождение памяти.
- •18.2. Создание одномерного динамического массива.
- •18.3. Создание двуxмерного динамического массива.
- •19. Операция typedef
- •20. Отладка и пошаговое выполнение программы
14.10. Объединения
Объединение - поименованная совокупность данных разных типов, размещаемых в одной и той же области памяти, размер которой достаточен для хранения наибольшего элемента.
Объединенный тип данных декларируется подобно структурному типу:
union ID_объединения {
описание полей
};
Пример описания объединенного типа:
union word {
int nom;
char str[20];
};
Пример объявления объектов объединенного типа:
union word p_w, mas_w[100];
Объединения применяют для экономии памяти в случае, когда объединяемые элементы логически существуют в разные моменты времени либо требуется разнотипная интерпретация поля данных.
Например, поток сообщений по каналу связи пусть содержит сообщения трех видов:
struct m1 {
char code;
float data[100]; };
struct m2 {
char code;
int mode; };
struct m3 {
char code, note[80]; };
Элемент code - признак вида сообщения. Удобно описать буфер (место для хранения) сообщений в виде
struct m123 {
char code;
union {
float data[100];
int mode;
char note[80]; };
};
Практически все вышесказанное для структур имеет место и для объединений.
Декларация данных типа union, создание переменных этого типа и обращение к полям объединений производится аналогично структурам.
Пример использования переменных типа union:
. . .
union W {
int a;
float b;
char s[5];
};
void main(void) {
W s;
s.a = 4;
printf(“\n Integer a = %d, Sizeof(s.a) = %d”, s.a, sizeof(s.a));
s.b = 1.5;
printf(“\n Float b = %f, Sizeof(s.b) = %d”, s.b, sizeof(s.b));
strcpy(s.s, “Minsk”);
printf(“\n Char[] a = %s, Sizeof(s.s) = %d”, s.s, sizeof(s.s));
printf(“\n Sizeof(s) = %d”, sizeof(s));
getch();
}
Результат работы программы:
Integer a = 4, Sizeof(s.a) = 2
Float b = 1.500000, Sizeof(s.b) = 4
Char[] a = Minsk, Sizeof(s.s) = 5
Sizeof(s) = 5
15. Генерация псевдослучайных чисел.
В языке Си есть возможность генерации т.н. псевдослучайных чисел, т.е. чисел, выглядящих для человека как случайные, хотя в действительности вычисляемых по некоторому алгоритму.
К числу функций, обеспечивающих генерацию псевдослучайных чисел, относятся random() и randomize(). Для их работы необходимо подключить заголовочный файл stdlib.h (годятся также и некоторые другие).
Собственно генерацию выполняет функция random. При обращении к ней в скобках надо указать число, задающее диапазон генерируемых чисел (обозначим его N). Результат функции - "случайное" целое число, равновероятно выбранное в диапазоне от 0 до N-1 (таким образом, получается N различных вариантов этого числа).
Если нам нужно случайное целое число в другом диапазоне, то достаточно прибавить к значению random() начало требуемого диапазона, "сдвинув" тем самым результат:
int a,b,x;
...
x=random(b-a+1)+a; // x - случайное число в диапазоне [a..b]
Аналогично можно получать и дробные числа.
Работа функции random() основана на использовании специальной статической ячейки памяти. При запуске программы эта ячейка получат некоторое значение (обычно 0), а затем при каждом обращении к функции random() новое очередное значение в этой ячейке вычисляется из предыдущего по достаточно сложному алгоритму. Исходя из текущего значения этой ячейки, вычисляется сам результат функции random(). Поэтому он не имеет никакой видимой связи с предыдущим ее результатом, что и создает "псевдослучайность" полученных чисел. Однако, при повторном запуске программы начальное значение этой ячейки вновь будет восстановлено, поэтому вся последовательность полученных псевдослучайных чисел повторится.
Если же мы хотим, чтобы последовательность генерируемых чисел различалась при каждом запуске программы, можно воспользоваться функцией randomize(). Она записывает в упомянутую ячейку значение текущего системного времени (с учетом сотых долей секунд, а также даты). Поскольку дата и время запуска программы не могут повториться (тем более - с точностью до сотых долей секунды), после вызова randomize() функция random() будет выдавать уже совершенно новую, практически непредсказуемую последовательность.
Поэтому обращение к randomize() достаточно сделать один раз в начале программы. Не стоит делать это в цикле, т.к. значение системного времени обновляется не более 100 раз в секунду, а цикл может выполниться быстрее, и тогда каждый вызов randomize() запишет в ячейку одно и то же значение, а следующие за ними вызовы random() дадут одинаковые результаты.
Пример программы, заполняющей массив случайными числами от 1 до 100:
int a[40], n, i;
...
randomize();
for (i=0; i<n; i++)
a[i]=random(100)+1;