Повторение: указатели void
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 49 из 61.
void* — это способ C сказать: «указатель на что-то, но я не скажу вам, на что именно». Он может хранить адрес любого типа данных: int, float, структуры или чего-либо ещё. Это делает его основой для написания универсального кода на C.
Но есть важное ограничение: нельзя напрямую разыменовать void*. Компилятор не знает, сколько байт нужно прочитать и как их интерпретировать. Чтобы использовать data, необходимо привести его обратно к правильному типу:
void print_int(void* data) {
int* p = (int*)data;
printf("%d\n", *p);
}
int main() {
int x = 42;
print_int(&x);
return 0;
}Такая гибкость требует ответственности. Если привести указатель к неправильному типу, компилятор вас не остановит, но программа выдаст мусор или завершится с ошибкой. Поэтому универсальные function часто используют void* вместе с индикатором типа (например, перечислением или флагом), чтобы function могла правильно интерпретировать data.
В следующих уроках вы будете использовать void* для создания контейнеров, способных хранить data любого типа, что позволит создавать по-настоящему повторно используемые структуры данных.
Задание
ЛегкоНапишите функцию с именем print_value, которая принимает два параметра: указатель void* на данные и флаг типа int. Функция должна интерпретировать и выводить данные в зависимости от флага типа:
- Если флаг типа равен
0, приведите указатель к типуint*и выведите целочисленное значение - Если флаг типа равен
1, приведите указатель к типуfloat*и выведите значение с плавающей точкой с двумя знаками после запятой
Ваша программа получит два входных значения:
- Флаг типа (
0для целого числа,1для значения с плавающей точкой) - Числовое значение
В зависимости от флага типа сохраните значение в переменной соответствующего типа, затем вызовите print_value, передав указатель на эту переменную и флаг типа.
Пример вывода, если входные значения — 0 и 42:
42Пример вывода, если входные значения — 1 и 3.14:
3.14Пример вывода, если входные значения — 0 и -17:
-17Пример вывода, если входные значения — 1 и 99.5:
99.50Попробуйте сами
#include <stdio.h>
// TODO: Напишите вашу функцию print_value здесь
int main() {
int type_flag;
scanf("%d", &type_flag);
if (type_flag == 0) {
int int_value;
scanf("%d", &int_value);
// TODO: Вызовите print_value с указателем на int_value и флагом типа
} else if (type_flag == 1) {
float float_value;
scanf("%f", &float_value);
// TODO: Вызовите print_value с указателем на float_value и флагом типа
}
return 0;
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик7Указатели на функции
Объявление указателей на функцииВызов указателей на функцииTypedef для указателей на функцииПередача функций в качестве аргументовИтоги: Диспетчеризация калькулятора10Обобщенные контейнеры
Повторение: указатели voidОбобщенная оберткаОбобщенный обмен (Swap)Обобщенное сравнениеПовторение: обобщенный массив2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C