- •Структура программы на языке Си. Этапы выполнения программы
- •1.1. Алфавит языка Си
- •1.3. Идентификаторы и ключевые слова
- •1.4. Знаки операций
- •2. Переменные и константы. Типы данных
- •2.1. Основные типы данных
- •2.2. Декларация (объявление) объектов
- •2.4. Целочисленные константы
- •2.5. Константы вещественного типа
- •2.6. Символьные константы
- •2.7. Строковые константы
- •3. Обзор операций
- •3.2. Арифметические операции
- •3.3. Операции сравнения
- •3.4. Логические операции
- •4.1. Операция присваивания
- •Примеры недопустимых выражений:
- •4.2. Сокращенная запись операции присваивания
- •4.3. Преобразование типов операндов бинарных операций
- •4.4. Преобразование типов при присваивании.
- •4.5. Операция явного приведения типа
- •4.6. Операция «,» (запятая)
- •5.3. Консольные функции вывода данных на экран
- •5.4. Консольные функции ввода информации
- •6. Операторы языка с.
- •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
- •9. Операторы передачи управления.
- •9.1. Оператор безусловного перехода goto
- •9.2. Операторы continue, break и return
- •10. Массивы
- •10.1. Одномерные массивы
- •10.2. Примеры алгоритмов, использующих одномерные массивы.
- •10.3. Многомерные массивы
- •11.5. Операция sizeof
- •11.6. Побитовые логические операции. Операции над битами
- •12.1. Строки как нуль-терминированные массивы char.
- •12.4. Преобразования строковых типов.
- •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.10. Объединения
- •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.10. Указатели на функции
- •Id_функции(список аргументов);
- •18.1. Динамическое выделение и освобождение памяти.
Void f1(int, const double *);
Рекомендуется указывать const перед всеми параметрами - указателями, для которых в функции не предусмотрено изменение значений, на которые они ссылаются. Это облегчает, например, отладку программы, т.к. по заголовку функции видно, какие данные в функции изменяются, а какие нет.
17.8 . Указатели на структуры
Указатели могут указывать и на структурный тип данных:
struct Point{
int x,y;
} r, *p;
p=&r;
Для обращения к полю структуры через указатель придется писать не только звездочку, но и скобки (т.к. операция "точка" имеет приоритет выше, чем "звездочка" ):
(*p).x=3; // r.x=3
(*p).y=4; // r.y=4
Ввиду распространенности подобного действия, в языке С введена специальная сокращенная запись операции доступа к полям структур и объединений при помощи указателей:
-> (стрелка);
Она означает разадресацию указателя на структуру, стоящего слева от знака ->, и переход к полю этой структуры, указанному справа от ->. Поэтому вышеприведенный пример присваивания значений полям структур можно записать и короче:
p->x=3;
p->y=4;
В сущности, подобная операция уже давно знакома читателю: все стандартные компоненты C++ Builder'а являются как раз указателями на структуры (точнее, на объекты - структуры, объявленные вместе с обрабатывающими их функциями). Поэтому, например, выражение Edit1->Text означает переход от указателя Edit1 (имеющего тип TEdit * ) к самому объекту (имеющему тип TEdit) и его полю Text .
Сказанное иллюстрируется следующим примером:
Edit1->Text="A";
Edit2->Text="B";
Edit1=Edit2; // Edit1 теперь указывает на 2-ой Edit !
Edit1->Text="C";
В результате первый Edit сохранит значение "A", а второй получит значение "C". Отметим, что после выполнения этого фрагмента программы и Edit1 и Edit2 указывают на второй Edit, и любые операции и с Edit1 , и с Edit2 будут относиться к нему; к первому же Edit'у вообще не осталось доступа из программы вплоть до завершения ее работы.
Присваивание указателей на компоненты С++ Builder'а может быть полезно, например, если компонент C++ Builder'а сделать аргументом при вызове функции.
17.10. Указатели на функции
В языке Си допускаются указатели не только на данные, но и на функции. Они позволяют, например, создать функцию, строящую таблицу значений любой другой функции (с заданным видом списка параметров); при этом конкретный вызов этой другой функции осуществляется через указатель на функцию.
Рассмотрим методику работы с указателями на функции.
1. Как и любой объект языка Си, указатель на функции необходимо декларировать. Формат объявления указателя на функции следующий:
тип (*переменная-указатель)(список параметров);
т.е. декларируется указатель, который можно устанавливать на функции, возвращающие результат указанного типа и которые имеют указанный список параметров. Наличие первых круглых скобок обязательно, так как без них – это декларация функции, которая возвращает указатель.
Например, объявление вида:
double (*p_f )(char, double);
говорит о том, что декларируется указатель p_f, который можно устанавливать на функции, возвращающие результат типа double и имеющие два параметра: первый – символьного типа, а второй – вещественного типа.
2. Идентификатор функции считается константным указателем, поэтому для того, чтобы установить переменную-указатель на конкретную функцию, достаточно ей присвоить ее идентификатор:
переменная-указатель = ID_функции;
Например, имеется функция с прототипом: double f1(char, double); тогда операция
p_f = f1;
установит указатель p_f на данную функцию.
Идентификатор функции может быть присвоен указателю и по-другому:
double f1(char C, double D){
... // тело функции f1
}
void FunOut(double (*p_f )(char, double)){
... // тело функции FunOut
}
void main(){
... // тело функции main
FunOut(f1);
... // тело функции main
}
Здесь при вызове функции FunOut в нее передается аргумент - указатель на функцию f1, который присваивается параметру p_f .
3. Вызов функции после установки на нее указателя выглядит так:
(*переменная-указатель)(список аргументов);
или
переменная-указатель (список аргументов);
После таких действий кроме стандартного обращения к функции: