- •Алфавит языка Си
- •Идентификаторы (имена) языка Си
- •Ключевые слова
- •Константы (литералы)
- •Комментарии
- •Пример программы на Си
- •Последовательность обработки программы на Си
- •Термины
- •2.1. Концепция типа данных
- •2.2. Базовые типы данных
- •2.2. Атрибуты объектов
- •2.2.1. Класс памяти
- •2.2.2. Область (сфера) действия, связанного с объектом идентификатора
- •2.2.3. Область видимости объекта
- •2.2.4. Продолжительность существования объекта (время жизни)
- •2.2.5. Тип компоновки (связывания)
- •2.3. Объявления, определения и описания в языке Си
- •2.4. Объявления переменных стандартных типов
- •2.5. Преобразования типов
- •Термины
- •3.1. Определение и общая классификация операторов
- •3.2. Последовательно выполняемые операторы
- •3.3. Операции языка Си
- •3.4. Приоритеты и порядок выполнения операций, тип результата выражения
- •Тип результата выражения арифметической бинарной операции
- •Даны X, y (значения вводятся с клавиатуры). Вычислить a, если
- •Термины
- •4.1. Условный оператор
- •4.2. Переключатель
- •4.3. Операторы циклов
- •4.4. Оператор безусловной передачи управления
- •4.5. Оператор возврата из функции
- •4.6. Оператор выхода из цикла или переключателя
- •4.7. Оператор перехода к следующей итерации цикла
- •Термины
- •5.1. Указатели
- •5.2. Ссылки
- •5.3. Массивы
- •5.3.1. Одномерные массивы
- •Int a[100]; // Объявление массива из 100 элементов типа int
- •Инициализация массива
- •Массивы и указатели
- •Динамические массивы
- •5.3.2. Многомерные массивы
- •Инициализация многомерных массивов
- •Динамические многомерные массивы
- •Указатель на массив указателей и указатель на массив
- •Int ** p1; // Указатель на массив указателей
- •Int (*p2)[10]; // Указатель на массив из 10 элементов типа int
- •Термины
- •6.1. Структуры
- •Int X; // Поле структуры
- •Int X; // Поле структуры
- •Int X; // Поле структуры
- •Инициализация структуры
- •Int year, page; // Год издания и число страниц
- •6.2. Объединения
- •6.3. Битовые поля структур и объединений
- •Int a1: 10; // Битовое поле из 10 бит
- •Int a2: 14; // Битовое поле из 14 бит
- •Int :6; // Пропускаем 6 бит
- •6.4. Директива определения типа typedef
- •Термины
- •7.1. Определение, описание и вызов функции
- •7.2. Использование значений параметров по умолчанию
- •7.3. Изменение значений скалярных параметров в функциях
- •7.3.1. Передача параметров в функции по значению
- •7.3.1. Передача параметров в функции по указателю (по ссылке)
- •7.4. Передача в функцию массивов
- •7.4.1. Передача в функцию массивов, не являющихся строками
- •7.4.2. Передача в функцию строк
- •7.5. Функции с переменным количеством параметров
- •7.6. Рекурсивные функции
- •7.7. Подставляемые (inline) функции
- •7.8. Указатели на функции
- •7.10. Шаблоны функций
- •7.11. Возможные параметры функции main
- •Термины
- •8.1. Общие сведения о вводе-выводе
- •8.2. Стандартные потоки ввода-вывода
- •8.3. Функции для вывода в поток stdout
- •8.4. Функции для считывания из потока stdin
- •8.5. Ввод- вывод в файлы Открытие файла
- •Закрытие файла
- •Определение конца файла
- •Функции записи в файл
- •Функции чтения из файла
- •Функции позицирования в файлах
- •Функции для сброса буферов
- •Термины
- •9.1. Стадии и основные команды препроцессорной обработки
- •9.2. Замены в тексте
- •9.3. Макроподстановки
- •9.4. Включение текстов из файлов
- •9.5. Условная компиляция
- •9.6. Директива нумерации строк
- •9.7. Директива обработки ошибок
- •9.8. Директивы # и ##
- •9.9. Заранее определенные препроцессорные идентификаторы
- •9.10. Указания компилятору
- •Термины
7.2. Использование значений параметров по умолчанию
Параметры в определении функции могут иметь, так называемые, умалчиваемые значения. Если параметр имеет умалчиваемое значение, то при вызове функции он может отсутствовать, в этом случае при выполнении тела функции вместо формального параметра используется его умалчиваемое значение.
Основные правила при использовании значений параметров по умолчанию:
-
если в определении функции параметр имеет умалчиваемое значение, то все параметры, которые следуют за ним, должны иметь умалчиваемые значения;
-
если при вызове параметр с умалчиваемым значением отсутствует, то все параметры, которые следуют за ним, должны также отсутствовать.
Пример функции:
int summa(int a, int b=10, int c=5) // Параметры b и c имеют умалчиваемые значения
{
return a+b+c;
}
Примеры вызовов этой функции:
int i=2, j=5, s1, s2, s3;
s1=summa(i, 2, j); // Все параметры присутствуют s1=2+2+5=9
s2=summa(i, j); // Параметр с отсутствует s2=2+5+5=12
s3=summa(i); // Параметры b и c отсутствуют s3=2+10+5=17
7.3. Изменение значений скалярных параметров в функциях
7.3.1. Передача параметров в функции по значению
Рассмотрим пример, когда функция пытается изменить значение своего параметра.
void MyFun(int a)
{
a=100;
}
void main()
{
int a=10;
MyFun(a);
printf("a=%d", a); // Будет напечатано a=10
}
В данном примере, несмотря на то, что функция меняет значение параметра, на печать будет выведено старое значение фактического параметра – переменной a, т.е. изменение, которое произвела функция с параметром, после выхода из функции не сохраняется. Это происходит потому, что при передаче параметров в функцию создаются копии параметров в стеке (также все локальные переменные функции размещаются в стеке), и функция работает не с исходной переменной, а с копией этой переменной в стеке. При выходе из функции место в стеке, где размещены параметры функции и ее локальные переменные, освобождается и все изменения пропадают. Данный процесс демонстрирует рисунок, представленный ниже.
Примечание. Стек (англ. stack — стопка) — структура данных, в которой доступ к элементам организован по принципу LIFO (англ. last in — first out, «последним пришёл — первым вышел»). В оперативной памяти выделяется специальный сегмент стека для временного хранения данных, который работает по такому же принципу.
На рисунке показано, что исходная переменная a может размещаться как в стеке – в данном примере, так оно и есть, так как переменная a локальная переменная функции main, так и за пределами стека, если бы a была бы глобальной переменной, в данном случае это не имеет значение, так как все равно функция работает с копией a.
Такой механизм передачи параметров в функцию называется передача параметров по значению (в стек копируется значение параметра).
7.3.1. Передача параметров в функции по указателю (по ссылке)
Рассмотрим, как можно добиться того, чтобы функция могла изменить значение параметра, и это изменение сохранялось бы после выхода из функции. Изменим немного представленный пример.
#include <stdio.h>
void MyFun(int* pa)
{
*pa=100;
}
void main()
{
int a=10;
MyFun(&a);
printf("a=%d", a); // Будет напечатано a=100
}
В этом примере значение переменной a будет изменено, так как в этом случае в стек помещается не копия переменной a, а адрес переменной, при выполнении операции обращение по адресу внутри функции, новое значение будет записано по адресу исходной переменной а и переменная будет изменена. Данный процесс демонстрируется на рисунке.
Такой механизм передача параметров называется передача параметров по указателю.
Таким образом можно сделать вывод, для того чтобы функция могла изменить значение параметра, параметр должен передаваться по указателю, т.е. в функцию необходимо передавать адрес исходного объекта (переменной).
Примечание. Поэтому в стандартной функции ввода scanf и некоторых других функциях при вызове передается адрес переменной (используется операция &).
В языке Си++ появился новый тип – ссылки. В некоторых случаях их удобно использовать вместо указателей в качестве параметров функции, так как ссылка, по сути, является указателем, но к ней не надо применять операцию обращения по адресу («*»). В представленном ниже примере функция также меняет значение параметра.
#include <stdio.h>
void MyFun(int& la) // Параметр функции - ссылка
{
la=100; // Не нужно применять операцию – обращение по адресу
}
void main()
{
int a=10;
MyFun(a); // При вызове не нужно получать адрес
printf("a=%d", a); // Будет напечатано a=100
}
