- •Функции.
- •Вызов функции с переменным числом параметров
- •Функция main и её параметры.
- •Директивы препроцессора (прекомпилера).
- •Объявление указателей.
- •Модификатор const.
- •Операции.
- •Указатели на различные типы.
- •Указатель на void.
- •Применение указателей для передачи данных между функциями.
- •Массивы.
- •Индексация массивов.
- •Хранение массива в памяти. Адреса элементов. Хранение массива в памяти.
- •Массивы и константные указатели.
- •Статическое и динамическое выделение памяти.
- •Функции calloc, malloc, free
- •Функция realloc
- •Передача массивов в качестве аргументов функции.
- •Указатели на функции.
- •Библиотеки функций.
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Работа со строковыми данными (стрингами). Представление строковых данных в языке c.
- •Функции работы со строками.
- •Потоковый ввод-вывод
- •Функции форматированного ввода-вывода.
- •Функция printf().
- •%[Флаги] [Ширина] [.Точность] [{h | l | I | i32 | i64}]тип
- •Для чего нужен форматированный вывод.
- •Функция scanf().
- •Функции sprintf() и sscanf().
- •Функции fprintf() и fscanf().
- •Функции неформатированного ввода-вывода.
- •Функции работы с файлами.
- •Потоковый ввод-вывод
- •Работа с потоками
- •Курсор.
- •Ввод-вывод отдельных символов и строк.
- •Форматированный ввод-вывод информации в файл.
- •Блочный потоковый ввод-вывод
- •Смена текущей позиции в файле. Проверка конца файла.
- •Функции доступа к файлам нижнего уровня.
- •Методы сортировки данных.
- •Введение
- •Сравнение методов сортировки
- •Программная реализация алгоритмов сортировки
- •Метод пузырька.
- •Метод обмена.
- •Метод вставки.
- •Метод Шелла.
- •Метод кучи (бинарной кучи).
- •Очередь
- •Линейный список
- •Физическое (машинное) представление линейных списков
- •Программные реализации структур данных. Стек. Реализация в виде массива.
- •Стек. Связанное представление.
- •Очереди. Реализация в виде массива.
- •Дерево. Связанное представление.
- •Рекурсивный вызов функций.
- •Структуры. Объединения. Перечисления.
- •Перечисление (enum).
- •Производные типы данных.
- •Структура (struct).
- •Побитовое описание полей структуры.
- •Объявление переменных, реализующих структуру.
- •Доступ к элементам структуры.
- •Объединение (union).
- •Вложенное описание структур и объединений.
- •Описание структур и объединений в виде пользовательского типа.
- •Передача структур и объединений в виде параметров функции.
- •Инициализация структур и объединений.
- •Выгода от использования структур
Указатель на void.
Всё вышесказанное применимо к указателям на любые типы, как простые, так и сложные. Отдельно выделяется лишь указатель на пустой тип, т.е. void*.
Указатель на пустой тип не может работать напрямую с памятью, т.к. непонятно какой размер имеет элементарная область, адресуемая этим указателем. Операции сложения/вычитания к нему также неприменимы. Но void* обладает одним важным свойством. В языке C указатель на какой-либо тип далеко не всегда может быть преобразован в указатель на какой-либо другой произвольный тип. Преобразование типа к void* можно осуществить для любого указателя. Это свойство удобно использовать при сравнении адресов, хранящихся в указателях на разные типы, и т.п.
Применение указателей для передачи данных между функциями.
Очень часто требуется, чтобы одна функция могла изменять переменные, относящиеся к другой. Например, в задачах сортировки часто бывает необходимо осуществить обмен значениями между двумя переменными. Предположим, что у нас есть две переменные х и у и нам надо создать функцию, производящую обмен значениями между этими двумя переменными. Тело функции создать весьма легко:
void change(int a, int b)
{
int m;
m=a;
a=b;
b=m;
}
Проблема заключается в том, что в ходе выполнения такой функции необходимо обновить значения у обоих переменных. Значения обоих передаваемых в функцию переменных при обычном вызове функции switch(x,y) не изменятся, т.к. их значения просто копируются в формальные аргументы а и b, с которыми потом уже производятся все манипуляции внутри функции. И по выходу из функции значения a и b просто потеряются, т.к. они никуда не возвращаются.
Можно переопределить функцию switch так, что она будет возвращать какое-либо из значений, например a:
int change(int a, int b)
{
int m;
m=a;
a=b;
b=m;
return a;
}
Но это тоже не решит всех проблем, т.к. по условию задачи нам нужно изменить ОБА значения, а оператор return позволяет возвращать только одно из них. В принципе, решить эту проблему можно с помощью глобальных переменных – используя их можно возвращать из функции несколько значений. Но такое решение будет громоздким и элегантным его назвать никак нельзя.
Стандартным решением такой задачи является использование указателей на переменные в качестве аргументов функции. В этом случае вместо значений переменных в функцию передаются их адреса, а внутри функции с помощью операции косвенной адресации по этим адресам извлекаются значения переменных.
Так, полное решение поставленной в начале раздела задачи будет выглядеть следующим образом:
void change(int *u, int *v)
{
int temp;
temp = *u; //записываем в temp значение, хранимое по адресу u
*u = *v; //записываем по адресу u значение, хранимое по адресу v
*v = temp; //записываем по адресу v значение, сохранённое в temp
return;
}
main ( )
{
int x = 5, y = 10;
printf (“Вначале x = %d и y = %d\n”, x, y);
change (&x, &y); // Вызов функции. В качестве аргументов
// передаём указатели на переменные.
printf (“Теперь x = %d и y = %d\n”, x,y);
return;
}
Массивы. Элементы массивов, доступ к элементам массива. Имя массива как указатель. Массивы указателей.