Чтение онлайн

ЖАНРЫ

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:
Листинг А.5. (stack.c) Стек унарных чисел

/* Реализация стека значений типа "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 показаны объявления типов данных и функций работы со стеком и унарными числами.

Листинг А.6. (definitions.h) Файл заголовков для файлов
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] Мы предполагаем, что читатели уже знакомы с языком С и знают, как использовать эти функции ввода-вывода, поэтому не будем их подробно описывать.

41

В стандартной библиотеке языка C++ аналогичным целям служат потоки ввода-вывода.

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

Б.1. Чтение и запись данных

Первая функция ввода-вывода, с которой сталкиваются те, кто начинают изучать язык С, называется

printf
. Она форматирует текстовую строку и записывает ее в стандартный выходной поток. Обобщенная ее версия
fprintf
записывает текст в заданный поток. Поток данных представляется в программе указателем типа
FILE*
. Чтобы получить этот указатель, необходимо открыть файл с помощью функции
fopen
. По завершении работы с файлом его необходимо закрыть с помощью функции
fclose
. Помимо функции
fprintf
существуют также функции
fputc
,
fputs
и
fwrite
, записывающие данные в поток. Функции
fscanf
,
fgetc
,
fgets
и
fread
читают данные из потока.

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

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

<fcntl.h>
,
<sys/types.h>
,
<sys/stat.h>
и
<unistd.h>
.

Б.1.1. Открытие файла

Чтобы открыть файл и получить дескриптор для работы с ним, необходимо вызвать функцию

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

Если второй аргумент равен

O_RDONLY
, файл открывается только для чтения. При попытке записи в такой файл будет выдана ошибка. Точно так же флаг
O_WRONLY
объявляет файл доступным только для записи. В случае флага
O_RDWR
файл открывается и для чтения. и для записи. Не всякий файл можно открыть в любом из трех режимов. Например, существующие права доступа к файлу могут не позволить конкретному процессу открывать файл для чтения или записи. Файл, находящийся в устройстве, запись в которое невозможна (скажем, компакт-диск), тем более нельзя открыть для записи.

Поделиться с друзьями: