Menu
Coddy logo textTech

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

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

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

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

typedef struct {
    char name[100];
    int scores[50];
    double average;
} Student;

// По значению: копирует ~608 байт при каждом вызове
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

Шпаргалка

При передаче структур в функции вы можете выбирать между передачей по значению (копирование всей структуры) или передачей по указателю (копирование только адреса).

Передача по значению создает полную копию структуры:

void print_by_value(Student s) {
    printf("%s: %.2f\n", s.name, s.average);  // Используйте оператор "точка"
}

Передача по указателю передает только адрес в памяти:

void print_by_pointer(const Student *s) {
    printf("%s: %.2f\n", s->name, s->average);  // Используйте оператор "стрелка"
}

Ключевые различия:

  • При передаче по значению используется оператор "точка" (s.member)
  • При передаче по указателю используется оператор "стрелка" (s->member)
  • Указатели более эффективны для больших структур (всего 8 байт против размера всей структуры)
  • Используйте const с указателями, если функция не должна изменять данные

Программисты на C обычно предпочитают передавать структуры по указателю для лучшей производительности.

Попробуйте сами

#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 в поле name структуры
    
    // TODO: Вызвать display_by_value с Product
    
    // TODO: Вызвать display_by_pointer с указателем на Product
    
    return 0;
}
quiz iconПроверьте себя

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

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