Четыре проверенных паттерна пользовательских функций в C
Четыре проверенных паттерна пользовательских функций в C
Изучите четыре различных способа реализации пользовательской функции проверки простоты числа и выявите, какой подход даёт наибольшую ясность и переиспользуемость.
Ниже четыре полные программы демонстрируют, как одна и та же логическая задача может быть выражена с разными сигнатурами функций. Все четыре дают идентичный вывод, но дизайнерские решения различаются, иллюстрируя ключевые компромиссы в дизайне функций.
Пример 1: Без аргументов, без возвращаемого значения
#include <stdio.h>
void checkPrimeNumber();
int main() {
checkPrimeNumber(); // аргумент не передаётся
return 0;
}
// Возвращаемый тип void — не возвращает значение
void checkPrimeNumber() {
int n, i, flag = 0;
printf("Enter a positive integer: ");
scanf("%d", &n);
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) { flag = 1; }
}
if (flag == 1) printf("%d is not a prime number.", n);
else printf("%d is a prime number.", n);
}
Функция checkPrimeNumber() отвечает за ввод пользователя, проверку на простоту и печать результата. Поскольку возвращаемый тип void, она сообщает результат только через побочные эффекты.
Пример 2: Без аргументов, но с возвращаемым значением
#include <stdio.h>
int getInteger();
int main() {
int n, i, flag = 0;
// аргумент не передаётся
n = getInteger();
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) { flag = 1; break; }
}
if (flag == 1) printf("%d is not a prime number.", n);
else printf("%d is a prime number.", n);
return 0;
}
// Возвращает целое, введённое пользователем
int getInteger() {
int n;
printf("Enter a positive integer: ");
scanf("%d", &n);
return n;
}
Здесь getInteger() инкапсулирует рутину ввода и возвращает значение в main, который затем выполняет проверку на простоту. Это разделение делает шаг ввода переиспользуемым в разных контекстах.
Пример 3: Аргумент передан, нет возвращаемого значения
#include <stdio.h>
void checkPrimeAndDisplay(int n);
int main() {
int n;
printf("Enter a positive integer: ");
scanf("%d", &n);
// n передаётся в функцию
checkPrimeAndDisplay(n);
return 0;
}
// Возвращаемый тип void — не возвращает значение
void checkPrimeAndDisplay(int n) {
int i, flag = 0;
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) { flag = 1; break; }
}
if(flag == 1) printf("%d is not a prime number.", n);
else printf("%d is a prime number.", n);
}
В этом паттерне ответственность за вывод перемещена в вспомогательную функцию. Хотя это делает main стройным, функция теперь связывает алгоритм с I/O, снижая переиспользуемость.
Пример 4: Аргумент передан и есть возвращаемое значение
#include <stdio.h>
int checkPrimeNumber(int n);
int main() {
int n, flag;
printf("Enter a positive integer: ");
scanf("%d", &n);
// n передаётся в checkPrimeNumber()
// возвращённое значение присваивается flag
flag = checkPrimeNumber(n);
if(flag == 1) printf("%d is not a prime number", n);
else printf("%d is a prime number", n);
return 0;
}
// int возвращается из функции
int checkPrimeNumber(int n) {
int i;
for(i = 2; i <= n/2; ++i) {
if(n % i == 0) return 1;
}
return 0;
}
Этот дизайн изолирует алгоритм и возвращает простой флаг статуса. Вызывающий код решает, как представить результат, что делает функцию высокопереиспользуемой в библиотеках или крупных приложениях.
Выбор оптимального паттерна
Хотя все четыре реализации дают один вывод, наиболее поддерживаемый и тестируемый подход — Пример 4: передача числа как аргумента и возврат булево-подобного флага. Этот паттерн следует принципу единственной ответственности, позволяет юнит-тестирование checkPrimeNumber без I/O зависимостей и легко интегрируется в более сложные системы.
В конечном счёте, выбор зависит от архитектуры проекта. Если функция должна взаимодействовать с пользователем напрямую, Пример 3 может подойти. Для библиотечного кода или сервисов, где I/O обрабатывается отдельно, Пример 4 даёт максимальную гибкость.
Резюме паттернов
| Паттерн | Аргументы | Возврат | Плюсы | Минусы |
|---|---|---|---|---|
| 1. Нет аргументов, нет возврата | — | void | Простота для скриптов | Жёсткая связь с I/O, нетестируемо |
| 2. Нет аргументов, есть возврат | — | T | Инкапсуляция ввода | Ввод всё равно жёстко задан |
| 3. Есть аргументы, нет возврата | T | void | Чистый main, разделение логики | Связка алгоритма с выводом |
| 4. Есть аргументы, есть возврат | T | T | Максимальная переиспользуемость, тестируемость, SRP | Больше кода в main |
Язык C
- Освоение пространств имен в C#: организация, область видимости и лучшие практики
- Типы данных в C: int, float, char и другие — полное руководство
- Операторы в C: исчерпывающее руководство
- Стандартные библиотечные функции в C: практическое руководство
- Переменные и типы данных в C++: подробное руководство по int, double, char, string, bool
- Указатели в C: полное руководство по типам, использованию и лучшим практикам
- Освоение программирования на C: подробное руководство для начинающих
- Типы данных в C: полное руководство по целочисленным, вещественным и производным типам
- Функции в C: объявление, определение, вызов, аргументы (по значению и по ссылке), рекурсия
- Функции с переменным числом аргументов в C: практическое руководство