diff --git a/build/main.pdf b/build/main.pdf index 5c8aba8..d1d090e 100644 Binary files a/build/main.pdf and b/build/main.pdf differ diff --git a/main.tex b/main.tex index 9633b32..4a79a70 100644 --- a/main.tex +++ b/main.tex @@ -31,90 +31,11 @@ \import{sections/}{10-strings} % 11 structs \import{sections/}{11-structs} - -\section{Файлы} -% Коллеги здравствуйте. -% За предыдущие занятия мы с вами познакомились почти со всеми существующими в языке С типами данных, как примитивными, так и ссылочными. Довольно подробно рассмотрели работу почти всех операторов языка. Пришло время поговорить о взаимодействии программы с операционной системой, а именно - о чтении и записи в файловую систему компьютера. - - - - -% Файловая система любого компьютера - это структура. Для языка С файл - это тоже структура. Структура, хранящая данные о положении курсора в файле, его название, буферы, флажки и прочие свойства. Файлы делятся на два основных типа - текстовые и бинарные. Мы рассмотрим работу с текстовыми. -% СЛАЙД О ФАЙЛОВОЙ СИСТЕМЕ - - -% Опишем переменную, хранящую указатель на нашу структуру. Вся основная работа будет проходить через неё. Для того, чтобы присвоить этой переменной указатель на какой-то реальный файл воспользуемся функцией fopen, которая возвращает указатель на адрес в памяти. -% FILE *f; - - - -% Функция принимает в качестве аргументов имя файла в двойных кавычках и режим его открытия. -% Основных используемых режимов шесть - чтение, запись, добавление, двоичное -% чтение, двоичную запись и двоичное добавление. Функции записи и добавления создают файл в случае его отсутствия. А функция записи стирает файл, если он существует и не пустой. -% СЛАЙД О ВОЗМОЖНОСТЯХ И РЕЖИМАХ FOPEN -% Итак создадим текстовый файл с каким-то неожиданным названием вроде filename.txt, и скажем нашей программе, что нужно будет его создать, если его не существует, перезаписать, если существует, а дальше мы будем в него записывать данные. -% Имя файла в аргументе может быть как полным, вроде C:\FILE.TXT тогда файл будет создан в корне диска C, так и относительным, каким мы его указали сейчас. Это значит, что файл будет создан в той папке, в которой запускается наша программа. -% f = fopen(“filename.txt”, “w”); - - -% В случае, если файл не найден или по какой-то причине не создался, в переменную file запишется нулевой указатель, поэтому перед тем, как начать работу с файлом, нужно проверить, смогла-ли программа его открыть, для этого запишем условие если в наш указатель записался нулевой указатель, то дальнейшее выполнение функции Мэйн не имеет смысла. - -% if(file == NULL) return 1; - - -% Если всё хорошо, можем записывать в файл данные. Для записи в файл есть несколько функций, мы воспользуемся самой простой и очевидной -% fprintf(); . В неё в качестве первого аргумента обязательно нужно передать указатель на файл, в который мы собираемся писать, а дальше можно использовать как знакомый нам printf() со всеми его удобствами, заполнителями, экранированными последовательностями и дополнительными аргументами. После того как мы закончили запись в файл его необходимо -% закрыть, вызвав функцию fclose(); - - -% fprintf(f, “Hello, files! %s”, “we did it! \n”); - - - - -% fclose(f); -% Запустим наш проект и посмотрим что у нас получилось. Перейдем в проводник и увидим что в папке проекта появился файл filename.txt, в котором написано наше содержимое, откроем его с помощью блокнота. - - -% Теперь давайте рассмотрим не менее важную тему, а именно - чтение из файла. Для этого нужно его открыть в режиме чтения. Далее мы можем воспользоваться неожиданно похожей функцией - fscanf() чтобы прочитать форматированные значения из файла. Создадим массив из переменных типа char, назовем его word и, при помощи функции fscanf() считаем из файла некоторую строку, которую положим в этот массив. Далее выведем в консоль строку которую прочитали, для этого воспользуемся привычной нам функцией printf, а затем выведем пустую строку. Запустим нашу программу и увидим, что в консоль вывелось слово Hello, - т.е. до пробела, функция fscanf отлично отработала. - -% char word[256]; -% f = fopen(“filename.txt”, “r”); - -% fscanf(f, “%s”, &word); - -% printf(“%s”, word); -% puts(“”); - - -% Но сколько данных читать? Как узнать, что достигнут конец файла? Для этого придумали функцию feof() (FILE END OF FILE) возвращающую ноль, если конец файла не достигнут, и единицу если достигнут. -% Опишем цикл, который выведет в консоль все полученные сканом строки из нашего файла. Для этого мы циклически пройдемся по всему файлу пока не будет достигнут конец и будем выводить считанные строки в консоль - -% Запустим наш проект и убедимся, что вывод в консоль полностью соответствует содержимому файла, и это было не так уж сложно. -% Не забудем в конце закрыть файл. - - - -% char word[256]; -% f = fopen(“filename.txt”, “r”); -% while(!feof(file)){ -% fscanf(f, “%s”, &word); -% printf(“%s”, word); -% } - - -% fclose(f); -% puts(“”); - - -% На следующем уроке поговорим о распределении памяти. До скорой встречи! +% 12 files +\import{sections/}{12-files} \section{Распределение памяти} - -% Коллеги, здравствуйте. -% Это занятие находится в конце курса, но не по важности. Сильная сторона языка С не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности не подвесить среду виртуализации или не сломать операционную систему. - - +Этот раздел находится в конце книги, но не по важности. Сильная сторона языка С не только в возможности работать с указателями, но и в возможности самостоятельно управлять выделяемой памятью внутри программы. В языках высокого уровня данная возможность зачастую скрыта от программиста, чтобы по случайности программа не привела к зависанию среды виртуализации, не попыталась воспользоваться всей возможной оперативной памятью или не сломала операционную систему. % Итак, как мы уже знаем, все переменные всех типов как-то хранятся в памяти, и до этого момента нас устраивало, как операционная система нам эту память выделяет. Но, пришло время взять бразды правления в свои руки. Процесс выделения памяти для программы называется memory allocation отсюда и название функции, которая выделяет память и пишет в предложенный идентификатор указатель на начало этой области. malloc(size); - она принимает в качестве аргумента размер выделяемой памяти. Как видим, функция возвращает пустоту, то есть область памяти будет зафиксирована, но не размечена. То есть это будет просто некоторая пустая область из n байт. % СЛАЙД ПРО MALLOC() И АРГУМЕНТЫ diff --git a/sections/12-files.tex b/sections/12-files.tex new file mode 100644 index 0000000..8a885fa --- /dev/null +++ b/sections/12-files.tex @@ -0,0 +1,65 @@ +\section{Файлы} +В предыдущих разделах мы познакомились почти со всеми существующими в языке С типами данных, как примитивными, так и ссылочными. Довольно подробно рассмотрели работу почти всех операторов языка. Пришло время выйти за пределы программы (хотя бы в части хранения данных) и поговорить о взаимодействии программы с операционной системой, а именно - о чтении и записи в файловую систему компьютера. Файловая система \textit{любого} компьютера - \textbf{это структура}. Для языка С файл - это тоже структура. Структура, хранящая данные о положении курсора в файле, его название, буферы, флажки и прочие свойства. Файлы делятся на два основных типа - текстовые и бинарные. Мы рассмотрим работу с текстовыми, поскольку работа с бинарными практически ничем не отличается, а текст всё-таки проще воспринимается. + +С места в карьер, опишем переменную, хранящую указатель на структуру <<файл>>. Вся основная работа будет проходить через неё. Для того, чтобы присвоить этой переменной указатель на какой-то реальный файл будем пользоваться функцией \code{fopen();}, которая возвращает указатель на адрес в памяти. Функция принимает в качестве аргументов имя файла в двойных кавычках и режим его открытия. +\begin{lstlisting}[language=C,style=CCodeStyle] +FILE *f; +\end{lstlisting} + +Основных используемых режимов шесть: +\begin{itemize} +\item чтение, +\item запись, +\item добавление, +\item двоичное чтение, +\item двоичная запись, +\item двоичное добавление. +\end{itemize} +\subsection{Запись} +Функции \textbf{записи и добавления} \textit{создают} файл в случае его отсутствия. А функция \textbf{записи} \textit{стирает} файл, если он существует и не пустой. Итак создадим текстовый файл с каким-то неожиданным названием, вроде \code{filename.txt}, и скажем нашей программе, что нужно будет его создать, если его не существует, перезаписать, если существует, а дальше мы будем в него записывать данные, то есть режим открытия будет \code{"w"}. Имя файла в аргументе может быть как полным (абсолютным), вроде \code{C:\\FILE.TXT} тогда файл будет создан в корне диска C, или \code{/home/user/file.txt}. Также имя файла может быть и относительным, каким мы его указали сейчас, это значит, что файл будет создан в той папке, в которой запускается наша программа. +\begin{lstlisting}[language=C,style=CCodeStyle] +f = fopen("filename.txt", "w"); +\end{lstlisting} + +В случае, если файл не найден или по какой-то причине не создался, в переменную \code{f} запишется нулевой указатель, поэтому перед тем, как начать работу с файлом, нужно проверить, смогла-ли программа его открыть, для этого запишем условие, что если в наш указатель записался нулевой указатель, то дальнейшее выполнение функции \code{int main (int argc, char *argv[])} не имеет смысла. + +\begin{lstlisting}[language=C,style=CCodeStyle] + if (file == NULL) return 1; +\end{lstlisting} +Если всё хорошо, можем записывать в файл данные. Для записи в файл есть несколько функций, мы воспользуемся самой простой и очевидной:\code{fprintf();}, в неё в качестве первого аргумента обязательно нужно передать указатель на файл, в который мы собираемся писать, а дальше можно использовать как знакомый нам \code{printf();} со всеми его удобствами, заполнителями, экранированными последовательностями и дополнительными аргументами. После того как мы закончили запись в файл его необходимо +закрыть, вызвав функцию \code{fclose();} + +\begin{lstlisting}[language=C,style=CCodeStyle] + fprintf(f, "Hello, files! %s", "we did it!\n"); + fclose(f); +\end{lstlisting} +Запустив проект, посмотрим что у нас получилось. В терминале не будет никакого вывода, но если перейти в проводник, то можно увидеть, что в папке проекта появился файл \code{filename.txt}, в котором написано наше содержимое. Открывается такой текстовый файл любым обычным блокнотом + +\subsection{Чтение} +Отлично, программа теперь умеет сохранять результаты своей работы в файлы, то есть у нас появилось ещё одно средство вывода информации, помимо терминала. Теперь давайте рассмотрим не менее важную тему, а именно - чтение из файла. Ведь тогда мы сможем не просто иначе выводить информацию, но и сохранять её на жёстком диске от запуска к запуску программы, а значит хранить какие-то настройки или промежуточные значения. Для этого нам нужно совершить несколько несложных действий с применением неожиданно знакомой функции \code{fscanf();} чтобы прочитать форматированные значения из файла: +\begin{itemize} +\item создать массив \code{char[]}, для примера, назовем его \code{word}; +\item нужный файл открыть в режиме чтения; +\item при помощи функции \code{fscanf();} считать из файла некоторую строку, которую положим в этот массив. +\end{itemize} +Далее выведем в консоль строку которую прочитали, для этого воспользуемся привычной нам функцией \code{printf();} а затем выведем пустую строку. Запустим нашу программу и увидим, что в консоль вывелось слово \code{Hello}, функция \code{fscanf();} отлично отработала, прочитав все символы из файла до пробела. + +\begin{lstlisting}[language=C,style=CCodeStyle] +char word[256]; +f = fopen("filename.txt", "r"); +fscanf(f, "%s", &word); +printf("%s\n", word); +\end{lstlisting} + +Но сколько данных читать? Как узнать, что достигнут конец файла? Для этого придумали функцию \code{feof();} (англ. file: end of file) возвращающую ноль, если конец файла не достигнут, и единицу если достигнут. Опишем цикл, который выведет в консоль все полученные \code{fscanf();} строки из нашего файла. То есть, мы циклически пройдемся по всему файлу, пока не будет достигнут его конец и будем выводить считанные строки в консоль: + +\begin{lstlisting}[language=C,style=CCodeStyle] +char word[256]; +f = fopen("filename.txt", "r"); +while (!feof(file)) { + fscanf(f, "%s", &word); + printf("%s ", word); +} +printf("\n"); +fclose(f); +\end{lstlisting}