Menu
Coddy logo textTech

Указатель против значения

Часть раздела Объектно-ориентированное программирование путешествия по 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 не должна изменять данные, и обычный указатель, когда должна. Так ты получаешь и эффективность, и ясное намерение.

challenge icon

Задание

Легко

Давайте создадим модуль 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;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C