Указатель против значения
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 9 из 61.
Когда вы передаёте структуру в function, C предоставляет вам два варианта: передать её по значению (copy всю структуру) или передать её через pointer (copy только address). Выбор существенно влияет на производительность.
Передача по значению создаёт полную копию структуры в стеке. Для небольшой структуры с несколькими целыми числами это нормально. Но представь структуру размером в сотни байт: каждый вызов function копирует все эти данные:
typedef struct {
char name[100];
int scores[50];
double average;
} Student;
// По значению: копирует ~308 байт при каждом вызове
void print_by_value(Student s) {
printf("%s: %.2f\n", s.name, s.average);
}
// По указателю: копирует только 8 байт (адрес)
void print_by_pointer(const Student *s) {
printf("%s: %.2f\n", s->name, s->average);
}
Синтаксис также отличается. С параметром-значением используется оператор dot (s.name). С указателем используется оператор arrow (s->name).
Версия с указателем более эффективна, поскольку передаёт только адрес памяти, обычно 8 байт независимо от размера структуры.
Вот почему программисты на C почти всегда передают структуры через указатель. Используй const, когда function не должна изменять данные, и обычный указатель, когда должна. Так ты получаешь и эффективность, и ясное намерение.
Задание
ЛегкоДавайте создадим модуль Product, демонстрирующий разницу между передачей структур по значению и по указателю. Вы создадите две функции отображения: одну, которая получает всю структуру как копию, и другую, которая получает только указатель на неё.
Вы создадите три файла:
product.h: Объявите структуруProductс тремя members:char name[50],double priceиint quantity. Также объявите две функции:display_by_value: принимаетProductпо значению и выводит её информациюdisplay_by_pointer: принимаетconst Product *и выводит ту же информацию
PRODUCT_H.product.c: Implement обе функции. Обратите внимание на разницу в синтаксисе: версия по значению использует оператор точки (p.name), а версия с указателем использует оператор стрелки (p->name). Обе функции должны выводить данные в одном и том же формате.main.c: Создайте Product, затем вызовите обе функции отображения, чтобы показать, что они выдают одинаковый результат, несмотря на использование разных стилей параметров.
Вы получите три входных значения: название продукта (строка), цену (число типа double) и количество (целое число).
В основном файле инициализируйте Product этими значениями, затем вызовите display_by_value, а после него — display_by_pointer.
Обе функции должны выводить данные в таком формате:
Product: {name}, Price: {price}, Qty: {quantity}Используйте %.2f для цены, чтобы отображать два знака после запятой.
Например, при входных значениях Laptop, 999.99 и 5 результатом будет:
Product: Laptop, Price: 999.99, Qty: 5
Product: Laptop, Price: 999.99, Qty: 5Попробуйте сами
#include <stdio.h>
#include <string.h>
#include "product.h"
int main() {
char name[50];
double price;
int quantity;
// Считать входные данные
scanf("%s", name);
scanf("%lf", &price);
scanf("%d", &quantity);
// TODO: Создайте переменную Product и инициализируйте её входными значениями
// Подсказка: Используйте strcpy, чтобы скопировать name в поле name структуры
// TODO: Вызовите display_by_value с Product
// TODO: Вызовите display_by_pointer с указателем на Product
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C