Создание калькулятора факториалов на языке C

CBeginner
Практиковаться сейчас

Введение

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

В практическом занятии предоставлены пошаговые инструкции и примеры кода, которые помогут вам пройти процесс создания калькулятора факториалов. Вы начнете с изучения базового синтаксиса циклов for, которые являются важными для перебора элементов массива и выполнения повторяющихся задач. Затем вы узнаете, как обращаться к элементам массива и манипулировать ими, что является важным для расчета факториала. В практике также будут рассмотрены реализация расчета факториала, обработка крайних случаев, а также тестирование и отладка конечной программы.

Понять синтаксис цикла for

На этом этапе вы узнаете о базовом синтаксисе циклов for в языке программирования C, которые являются важными для перебора элементов массивов и выполнения повторяющихся задач, таких как вычисление факториалов.

Начнем с создания простой программы на языке C для демонстрации базового синтаксиса цикла for. Откройте WebIDE и создайте новый файл с именем loop_example.c в директории ~/project:

cd ~/project
touch loop_example.c
#include <stdio.h>

int main() {
    // Basic for loop syntax: for (initialization; condition; increment/decrement)
    for (int i = 0; i < 5; i++) {
        printf("Current iteration: %d\n", i);
    }
    return 0;
}

Пример вывода:

Current iteration: 0
Current iteration: 1
Current iteration: 2
Current iteration: 3
Current iteration: 4

Разберем синтаксис цикла for:

  • int i = 0: Инициализация - устанавливает переменную-счетчик цикла в начальное значение
  • i < 5: Условие - цикл продолжает выполняться, пока это условие истинно
  • i++: Инкремент - увеличивает счетчик цикла после каждой итерации

Теперь скомпилируйте и запустите программу, чтобы увидеть, как работает цикл:

gcc loop_example.c -o loop_example
./loop_example

Цикл for является мощным инструментом, так как позволяет точно контролировать процесс итерации. Вы можете изменять части инициализации, условия и инкремента/декремента, чтобы соответствовать различным программным потребностям, таким как обход массивов или выполнение вычислений.

Перебор элементов массива

На этом этапе вы научитесь перебирать элементы массива в языке C, что является важным для реализации нашего калькулятора факториалов. Исходя из знаний о цикле for, полученных на предыдущем этапе, мы рассмотрим, как обращаться к элементам массива и манипулировать ими.

Создадим новый файл с именем array_iteration.c в директории ~/project, чтобы продемонстрировать перебор массива:

cd ~/project
touch array_iteration.c
#include <stdio.h>

int main() {
    // Declare and initialize an array of integers
    int numbers[5] = {10, 20, 30, 40, 50};

    // Iterate through the array using a for loop
    for (int i = 0; i < 5; i++) {
        printf("Element at index %d is: %d\n", i, numbers[i]);
    }

    return 0;
}

Пример вывода:

Element at index 0 is: 10
Element at index 1 is: 20
Element at index 2 is: 30
Element at index 3 is: 40
Element at index 4 is: 50

Разберем основные концепции:

  • int numbers[5] создает массив, который может хранить 5 целых элементов
  • {10, 20, 30, 40, 50} инициализирует массив определенными значениями
  • numbers[i] обращается к отдельным элементам массива с использованием индекса
  • Цикл for использует i в качестве индекса для последовательного доступа к каждому элементу

Теперь скомпилируйте и запустите программу:

gcc array_iteration.c -o array_iteration
./array_iteration

Для того чтобы перебор стал более практичным, создадим пример, который вычисляет сумму элементов массива:

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};
    int sum = 0;

    // Calculate sum using array iteration
    for (int i = 0; i < 5; i++) {
        sum += numbers[i];
    }

    printf("Sum of array elements: %d\n", sum);

    return 0;
}

Пример вывода:

Sum of array elements: 150

Это демонстрирует, как можно использовать циклы for для выполнения операций над элементами массива, что будет важным при реализации нашего будущего калькулятора факториалов.

Реализация расчета факториала

На этом этапе вы научитесь реализовать функцию для расчета факториала на языке C, используя техники итерации цикла, которые вы изучили на предыдущих этапах. Факториал - это математическая операция, которая представляет собой произведение числа на все положительные целые числа, меньшие его.

Создадим новый файл с именем factorial_calculator.c в директории ~/project:

cd ~/project
touch factorial_calculator.c
#include <stdio.h>

// Function to calculate factorial
int calculateFactorial(int n) {
    // Initialize result to 1
    int factorial = 1;

    // Use for loop to multiply numbers from 1 to n
    for (int i = 1; i <= n; i++) {
        factorial *= i;
    }

    return factorial;
}

