number answer = make_zero();
number multiplicand = n1;
while (!zerop(multiplicand)) {
number answer2 = add(answer, n2);
destroy_number(answer);
answer = answer2;
multiplicand = multiplicand >one_less_;
}
return answer;
}
/* Эта функция возвращает ненулевое значение, если
ее аргумент является четным числом. */
number even(number n) {
if (zerop(n))
return add_one(make_zero());
else
return odd(n->one_less_);
}
/* Эта функция возвращает ненулевое значение, если
ее аргумент является нечетным числом. */
number odd (number n) {
if (zerop(n))
return make_zero();
else
return even(n->one_less_);
}
/* Приведение строки, содержащей десятичное целое,
к типу "number". */
number string_to_number(char* char_number) {
number answer = make_zero();
int num = strtoul(char_number, (char **)0, 0);
while (num != 0) {
answer = add_one(answer);
--num;
}
return answer;
}
/* Приведение значения типа "number"
к типу "unsigned int". */
unsigned number_to_unsigned_int (number n) {
unsigned answer = 0;
while (!zerop(n)) {
n = n->one_less_;
++answer;
}
return answer;
}
Функции, приведенные в листинге A.5, реализуют стек унарных чисел, представленных в виде связных списков.
/* Реализация стека значений типа "number". */
#include <assert.h>
#include <stdlib.h>
#include "definitions.h"
/* Создание пустого стека. */
Stack create_stack() {
return 0;
}
/* Эта функция возвращает ненулевое значение,
если стек пуст. */
int empty_stack(Stack stack) {
return stack == 0;
}
/* Удаление числа, находящегося на вершине стека.
Если стек пуст, программа аварийно завершается. */
number pop_stack(Stack* stack) {
number answer;
Stack rest_of_stack;
assert(!empty_stack(*stack));
answer = (*stack)->element_;
rest_of_stack = (*stack)->next_;
free(*stack);
*stack = rest_of_stack;
return answer;
}
/* Добавление числа в начало стека. */
void push_stack(Stack* stack, number n) {
Stack new_stack =
malloc(sizeof(struct StackElement));
new_stack->element_ = n;
new_stack->next_ = *stack;
*stack = new_stack;
}
/* Очистка стека. */
void clear_stack(Stack* stack) {
while(!empty_stack(*stack)) {
number top = pop_stack (stack);
destroy_number(top);
}
}
В листинге А.6 показаны объявления типов данных и функций работы со стеком и унарными числами.
number.c и stack.c#ifndef DEFINITIONS_H
#define DEFINITIONS_H 1
/* Представление числа в виде связного списка. */
struct LinkedListNumber {
struct LinkedListNumber* one_less_;
};
typedef struct LinkedListNumber* number;
/* Реализация стека чисел, представленных в виде
связных списков. Значение 0 соответствует
пустому стеку. */
struct StackElement {
number element_;
struct StackElement* next_;
};
typedef struct StackElement* Stack;
/* Операции над стеком. */
Stack create_stack();
int empty_stack(Stack stack);
number pop_stack Stack* stack);
void push_stack(Stack* stack, number n);
void clear_stack(Stack* stack);
/* Операции над числами */
number make_zero();
void destroy_number(number n);
number add(number n1, number n2);
number subtract(number n1, number n2);
number product(number n1, number n2);
number even(number n);
number odd(number n);
number string_to_number(char* char_number);
unsigned number_to_unsigned_int(number n);
#endif /* DEFINITIONS_H */
Приложение Б
Низкоуровневый ввод-вывод
Программисты, пишущие Linux-программы на языке С. имеют в своем распоряжении два набора функций ввода-вывода. Один из них включен в стандартную библиотеку языка С: printf(), fopen() и т.д.[41] Мы предполагаем, что читатели уже знакомы с языком С и знают, как использовать эти функции ввода-вывода, поэтому не будем их подробно описывать.