Menu
Coddy logo textTech

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

Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 9 из 61.

Когда вы передаете структуру в функцию, C предоставляет вам два варианта: передать ее по значению (скопировать всю структуру) или передать ее по указателю (скопировать только адрес). Этот выбор существенно влияет на производительность.

Передача по значению создает полную копию структуры в стеке. Для небольшой структуры с несколькими целыми числами это нормально. Но представьте себе структуру размером в сотни байт — каждый вызов функции копирует все эти данные:

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);
}

Синтаксис также различается. При использовании параметра-значения вы используете оператор «точка» (s.name). При использовании указателя вы используете оператор «стрелка» (s->name).

Версия с указателем более эффективна, так как она передает только адрес памяти — обычно 8 байт независимо от размера структуры.

Вот почему программисты на C почти всегда передают структуры по указателю. Используйте const, когда функция не должна изменять данные, и обычный указатель, когда должна. Вы получаете как эффективность, так и ясность намерений.

challenge icon

Задание

Легко

Давайте создадим модуль Product, который демонстрирует разницу между передачей структур по значению и по указателю. Вы создадите две функции отображения: одну, которая получает всю структуру как копию, и другую, которая получает только указатель на нее.

Вы создадите три файла:

  • product.h: Объявите структуру Product с тремя членами: char name[50], double price и int quantity. Также объявите две функции:
    • display_by_value — принимает Product по значению и выводит информацию о нем
    • display_by_pointer — принимает const Product * и выводит ту же информацию
    Используйте include guards с символом PRODUCT_H.
  • product.c: Реализуйте обе функции. Обратите внимание на разницу в синтаксисе: версия «по значению» использует оператор «точка» (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 и инициализируйте её введенными значениями
    // Hint: Используйте strcpy для копирования имени в поле name структуры
    
    // TODO: Вызовите display_by_value, передав Product
    
    // TODO: Вызовите display_by_pointer, передав указатель на Product
    
    return 0;
}
quiz iconПроверьте себя

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

Все уроки раздела Object Oriented Programming