# 07 Лекция Полная версия [TOC] ## Ввод/Вывод ### Файловый ввод/вывод `fopen` - открыть файл, принимает 2 аргумента 1) путь (просто имя файла если в тек папке - то, **откуда запускали исполняемый файл** .exe), или абсолютный/относительный путь, только надо не забывать, что в пути надолибо удвоить обратный слэш - `\\`, либо писать путь через прямые - `/` 2) режим (как открыть файл): * `"r"` - на чтение, если файла нет - вернет NULL. * `"w"` - на запись, если файла нет - создает, если есть - обнуляет файл. * `"a"` - на дозапись, если файла нет - создаст, если есть - откроет на конце файла. Возвращает указатель на `FILE`. У режима есть модификаторы - `t` или `b`, текстовый и двоичный (бинарный) соответственно, применяется после режима - `"rt"`, `"wb"`, по умолчанию всегда текстовый режим. [Подробнее](https://en.cppreference.com/w/cpp/io/c/fopen) Можно открыть на запись/чтение одновременно - добавить `+` к режиму (до модификатора), например: `r+b` или `w+`, *использовать очень аккуратно* Если происходит какая либо ошибка, нет файла/не удалось создать/нет прав - `fopen` вернет `NULL`, специальное значение (`NULL == 0`). Рекомендуется **всегда** проверять, тк легко получить [null pointer exeption](https://stackoverflow.com/questions/1823721/how-to-catch-the-null-pointer-exception#:~:text=There's%20no%20such%20thing%20as,other%20exceptions%20in%20C%2B%2B) - падение программы. `fclose` - закрыть файл, принимает указатель на `FILE` (необходимо всегда закрывать файл, в противном случае, в лучшем случае, файл будет держаться до конца нашей программы (а возможно до перезагрузки компьютера)) **Файлы обязательно надо закрывать!** Желательно когда он перестал быть нужным, а не в конце программы. Тк этот файл блокируется пока он открыт нашей программой, так же под него выделенна память Чтобы работать с файлами - мы можем использовать функции семейства printf/scanf, добавив `f` к названию функции, и ещё один первый аргумент - указатель на файл (то, что возвращает `fopen`)? напрмер: `fscanf(in, "%i", &a);` ```c int read_and_write_sum_file() { int a, b; FILE *in = fopen("in.txt", "r"); //"r" - на чтение FILE *out = fopen("out.txt", "w"); // "w" - на запись if(in == NULL) // проверка на открытие { printf("I can't open the input file\n"); return 1; } if(out == NULL) { printf("I can't open the output file\n"); return 1; } fscanf(in, "%i %i", &a, &b); //считать два числа fprintf(out, "%i\n", a+b); //записать их сумму //code// fclose(in); // закрытие файлов fclose(out); return 0; } ``` В более низкоуровневых функциях (с - `open`, win - `create file`) можно указать какие операции мы хотим оставить другим пользователям. > C++ файловым (и не только) стандартным вводом и выводом лучше не пользоваться, тк под ними скрываются большие нетривиальные куски кода, которые медленно работают и плохо распаралеливаются (из-за глобальных переменных) (лучше в С++ использовать сишные функции ввода-вывода) Модификатор `b` двоичный - это про переводы строк Какие бывают переводы строк: 1) Windows - `0x0D 0x0A` (13 10) (`\r` `\n`) 2) Unix - `0x0A` (10) (`\n`) (Linux) (new MacOC) 3) Old MacOC - `0x0D` (13) (`\r`) > По [ASCII](https://en.wikipedia.org/wiki/ASCII#Control_code_chart), на самом деле: > * `0x0A` - [Line Feed](https://en.wikipedia.org/wiki/Newline) (перевод строки) > * `0x0D` - [Carriage Return](https://en.wikipedia.org/wiki/Carriage_return) (возврат каретки) Если мы работаем с двоичными данными, мы всегда хотим открыть в режиме с модификатором `b`. (часто это забывают сделать пользователи linux, тк у них совпадет `\n` и системный перевод) ### Потоки > Стандартный ввод/вывод на самом деле тоже файловый, можно перенаправить из консоли в файл (`freeopen`) > Есть три стандартных потока: > 1) stdin - поток ввода > 2) stdout - поток вывода > 3) stderr - поток ошибок (пример - `fprintf(stderr, "Hi");`) ## Про ветвление ```c if(out == NULL) //можно писать без {} (блока) если ОДНА строчка printf("I can't open the output file\n"); else // else - если if не отработал - условие в скобочках ложное printf("OK"); //если строчек будет несколько (без блока) в if будет выполненна //ТОЛЬКО ПЕРВАЯ, вне зависимости от отступа ``` `;` посреди текста - это пустой оператор, её любят ставить после `}`, однако она не всегда там нужна и её не стоит пихать куда попало, например: ```c if(out == NULL) { printf("I can't open the output file\n"); }; //в данном случа означает, что цепочка if закончилась else // НЕ скомпилируется, тк не найдет свой if printf("OK"); ``` Так же можно создавать длинные цепочки if с помощью `else if` - отрицает все предыдущие if и принимает новое утверждение в скобках, например: ```c if(a == 5) { printf("a == 5\n"); } else if(b == 3) { printf("a != 5, but b == 3\n"); } else { printf("a != 5, and b != 3\n"); } ``` If в скобках принимает логическое значение, то есть 0 или 1 (false или true), исполняет код под под if когда значение в скобках принимает логическую единицу, в связи с этим, и тем, что NULL ассоциируется с 0, например, можно короче записать проверку на неоткрытие файла: ```c if(!in) //! - инвертировать логическое значение, 0 -> 1, 1 -> 0 //in указатель на файл (результат fopen) { printf("I can't open the input file\n"); } //ТОЖЕ САМОЕ if(in == NULL) { printf("I can't open the input file\n"); } ``` ## Циклы 1. while ```c int a = 4; while(a < 10) //цикл будет выполняться //пока условие в скобках - логическая единица { a++; } // a == 10; ``` --- 2. do while ```c int a = 10; do //блок под do выполниться один раз { a++; } while(a < 10); //затем цикл будет выполняться //пока условие в скобках - логическая единица //рекомедуется писать `while` на строке с `{`, для большей понятности //a == 11; ``` ```c int a = 10; while(a < 10) //обычный while { a++; } // a == 10; ``` --- 3. for ```c for(int i = 0; i < 10; i++) // int i = 0 происходит до цикла // i < 10 условие как в while // i++ происходит на каждом шаге в конце { printf("%i\n", i); } //напечатно: 0 1 2 3 4 5 6 7 8 9 ``` Эквивалент: ```c for(A; B; C) { D; //кусок кода } // ТОЖЕ САМОЕ (ПОЧТИ) { A; //происходит до цикла, обычно создание переменной while(B) //условие { D; //кусок кода C; //Происходит на каждом шаге } } ``` В таком эквиваленте есть только одно расхождение, при использовании слова `continue;` `continue;` - ключевое слово для цикла, означает пропустить всё до конца следующего шага (Оставляет `С` в `for`) `break;` - ключевое слово для цикла, означает выйти из цикла