Передача указателей на структуры
Часть раздела Logic & Flow путешествия по C на Coddy — урок 47 из 63.
Хотя передача структур по значению хорошо подходит для чтения данных, она становится неэффективной при работе с большими структурами, так как копируется вся структура целиком. Что еще более важно, вы не можете изменить исходную структуру внутри функции. Именно здесь передача указателей на структуры становится необходимой.
Когда вы передаете указатель на структуру вместо самой структуры, функция получает адрес памяти исходной структуры. Этот подход предлагает два ключевых преимущества: он более эффективен (отсутствует копирование) и позволяет функции изменять исходные данные.
Синтаксис функции, принимающей указатель на структуру:
void functionName(struct StructureName *ptr) {
// Тело функции, использующее ptr->member
}Внутри функции вы используете оператор «стрелка» для доступа к членам структуры и их изменения. Любые изменения, внесенные через указатель, будут напрямую влиять на исходную структуру в вызывающей функции, что делает этот подход идеальным для функций, которым необходимо обновлять или преобразовывать данные структуры.
Эта техника является фундаментальной для создания эффективных программ на языке C, работающих со сложными структурами данных, так как она сочетает в себе мощь указателей с организацией structs.
Задание
ЛегкоСоздайте программу на языке C, которая демонстрирует передачу указателей на структуры в функции для эффективного изменения данных. Ваша программа должна:
- Определить
structс именемBankAccountсо следующими полями:- Целое число
accountNumberдля хранения номера счета - Символьный массив
ownerNameразмером 30 для хранения имени владельца счета - Число с плавающей точкой
balanceдля хранения баланса счета - Целое число
transactionCountдля хранения количества транзакций
- Целое число
- Написать функцию с именем
depositMoney, которая:- Принимает указатель на структуру
BankAccountи сумму типа float в качестве параметров - Добавляет сумму к балансу счета, используя оператор "стрелка"
- Увеличивает счетчик транзакций на 1
- Выводит
"Deposit successful. New balance: %.2f\n"
- Принимает указатель на структуру
- Написать функцию с именем
withdrawMoney, которая:- Принимает указатель на структуру
BankAccountи сумму типа float в качестве параметров - Проверяет, превышает ли сумма снятия текущий баланс
- Если средств недостаточно, выводит
"Insufficient funds. Current balance: %.2f\n" - Если средств достаточно, вычитает сумму из баланса, увеличивает счетчик транзакций и выводит
"Withdrawal successful. New balance: %.2f\n"
- Принимает указатель на структуру
- Написать функцию с именем
displayAccount, которая:- Принимает указатель на структуру
BankAccountв качестве параметра - Выводит информацию о счете в следующем строгом формате:
"Account Information:\n""Account Number: %d\n""Owner: %s\n""Balance: %.2f\n""Transactions: %d\n"
- Принимает указатель на структуру
- В функции main:
- Создать переменную типа
BankAccountс именемaccount - Считать номер счета, имя владельца и начальный баланс из входных данных
- Установить счетчик транзакций в 0
- Вызвать
displayAccount, чтобы показать начальное состояние счета - Считать сумму депозита и вызвать
depositMoney - Считать сумму снятия и вызвать
withdrawMoney - Вызвать
displayAccount, чтобы показать конечное состояние счета
- Создать переменную типа
Эта задача демонстрирует возможности передачи указателей на структуры в функции. В отличие от передачи по значению, функции получают адрес памяти оригинальной структуры, что позволяет им напрямую изменять исходные данные. Этот подход более эффективен (отсутствует копирование) и позволяет функциям на постоянной основе изменять значения структуры в вызывающей функции.
Шпаргалка
При передаче структур по значению копируется вся структура целиком, что неэффективно для больших структур и не позволяет изменять исходные данные. Передача указателей на структуры решает обе проблемы путем передачи адреса памяти вместо самой структуры.
Синтаксис функции для принятия указателя на структуру:
void functionName(struct StructureName *ptr) {
// Тело функции с использованием ptr->member
}Внутри функции используйте оператор «стрелка» (->) для доступа и изменения членов структуры через указатель. Любые внесенные изменения напрямую повлияют на исходную структуру в вызывающей функции.
Этот подход предлагает два ключевых преимущества:
- Более эффективно (нет копирования всей структуры)
- Позволяет функциям изменять данные исходной структуры
Попробуйте сами
#include <stdio.h>
#include <string.h>
// TODO: Определите структуру BankAccount здесь
// TODO: Напишите функцию depositMoney здесь
// TODO: Напишите функцию withdrawMoney здесь
// TODO: Напишите функцию displayAccount здесь
int main() {
// Чтение входных данных
int accountNum;
char ownerName[30];
float initialBalance;
float depositAmount;
float withdrawAmount;
scanf("%d", &accountNum);
scanf("%s", ownerName);
scanf("%f", &initialBalance);
scanf("%f", &depositAmount);
scanf("%f", &withdrawAmount);
// TODO: Создайте переменную BankAccount и инициализируйте её
// TODO: Вызовите displayAccount, чтобы показать начальное состояние
// TODO: Вызовите depositMoney с суммой депозита
// TODO: Вызовите withdrawMoney с суммой снятия
// TODO: Вызовите displayAccount, чтобы показать конечное состояние
return 0;
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Logic & Flow
1Основы указателей
Что такое указатель?Объявление указателейОператор взятия адреса (&)Оператор разыменования (*)Указатели NULLИтоги: Основы указателей4Проект: Простая текстовая утилита
Обзор проектаПодсчет символов2Указатели и массивы
Имена массивов как указателиЭлементы массива — указателиАрифметика указателейСравнение указателейИтоги: Обход массива через указатели5Указатели и функции
Передача по значениюПередача указателей в функцииИзменение переменных через указателиКлассический пример: SwapПередача массивов в функцииИтоги: указатели как аргументы функций8Структуры и указатели
Указатели на структурыОператор «стрелка» (->)Передача структур по значениюПередача указателей на структурыДинамическое выделение памяти для структурИтоги: Изменение структур через указатели11Итоговые задачи на повторение
Повторение: динамическая конкатенация строкПовторение: массив структурПовторение: счетчик частоты слов3Символьные массивы и строки
Строки как массивы charНуль-терминаторВвод строк с помощью scanfИспользование strlen()Использование strcpy()Использование strcat()Использование strcmp()Итоги: основные строковые функции