
- •Синтаксис языка c. Структура программы. Характеристика функции main.
- •Директивы препроцессора (основные).
- •Базовые типы данных.
- •Декларация объектов программы на языке c, атрибуты: тип, класс памяти и область действия.
- •Константы в программах на языке c.
- •Функции вывода информации. Использование модификаторов и управляющих последовательностей.
- •Функции ввода информации.
- •Ввод/вывод потоками (cin, cout).
- •Синтаксис операторов языка c, операторы-выражения, управляющие операторы в языке с.
- •Арифметические операции, преобразование типов операндов арифметических операций. Средство "typedef".
- •Сокращенная запись операции присваивания
- •X##; - постфиксную.
- •Операции отношений (сравнения) и логические операции. Операции сравнения
- •Логические операции
- •Побитовые логические операции, операции над битами
- •Операторы передачи управления goto, continue, break, return.
- •Ветвящийся алгоритм. Условный оператор if, условная операция «? :».
- •If (условие ) оператор1;
- •If (условие1) оператор1;
- •Оператор выбора альтернатив (переключатель) switch.
- •Операция ",".
- •Циклический алгоритм. Оператор с предусловием while.
- •Оператор цикла с постусловием do - while.
- •Оператор цикла с предусловием и коррекцией for.
- •Функции в с. Способы описания функции, операция вызова функции.
- •Указатели как тип данных. Операции * и &. Операции над указателями.
- •Одномерные массивы и связь с указателями.
- •Cтроковые данные в с. Библиотечные функции для их обработки.
- •Указатель на указатель, многомерные массивы.
- •Динамическая память, функции и операции работы с памятью.
- •Указатели на функцию
- •Тип данных «структура», общая характеристика.
- •Файлы в с. Типы файлов, понятие файловой переменной и увязка ее с физическим файлом.
- •Текстовые файлы.
- •Основные режимы работы с бинарными файлами, последовательный и прямой доступ.
Указатели на функцию
В языке Си идентификатор функции является константным указателем на начало функции в оперативной памяти и не может быть значением переменной. Но имеется возможность декларировать указатели на функции с которыми можно обращаться как с переменными (например, можно создать массив, элементами которого будут указатели на функции).
Рассмотрим методику работы с указателями на функции:
1. Как и любой объект языка Си, указатель на функции необходимо декларировать. Формат объявления указателя на функции следующитип (*переменная-указатель) (список параметров);
т.е. декларируется указатель, который можно устанавливать на функции, возвращающие результат указанного типа и имеют указанный список параметров. Наличие первых круглых скобок обязательно, так как без них –это декларация функции, которая возвращает указатель на результат своей работы указанного типа и имеет указанный список параметров. Например, объявление вида:
float (*p_f) (char, float);
говорит о том, что декларируется указатель p_f, который можно устанавливать на функции, возвращающие вещественный результат и имеющие два параметра: первый – символьного типа, а второй – вещественного типа.
2. Идентификатор функции является константным указателем, поэтому для того чтобы установить переменную-указатель на конкретную функцию, достаточно ей присвоить идентификатор этой функции:
переменная-указатель = имя_функции; Например, имеется функция с прототипом
float f1(char, float);
тогда операция
p_f = f1;
установит указатель p_f на данную функцию.
3. Вызов функции после установки на нее указателя выглядит так:
(*переменная-указатель)(список аргументов);
или
переменная-указатель (список аргументов);
После таких действий кроме стандартного обращения к функции
имя_функции(список аргументов);
появляется еще два способа вызова функции:
(*переменная-указатель)(список аргументов); или
переменная-указатель (список аргументов);
Последнее справедливо, так как p_f также является адресом начала функции в оперативной памяти. Для нашего примера к функции f1 можно обратиться следующими способами:
f1(‘z’, 1.5); // Обращение к функции по имени
(* p_f)(‘z’, 1.5); // Обращение к функции по указателю
p_f(‘z’, 1.5); // Обращение к функции по имени указателя
4. Пусть имеется вторая функция с прототипом:
float f2(char, float);
тогда, переустановив указатель p_f на эту функцию: p_f = f2;
имеем опять три способа ее вызова:
f2(‘z’, 1.5); // по имени функции
(* p_f)(‘z’, 1.5); // по указателю на функцию
p_f(‘z’, 1.5); // по имени указателя на функцию
Основное назначение указателей на функции – это обеспечение возможности передачи идентификаторов функций в качестве параметров в функцию, которая реализует некоторый вычислительный процесс, используя формальное имя вызываемой функции.
Тип данных «структура», общая характеристика.
Структура объединяет логически связанные данные разных типов. Структурный тип данных определяется описанием шаблона:
struct имя_структуры {
описание полей;
};
между символами } и ; иногда помещают список декларируемых структурных переменных, при этом «имя_структуры» можно опустить.
Описание полей производится обычным способом, ограничений на тип элементов нет.
Пример определения структурного типа:
struct person
{
char fio[72];
int dlg;
struct person *next;
};
Интерпретация объекта типа struct person:
fio |
dlg |
next |
72 |
2 |
4 |
длина в байтах
Структурный тип "struct имя_структуры" можно использовать для декларации структурных переменных, массивов, функций и т.д.
struct person teacher; // структурная переменная
struct person student[100]; // массив структур
Предыдущий пример можно записать кратко:
struct person {
char fio[72];
int dlg;
struct person *next;
} teacher, student[100];
Элементом структуры могут быть битовые поля (строки битов): struct fields {
unsigned int flag:1;
unsigned int mask:10;
unsigned int code:5; };
после символа « : » указывается длина битового поля, не превышающая разрядность поля типа int.
Битовые поля размещаются последовательно в поле типа int, при нехватке места для очередного битового поля - переход на следующее поле типа int. Возможно объявление безымянных битовых полей, а длина поля 0 означает необходимость перехода на очередное поле int:
struct areas {
unsigned f1:1;
:2; /* Безымянное поле длиной 2 бита */
unsigned f2:5;
:0 /* Признак перехода на следующее поле int */
unsigned f3:5;
float data; /* Структура может содержать */
char buffs[100];/* элементы любых типов данных */
};
Битовые поля могут использоваться в выражениях как целые числа соответствующей длине поля разрядности в двоичной системе счисления. Единственное отличие этих полей от обычных объектов - запрет операции определения адреса (&). Следует учитывать, что использование битовых полей снижает быстродействие программы по сравнению с представлением данных в полных полях из-за необходимости выделения битового поля.
Структурный тип данных удобно применять для группового управления манипулирования логически связанными объектами. Параметрами таких операций являются адрес и размер структуры.
Примеры групповых операций:
- захват и освобождение памяти для объекта, представленного совокупностью не обязательно однотипных данных;
- запись и чтение данных, хранящихся на внешних носителях как физические и/или логические записи с известной структурой.
Обращение к элементам структур производится посредством:
а) операции принадлежности (.) в виде:
имя_структуры_или_объединения.имя_элемента
или
(*указатель_структуры_или_объединения).имя_элемента
б) операции косвенной адресации (->) в виде:
указатель_структуры_или_объединения -> имя_элемента
Примеры обращения:
teacher.next
area->bin
buffer[i].byte[1]
Вложенные структуры, указатели на структуру, массивы структур.
Структуры могут быть вложенными, т.е. поле структуры может быть связующим полем с внутренней структурой, описание которой должно предшествовать по отношению к основному шаблону.
Например, в структуре person, содержащей Ф.И.О. и дату рождения, сделать дату рождения внутренней структурой date по отношению к структуре person. Шаблон такой конструкции будет выглядеть следующим образом:
struct date
{
int day, month, year;
};
struct person
{
char fio[40];
struct date f1;
} ;
Объявляем переменную и указатель на переменные такой структуры:
struct person a, *p;
Инициализируем указатель p адресом переменной а: p =&a;
Тогда обращение к полям структурной переменной a будет следующим:
a .fio
a.f1.day
a.f1.montha.f1.year
или
p->fio
p->f1.day
p->f1.month
p->f1.year
Структурный тип может быть использован для декларации массивов, элементами которых являются структурные переменные, например:
struct person spisok[100]; - spisok - массив структур;
или
struct person
{
char fio[40];
int day, month, year;
} spisok[100];
В данном случае обращение к полю, например, day i-й записи может быть выполнено одним из следующих способов:
spisok[i].day *(spisok+i).day
(spisok+i)->day.
можно передавать отдельные элементы). Но существует возможность обойти это ограничение, используя в качестве аргумента указатель на структуру. Описание
struct anketa *uk;
говорит , что uk - указатель на структуру типа anketa. Обозначение относится к конкретному элементу структуры и означает выборку этого элемента, например: uk-> tab_nom. Поскольку uk есть указатель на структуру anketa, то к элементу tab_nom можно обращаться и так:
(*uk).tab_nom,
если учесть, что указатель установлен на начало массива структур. Имя массива, как обычно, эквивалентно адресу его начального элемента и при добавлении к указателю на структуру или вычитании из него целого числа размер структуры учитывается автоматически Так, оператор uk=a; устанавливает указатель на первый экземпляр массива структур, а запись ++a; обеспечивает автоматический переход к следующему экземпляру. В выражении (*uk).fio скобки обязательны, так как приоритет операции выделения элемента " . " выше чем у "*".