Академический Документы
Профессиональный Документы
Культура Документы
Структура
файловой системы.
Файловая система состоит из четырех основных компонентов:
Пространство имен – методы именования объектов и организации в
виде единой иерархии
API – набор системных вызовов для перемещения между объектами и
управления ими
Методы безопасности – схема защиты, сокрытия и совместного
использования объектов
Реализация – программный код, который связывает логические модели
с дисковой подсистемой
Файловая система – это единая иерархическая структура, которая
начинается с каталога / и разветвляется, охватывая произвольное число
каталогов.
Каталог верхнего уровня называется корневым. Это
моноиерархическая система отличается от используемой в Windows,
где применяется понятие пространства имен, основанное на принципе
деления диска на разделы.
Цепочка имен каталогов, через которые необходимо пройти для
доступа к заданному файлу, вместе с именем этого файла образуют
путь к файлу. Путь может быть абсолютным (например, /temp/foo) или
относительным (например, book4/filesystem). Последние
интерпретируются начиная с текущего каталога. Стоит отметить, что
текущий каталог есть у каждого процесса (большинство процессов
никогда не изменяют свои рабочие каталоги, и поэтому просто
наследуют текущий каталог процесса, который их запустил).
Существует ограничение на длину имени файла – не более 255
символов. В имя нельзя включать символ косой черты и нулевые
символы. Также есть ограничение на длину пути, который передается
ядру в качестве аргумента системного вызова – 4095 байт.
{Из чего делаем? (реквизиты)} —-> [Как делаем? (команды)] —-> {Что
делаем? (цели)}
Несложно заметить что процессы трансляции и компиляции очень
красиво ложатся на эту схему:
/* — начало комментария;
*/ — конец комментария.
Операторы ветвления.
Простейший из них – условный оператор, имеет сокращенную и полную
формы. Сокращенная форма синтаксически определяется так:
if (выражение_условие) оператор;
Здесь в качестве элемента выражение_условие могут использоваться:
- арифметическое выражение;
- отношение;
- логическое выражение.
Оператор, указанный в условном, выполняется только тогда, когда
выражение_условие оказывается истинным (т.е. при его ненулевом
значении). Если выражение_условие ложно (равно нулю) – будет
выполняться оператор, следующий за условным.
Полная форма условного оператора:
if (выражение_условие)
оператор_1;
else
оператор_2;
Здесь в случае истинности (ненулевое значение) условия выполняется только
оператор 1, при нулевом условии выполняется только оператор 2.
Указатели.
Каждая переменная в программе – это объект, имеющий имя
(идентификатор) и значение. По имени можно обратиться к переменной и
получить ее значение. С точки зрения машинной реализации имя переменной
соответствует адресу того участка памяти, который для нее выделен, а
значение переменной – содержимому этого участка памяти.
Какие бы данные не хранились в переменной, в основе всегда лежит один и
тот же фундаментальный принцип:
любая переменная является только именем, которое компилятор ассоциирует
с определенным адресом памяти компьютера.
Таким образом, у переменной помимо имени есть еще адрес, и есть
содержимое этого адреса.
Вызов функции:
Вызов функции реализуется выражением с операцией «круглые скобки». При
этом используется следующий синтаксис:
<обозначение_функции> (<список фактических параметров>);
Обычно в качестве <обозначение_функции> выступает ее имя. Кроме того,
функцию можно обозначить, разыменовав указатель на нее. Этот способ
будет рассмотрен в дальнейшем.
<список фактических параметров>, называемых по аналогии с
математикой аргументами – это список выражений, количество которых
равно числу формальных параметров функции (исключение составляют
функции с переменным количеством параметров). Соответствие между
формальными и фактическими параметрами устанавливается по их
взаимному расположению в списках.
Между формальными и фактическими параметрами должно быть
соответствие по типам. Если типы не совпадают – включается механизм
преобразования типов (если проведение такого преобразования допустимо).
Передача параметров:
Синтаксис языка С предусматривает только один способ передачи
параметров – передачу по значениям. Это означает, что формальные
параметры функции локализованы в ней и не доступны вне ее определения,
никакие операции над формальными параметрами в теле функции не
изменяют значений фактических параметров.
Передача параметров по значению предусматривает следующие шаги:
1. При вызове функции выделяются участки памяти для ее формальных
параметров. Если параметром является массив, то формируется указатель на
начало этого массива и он служит представлением массива-параметра в теле
функции.
2. Вычисляются значения выражений, использованных в качестве
фактических параметров при вызове функции.
3. Вычисленные значения заносятся в участки памяти, выделенные для
формальных параметров функции.
4. В теле функции выполняется обработка с использованием значений
внутренних объектов-параметров, и результат передается в точку вызова
функции как возвращаемое ею значение.
5. После выхода из функции освобождается память, выделенная для ее
формальных параметров.
Указатели на функцию.
Рассмотрим теперь вопрос о том, почему в языке С функция введена как один
из производных типов. Необходимость в таком типе связана с задачами, в
которых функция (или ее адрес) должна выступать в качестве параметра
другой функции или в качестве значения, возвращаемого другой функцией. В
этом случае используется «указатель на функцию».
Самый употребительный «указатель на функцию» – это ее имя
(идентификатор). Идентификатор <имя_функции> в ее определении и в ее
прототипе подобен имени массива и является указателем-константой. Он
навсегда связан с определяемой функцией и не может быть «настроен» на
что-либо иное, чем ее адрес.
«Указатель на функцию» (как переменная) вводится отдельно от определения
и прототипа какой-либо функции. Для этих целей используется конструкция:
<тип> (*<имя_указателя>)(<спецификация_параметров>);
где <тип> - определяет тип возвращаемого функцией значения;
<имя_указателя> - идентификатор, произвольно выбранный программистом;
<спецификация_параметров> - определяет состав и типы параметров
функции.
В отличие от имени функции указатель func0 является переменной, т.е. ему
можно присваивать значения других указателей, определяющих адреса
функций программы. Важно, что тип указателя-переменной должен
полностью соответствовать типу функции, адрес которой ему присваивается.
Указатели на структуры.
Указатели на структуры определяются точно так же, как и указатели на
другие типы данных.
struct COMPLEX *pC;
complex *pcmpl;
Можно вводить указатели и в качестве обозначений структур, т.е.
struct birth {
char Where[40];
struct date When;
} *pB1, *pB2;
- это для одновременного описания структуры и ее определения (создаются
указатели pB1 и pB2.
Возможно также:
typedef struct COMPLEX
{
double real;
double imag;
} complex, *ptr_comp;
и тогда для определения переменной типа указатель на структуру:
ptr_comp px [12];
complex * px [12];
- одинаково определяют массивы из 12-ти указателей на структуру complex.
Чтобы указать, что данный файл открывается или создается как текстовый,
добавьте символ t в строку режима открытия (например, rt, w+t и т.д.).
Аналогичным образом, чтобы сообщить, что файл открывается или создается
как бинарный, добавьте в строку режима открытия символ b (например, wb,
a+b и т.д.). Функция f open () также позволяет вставить символы t или b
между буквой я символом (+) в строке режима открытия (например, строка
rt+ эквивалентна строке r+t). Когда файл открывается для обновления, можно
вводить и выводить данные в результирующий поток. Однако вывод не
может осуществляться непосредственно после ввода, если ему не
предшествует вызов функции fseek () или rewind (). В случае успеха fopen()
возвращает указатель на открытый поток; в случае ошибки - указатель
NULL.
Например:
FILE* stream = fopen("Install.dat", "r");
Указатель на открытый файловый поток используется во всех последующих
функциях работы с потоком.
По завершении работы с потоком он должен быть закрыт. Это
осуществляется с помощью функции f close (), которая имеет следующий
прототип:
int f close (FILE *stream) ;
Все буферы, связанные с потоком, освобождаются перед закрытием потока.
В случае успеха fclose() возвращает 0; в случае ошибки - EOF. Если ваша
программа не закрывает поток с помощью явного вызова fclose (). то он
закрывается автоматически по ее завершению.
Рассмотрим теперь функции, осуществляющие ввод-вывод в файловый
поток.
Функция fgetc() имеет следующий прототип:
int fgetc(FILE *stream);
Она осуществляет ввод символа из файлового потока stream. В случае успеха
функция преобразует прочитанный символ в тип int без учета знака. Если
делается попытка прочесть конец файла иди произошла ошибка, функция
возвращает EOF. Как видим, эта функция во всем аналогична функции getc(),
за исключением того, что чтение осуществляется из файлового потока. Более
того, как мы уже отмечали, на самом деле getc () - это макрос, реализованный
с помощью f getc (). То же самое относится и к следующим функциям: все
они имеют уже рассмотренные нами аналоги.
Функция fputc() имеет следующий прототип:
int fputc(int с, FILE *stream);
Она осуществляет вывод символа в файловый поток и во всем аналогична
функции putc ().
Функция f gats () имеет следующий прототип:
char *fgets(char *s, int n, FILE *stream);
Она осуществляет чтение строки символов из файлового потока в строку s.
Функция прекращает чтение, если прочитано n - 1 символов или встретился
символ перехода на новую строку ' \n'. Если встретился символ перехода на
новую строку, он сохраняется в переменной в. В обоих случаях в
переменную s добавляется символ '\0 ', который является признаком
завершения строковой переменной. В случае успеха функция возвращает
строку, на которую указывает параметр s. Если делается попытка чтения
конца файла или произошла ошибка, она возвращает null.
Функция f puts () имеет следующий прототип:
int fputs(const char *s, FILE *stream);
Она осуществляет вывод строки в файловый поток. Символ перехода на
новую строку не добавляется, и завершающий строку нуль-символ в
файловый поток не копируется. В случае успеха fputs () возвращает
неотрицательное значение. В противном случае она возвращает EOF.
Функция fscanf () имеет следующий прототип;
int fscanf(FILE *stream,
const char *format[, address, ...]);
Она во всем аналогична функции scanf (), за исключением того, что
форматированный ввод осуществляется не со стандартного устройства ввода,
а из файлового потока.
Функция fprintf () имеет следующий прототип:
int fprintf(FILE *stream,
const char *format[, argument, ...]);
Она во всем аналогична функции printf (), но осуществлят форматированный
вывод не на стандартное устройство вывода, а в файловый поток.
Функция feof () является на самом деле макросом и позволяет осуществлять
проверку на достижение символа конца файла при операциях ввода-вывода.
Она имеет следующий прототип:
int feof(FILE *stream);
Она возвращает ненулевое значение, если был обнаружен конец файла при
последней операции ввода в поток stream и 0, если конец файла еще не
достигнут.
Рассмотрим пример файлового ввода и вывода:
#include <stdio.h>
int main ()
{
FILE *in, *out;
if ({in = fopen("C;\\AUTOEXEC.BAT", "rt")) = NULL)
{
fprintf(stderr, "Cannot open input file.\n");
return 1;
}
if ((out = fopen
("C:\\AUTOEXEC.BAK", "wt")) = NULL)
{
fprintf(stderr,
"Cannot open output file.\n");
return 1;
}
while (!feof{in))
fputc(fgetc(in), out); fclose(in); fclose(out); fprintf{stderr, "The file is copied
successfully.\n");
return 0;
}
Две следующие функции предназначены для осуществления
неформатированного ввода и вывода в файловые потоки. Функция f read ()
имеет следующий прототип:
size_t
fread(void *ptr, size_t size, size_t n, FILE *stream);
Эта функция считывает из потока stream в буфер, указанный параметром ptr.
n блоков данных, каждый из которых содержит size байтов. В случае успеха
функция возвращает число прочитанных блоков. Если прочитан конец файла
или произошла ошибка, она возвращает число полностью прочитанных
блоков или 0.
Функция f write () имеет следующий прототип:
size_t
fwrite(const void *ptr, size_t size, size_t n, FILE «stream);
Она записывает в выходной поток stream из буфера, указанного параметром
ptr, n блоков данных, каждый из которых содержит size байтов. В случае
успеха функция возвращает число записанных блоков. В случае ошибки, она
возвращает число полностью записанных блоков или 0.
Язык программирования С. Работа со строками.
Объявление строк в C
Строки реализуются посредством массивов символов. Поэтому объявление
ASCII строки имеет следующий синтаксис:
char имя[длина];
Объявление строки в С имеет тот же синтаксис, что и объявление
одномерного символьного массива. Длина строки должна представлять собой
целочисленное значение (в стандарте C89 – константа, в стандарте C99
может быть выражением). Длина строки указывается с учетом одного
символа на хранение завершающего нуля, поэтому максимальное количество
значащих символов в строке на единицу меньше ее длины. Например, строка
может содержать максимально двадцать символов, если объявлена
следующим образом:
char str[21]; Инициализация строки в С осуществляется при ее объявлении,
используя следующий синтаксис:
char str[длина] = строковый литерал;
Строковый литерал – строка ASCII символов заключенных в двойные
кавычки. Примеры объявления строк с инициализацией:
char str1[20] = "Введите значение: ", str2[20] = "";
Пример:
const char message[] = "Сообщение об ошибке!";
Работа со строками в С
Так как строки на языке С являются массивами символов, то к любому
символу строки можно обратиться по его индексу. Для этого используется
синтаксис обращения к элементу массива, поэтому первый символ в строке
имеет индекс ноль. Например, в следующем фрагменте программы в строке
str осуществляется замена всех символов 'a' на символы 'A' и наоборот.
for(int i = 0; str[i] != 0; i++)
{
if (str[i] == 'a') str[i] = 'A';
else if (str[i] == 'A') str[i] = 'a';
}
Массивы строк в С
Объявление массивов строк в языке С также возможно. Для этого
используются двумерные массивы символов, что имеет следующий
синтаксис:
char имя[количество][длина];
Первым размером матрицы указывается количество строк в массиве, а
вторым – максимальная (с учетом завершающего нуля) длина каждой строки.
Например, объявление массива из пяти строк максимальной длиной 30
значащих символов будет иметь вид:
char strs[5][31];
При объявлении массивов строк можно производить инициализацию:
char имя[количество][длина] = {строковый литерал №1, ... строковый литерал
№N};
Число строковых литералов должно быть меньше или равно количеству
строк в массиве. Если число строковых литералов меньше размера массива,
то все остальные элементы инициализируются пустыми строками. Длина
каждого строкового литерала должна быть строго меньше значения длины
строки (для записи завершающего нуля).
Например:
char days[12][10] = {
"Январь", "Февраль", "Март", ”Апрель", "Май",
"Июнь", "Июль", "Август", "Сентябрь","Октябрь",
"Ноябрь", "Декабрь"
};
При объявлении массивов строк с инициализацией допускается не указывать
количество строк в квадратных скобках. В таком случае, количество строк в
массиве будет определено автоматически по числу инициализирующих
строковых литералов.
Например, массив из семи строк:
char days[][12] = {
"Понедельник", "Вторник", "Среда", "Четверг",
"Пятница", "Суббота", "Воскресенье"
};
Функции для работы со строками в С
Все библиотечные функции, предназначенные для работы со строками,
можно разделить на три группы:
1. ввод и вывод строк;
2. преобразование строк;
3. обработка строк.
Ввод и вывод строк в С
Для ввода и вывода строковой информации можно использовать функции
форматированного ввода и вывода (printf и scanf). Для этого в строке
формата при вводе или выводе строковой переменной необходимо указать
спецификатор типа %s. Например, ввод и последующий вывод строковой
переменной будет иметь вид:
char str[31] = "";
printf("Введите строку: ");
scanf("%30s”,str);
printf("Вы ввели: %s”,str);
Недостатком функции scanf при вводе строковых данных является то, что
символами разделителями данной функции являются:
1. перевод строки,
2. табуляция;
3. пробел.
Поэтому, используя данную функцию невозможно ввести строку,
содержащую несколько слов, разделенных пробелами или табуляциями.
Например, если в предыдущей программе пользователь введет строку:
"Сообщение из нескольких слов", то на экране будет выведено только
"Сообщение".
Для ввода и вывода строк в библиотеке stdio.h содержатся
специализированные функции gets и puts.
Функция gets предназначена для ввода строк и имеет следующий заголовок:
char * gets(char *buffer);
Между тем использовать функцию gets категорически не рекомендуется,
ввиду того, что она не контролирует выход за границу строки, что может
произвести к ошибкам. Вместо нее используется функция fgets с тремя
параметрами:
char * fgets(char * buffer, int size, FILE * stream);
где buffer - строка для записи результата, size - максимальное количество
байт, которое запишет функция fgets, stream - файловый объект для чтения
данных, для чтения с клавиатуры нужно указать stdin. Эта функция читает
символы со стандартного ввода, пока не считает n - 1 символ или символ
конца строки, потом запишет считанные символы в строку и добавит нулевой
символ. При этом функция fgets записывает в том символ конца строки в
данную строку, что нужно учитывать.
Функция puts предназначена для вывода строк и имеет следующий
заголовок:
int puts(const char *string);
Простейшая программа: ввод и вывод строки с использованием функций
fgets и puts будет иметь вид:
char str[102] = "";
printf("Введите строку: ");
fgets(str, 102, stdin);
printf("Вы ввели: ");
puts(str);
Для считывания одного символа можно использовать функцию fgetc(FILE *
stream). Она считывает один символ и возвращает значение этого символа,
преобразованное к типу int, если же считывание не удалось, то возвращается
специальная константа EOF, равная -1. Функция возвращает значение -1 для
того, чтобы можно было обрабатывать ситуацию конца файла, посимвольное
чтение до конца файла можно реализовать следующим образом:
int c;
while ((c = fgetc(stdin)) != EOF) {
// Обработка символа
}
Для вывода одного символа можно использовать функцию int fputc(int c,
FILE *stream);.
Помимо функций ввода и вывода в потоки в библиотеке stdio.h присутствуют
функции форматированного ввода и вывода в строки. Функция
форматированного ввода из строки имеет следующий заголовок:
int sscanf(const char * restrict buffer, const char * restrict string, [address] ...);
Функции форматированного вывода в строку имеют следующие заголовки:
int sprintf(char * restrict buffer,
const char * restrict format, [argument] ...);
int snprintf(char * restrict buffer, size_t maxsize,
const char * restrict format, [argument] ...);
UNIX
В операционной системе UNIX основными средствами взаимодействия
пользователя с системой являются клавиатура и экран монитора,
работающий в текстовом режиме. Вводимый пользователем текст
немедленно отображается на мониторе соответствующими знаками, однако
может и не отображаться (например, в случае ввода пароля). Для управления
вводом используются некоторые нетекстовые клавиши на
клавиатуре: Backspace (он же «Забой») — для удаления последнего
введенного символа или Enter — для передачи команды системе. Нажатие на
эти клавиши не приводит к отображению символа, вместо этого вводимый
текст обрабатывается системой тем или иным способом — эти клавиши и их
комбинации объединяют понятием управляющие символы.
Текстовый принцип работы с машиной позволяет отвлечься от конкретных
частей компьютера, вроде системной клавиатуры и видеокарты с монитором,
рассматривая единое конечное устройство, посредством которого
пользователь вводит текст и передает его системе, а система выводит
необходимые пользователю данные и сообщения. Такое устройство
называется терминалом. В общем случае терминал — это точка входа
пользователя в систему, обладающая способностью передавать текстовую
информацию. Терминалом может быть отдельное внешнее устройство,
подключаемое к компьютеру через порт последовательной передачи данных
(«COM-порт»). В роли терминала может работать (с некоторой поддержкой
со стороны системы) и программа (например, xterm или ssh).
Свойство терминала передавать только символьную информацию приводит к
тому, что некоторые из передаваемых символов должны восприниматься не
как текстовые, а как управляющие (например, символы, возвращаемые
клавишами Backspace и Enter). На самом деле управляющих символов
больше: часть из них предназначена для экстренной передачи команд
системе, часть — для редактирования вводимого текста. Многие из этих
символов не имеют специальной клавиши на клавиатуре, поэтому их
необходимо извлекать с помощью клавиатурного модификатора Ctrl.
Проблема в том, что на клавиатуре может быть так много разных
нетекстовых клавиш, что на них не хватает ограниченного количества разных
управляющих символов. Поэтому большинство нетекстовых клавиш
возвращают так называемую управляющую последовательность, которая
начинается управляющим символом, за которым следует строго
определенное число обычных символов.
Основная среда взаимодействия с UNIX — командная строка. Суть её в том,
что каждая строка, передаваемая пользователем системе, — это команда,
которую та должна выполнить. Пока не нажата клавиша Enter, строку можно
редактировать, затем она отсылается системе.
Команды интерпретируются и выполняются специальной программой —
командной оболочкой (или «shell», по-английски). Через командную
оболочку производится управление пользовательскими процессами — для
этого используются средства межпроцессного обмена, описанные ранее (см.
«Межпроцессное взаимодействие»).
Командная оболочка непосредственно связана с терминалом, через который
осуществляется передача управляющих последовательностей и текста. На
рисунке Рисунок 2.1, «Интерфейс командной строки» представлена общая
схема взаимодействия пользователя с системой при использовании
командной строки.
#include <stdio.h>
#include <malloc.h>
FILE* fp;
fp = fopen("matr.txt", "r+");
if (fp == NULL)
{
puts("error");
return;
}
Int k= 0;
While (!feof(fp))
{
Fscanf (“%d”, n);
K++
}
Int n = 0;
While (!feof(fp))
{
S = fgets(fp);
N++;
}
printf("\nМатрица \n");
printf("\n");
}
fclose(fp);
Int sum = 0;
Int max = 0;
For (int j = 0; j< n; j++);
{
Sum = 0;
}
For (int I =0; I <n; i++)
{
Sum = sum+ mass [i][j];
if (max > mass[i][j])
{
max = mass [i][j];
}
}
FILE* fp;
fp = fopen("matr.txt", "r+");
if (fp == NULL)
{
puts("error");