int main() {
    // Test factorial calculation for different numbers
    int numbers[] = {0, 1, 5, 7};

    // Iterate through the numbers and calculate their factorials
    for (int j = 0; j < 4; j++) {
        int num = numbers[j];
        int result = calculateFactorial(num);

        printf("Factorial of %d is: %d\n", num, result);
    }

    return 0;
}

Пример вывода:

Factorial of 0 is: 1
Factorial of 1 is: 1
Factorial of 5 is: 120
Factorial of 7 is: 5040

Разберем расчет факториала:

  • Факториал 0 и 1 равен 1
  • Факториал числа n (n!) = 1 2 3 ... n
  • Функция calculateFactorial() использует цикл for для умножения чисел
  • Мы начинаем расчет факториала с 1 и умножаем на каждое число до n

Скомпилируйте и запустите программу:

gcc factorial_calculator.c -o factorial_calculator
./factorial_calculator

Для того чтобы калькулятор стал более интерактивным, изменим программу так, чтобы она принимала ввод от пользователя:

#include <stdio.h>

int calculateFactorial(int n) {
    int factorial = 1;
    for (int i = 1; i <= n; i++) {
        factorial *= i;
    }
    return factorial;
}

int main() {
    int number;

    // Prompt user for input
    printf("Enter a number to calculate its factorial: ");
    scanf("%d", &number);

    // Calculate and display factorial
    int result = calculateFactorial(number);
    printf("Factorial of %d is: %d\n", number, result);

    return 0;
}

Пример взаимодействия:

Enter a number to calculate its factorial: 6
Factorial of 6 is: 720

Обработка крайних случаев

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

Давайте модифицируем наш калькулятор факториалов для обработки этих крайних случаев. Создайте новый файл с именем factorial_edge_cases.c в директории ~/project:

cd ~/project
touch factorial_edge_cases.c
#include <stdio.h>
#include <limits.h>

// Function to calculate factorial with error handling
int calculateFactorial(int n) {
    // Check for negative numbers
    if (n < 0) {
        printf("Error: Factorial is not defined for negative numbers.\n");
        return -1;
    }

    // Initialize result to 1
    int factorial = 1;

    // Check for potential integer overflow
    for (int i = 1; i <= n; i++) {
        // Check if multiplication will cause overflow
        if (factorial > INT_MAX / i) {
            printf("Error: Factorial result exceeds integer limit.\n");
            return -1;
        }
        factorial *= i;
    }

    return factorial;
}

int main() {
    // Test various edge cases
    int test_cases[] = {-5, 0, 1, 12, 13};

    for (int i = 0; i < 5; i++) {
        int number = test_cases[i];
        int result = calculateFactorial(number);

        // Only print result if calculation was successful
        if (result!= -1) {
            printf("Factorial of %d is: %d\n", number, result);
        }
    }

    return 0;
}

Пример вывода:

Error: Factorial is not defined for negative numbers.
Factorial of 0 is: 1
Factorial of 1 is: 1
Factorial of 12 is: 479001600
Error: Factorial result exceeds integer limit.

Основные техники обработки ошибок:

  • Проверка на отрицательные числа перед расчетом
  • Использование INT_MAX для предотвращения переполнения целого числа
  • Возвращение -1 для указания ошибки в расчете
  • Предоставление информативных сообщений об ошибках

Скомпилируйте и запустите программу:

gcc factorial_edge_cases.c -o factorial_edge_cases
./factorial_edge_cases

Давайте улучшим программу с помощью более удобной для пользователя обработки ввода:

#include <stdio.h>
#include <limits.h>

int calculateFactorial(int n) {
    if (n < 0) {
        printf("Error: Factorial is not defined for negative numbers.\n");
        return -1;
    }

    int factorial = 1;

    for (int i = 1; i <= n; i++) {
        if (factorial > INT_MAX / i) {
            printf("Error: Factorial result exceeds integer limit.\n");
            return -1;
        }
        factorial *= i;
    }

    return factorial;
}

int main() {
    int number;

    while (1) {
        printf("Enter a non-negative integer (or negative to exit): ");

        // Check if input is valid
        if (scanf("%d", &number)!= 1) {
            printf("Invalid input. Please enter an integer.\n");
            // Clear input buffer
            while (getchar()!= '\n');
            continue;
        }

        // Exit condition
        if (number < 0) {
            printf("Exiting factorial calculator.\n");
            break;
        }

        // Calculate and display factorial
        int result = calculateFactorial(number);
        if (result!= -1) {
            printf("Factorial of %d is: %d\n", number, result);
        }
    }

    return 0;
}

Пример взаимодействия:

Enter a non-negative integer (or negative to exit): 10
Factorial of 10 is: 3628800
Enter a non-negative integer (or negative to exit): -1
Exiting factorial calculator.

Тестирование и отладка калькулятора факториала

На этом последнем этапе вы научитесь тщательно тестировать и отлаживать свой калькулятор факториалов, используя различные методы тестирования и стратегии отладки.

Создадим комплексную программу для тестирования, которая включает несколько тестовых случаев и функции отладки. Создайте файл с именем factorial_test.c в директории ~/project:

cd ~/project
touch factorial_test.c
#include <stdio.h>
#include <assert.h>
#include <limits.h>

// Factorial calculation function with detailed error checking
int calculateFactorial(int n) {
    // Debug print to track function calls
    printf("DEBUG: Calculating factorial for %d\n", n);

    // Validate input range
    if (n < 0) {
        fprintf(stderr, "ERROR: Factorial undefined for negative numbers\n");
        return -1;
    }

    // Handle special cases
    if (n == 0 || n == 1) return 1;

    // Factorial calculation with overflow protection
    long long factorial = 1;
    for (int i = 2; i <= n; i++) {
        factorial *= i;

        // Overflow check
        if (factorial > INT_MAX) {
            fprintf(stderr, "ERROR: Factorial exceeds integer limit\n");
            return -1;
        }
    }

    return (int)factorial;
}

// Test function to verify factorial calculations
void runTests() {
    // Test cases with expected results
    struct TestCase {
        int input;
        int expected;
    } tests[] = {
        {0, 1},    // Edge case: 0!
        {1, 1},    // Edge case: 1!
        {5, 120},  // Normal case: 5!
        {10, 3628800}  // Larger number
    };

    int numTests = sizeof(tests) / sizeof(tests[0]);

    printf("Running %d test cases...\n", numTests);

    // Iterate through test cases
    for (int i = 0; i < numTests; i++) {
        int result = calculateFactorial(tests[i].input);

        // Assertion-style testing
        if (result == tests[i].expected) {
            printf("Test case %d PASSED: factorial(%d) = %d\n",
                   i+1, tests[i].input, result);
        } else {
            printf("Test case %d FAILED: Expected %d, Got %d\n",
                   i+1, tests[i].expected, result);
        }
    }
}

int main() {
    // Run comprehensive test suite
    runTests();

    // Interactive testing mode
    int number;
    printf("\nEnter a number to calculate its factorial (or negative to exit): ");
    while (scanf("%d", &number) == 1 && number >= 0) {
        int result = calculateFactorial(number);
        if (result!= -1) {
            printf("Factorial of %d is: %d\n", number, result);
        }

        printf("\nEnter another number (or negative to exit): ");
    }

    return 0;
}

Скомпилируйте и запустите программу:

gcc factorial_test.c -o factorial_test
./factorial_test

Пример вывода будет выглядеть так:

Running 4 test cases...
DEBUG: Calculating factorial for 0
Test case 1 PASSED: factorial(0) = 1
DEBUG: Calculating factorial for 1
Test case 2 PASSED: factorial(1) = 1
DEBUG: Calculating factorial for 5
Test case 3 PASSED: factorial(5) = 120
DEBUG: Calculating factorial for 10
Test case 4 PASSED: factorial(10) = 3628800

Enter a number to calculate its factorial (or negative to exit):

Показанные ключевые методы отладки и тестирования:

  • Вывод отладочной информации для отслеживания выполнения функций
  • Комплексные тестовые случаи, охватывающие крайние ситуации
  • Обработка ошибок для недопустимых входных данных
  • Защита от переполнения
  • Тестирование в стиле утверждений (assertion-style testing)
  • Интерактивный режим тестирования

Советы по отладке:

  1. Используйте printf() для логирования и отслеживания вызовов функций
  2. Явно обрабатывайте крайние случаи
  3. Реализуйте валидацию входных данных
  4. Используйте long long для вычислений с большими числами
  5. Создайте набор тестов для проверки различных сценариев

Резюме

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

Вы начали с создания простой программы на языке C для демонстрации базового синтаксиса цикла for, поняли части цикла: инициализацию, условие и инкремент/декремент. Затем вы научились перебирать массив целых чисел с использованием цикла for, обращаться к элементам массива и манипулировать ими.