Как сделать перенос строки в си

Добавил пользователь Alex
Обновлено: 05.10.2024

Подскажите, как переходить на новую строку при записи в файл. Я работаю на C++ через WinAPI
(функция WriteFile). Если я пишу '\n', то при просмотре файла в блокноте, строка не переводиться на новую, просто палочка рисуется |

4 ответа

Originally posted by dailys
Если я пишу '\n', то при просмотре файла в блокноте, строка не переводиться на новую, просто палочка рисуется |


Угу, заметил :) Я обычно с текстовыми файлами работаю через стандартные фукнции Си. Через них удобнее с текстами работать. По поводу вопроса: должно быть как-то просто, но на данный момент мне не пришло в голову ничего проще, чем подглядеть код перевода строки в hex-редакторе :)
И вот что получили:

Я создаю текстовый файл в режиме "w" и записываю туда информацию.
Затем считываю её порциями в режиме "r":
считываю первую порцию (30 байт), записываю её в переменную. Перевожу курсор на 30 байт от начала файла, считываю вторую порцию (10 байт) и заношу в переменную, затем так же третью порцию (10 байт). После этого, данная строка символов в файле заканчивается, мне нужно перейти на следующую строку и считать всё точно такими же порциями. Как начать считывать следующую строку?

Вот код программы:

  • Вопрос задан более трёх лет назад
  • 7033 просмотра

Оценить 1 комментарий

Ты вообще зачем восьмеричные коды определяешь для символов, которые и так есть в языке?
CR - '\r'
LF - '\n'
printf("%o %o\n", '\r', '\n');

Зачем вообще эти переводы курсоров? Можно просто использовать fread в режиме rb и считывать сразу в массив ? А запись производить с помощью фукции fwrite. fseek вообще не понимаю зачем нужен, если смещение само считается при записи.

Иван Громов: да это просто туфта какая-то. Открыл файл в текстовом режиме, а потом в нём переход на байтовую позицию выполняет.

Прочитай какую-нибудь приличную книгу по C, ты неправильно используешь функции, неправильно используешь символы. То, что при компиляции ошибок не выдаёт, ещё не значит, что ошибок нет. В файле, открытом в текстовом режиме, нельзя смещаться на байтовую позицию, потому что в текстовом потоке все позиции неточные из-за допустимых неявных преобразований (некоторые символы могут удаляться/добавляться). То есть ошибку оно не выдаст, но результат будет неопределённым, вплоть до неизвестного мусора в массивах. Про CR LF я тебе уже написал - ты делаешь то, что уже сделано и встроено в язык. И символы эти уже встроены, и коды их точно так же можно получить в любой момент.

Пожалуйста, приостановите работу AdBlock на этом сайте.

Итак, строки в языке Си. Для них не предусмотрено отдельного типа данных, как это сделано во многих других языках программирования. В языке Си строка – это массив символов. Чтобы обозначить конец строки, используется символ '\0' , о котором мы говорили в прошлой части этого урока. На экране он никак не отображается, поэтому посмотреть на него не получится.

Создание и инициализация строки

Так как строка – это массив символов, то объявление и инициализация строки аналогичны подобным операциям с одномерными массивами.

Следующий код иллюстрирует различные способы инициализации строк.

Объявление и инициализация строк

Рис.1 Объявление и инициализация строк

В первой строке мы просто объявляем массив из десяти символов. Это даже не совсем строка, т.к. в ней отсутствует нуль-символ \0 , пока это просто набор символов.

Вторая строка. Простейший способ инициализации в лоб. Объявляем каждый символ по отдельности. Тут главное не забыть добавить нуль-символ \0 .

Третья строка – аналог второй строки. Обратите внимание на картинку. Т.к. символов в строке справа меньше, чем элементов в массиве, остальные элементы заполнятся \0 .

Четвёртая строка. Как видите, тут не задан размер. Программа его вычислит автоматически и создаст массив символов нужный длины. При этом последним будет вставлен нуль-символ \0 .

Как вывести строку

Дополним код выше до полноценной программы, которая будет выводить созданные строки на экран.

Различные способы вывода строки на экран

Рис.2 Различные способы вывода строки на экран

Как видите, есть несколько основных способов вывести строку на экран.

  • использовать функцию printf со спецификатором %s
  • использовать функцию puts
  • использовать функцию fputs , указав в качестве второго параметра стандартный поток для вывода stdout .

Единственный нюанс у функций puts и fputs . Обратите внимание, что функция puts переносит вывод на следующую строку, а функция fputs не переносит.

Как видите, с выводом всё достаточно просто.

Ввод строк

С вводом строк всё немного сложнее, чем с выводом. Простейшим способом будет являться следующее:

Функция gets приостанавливает работу программы, читает строку символов, введенных с клавиатуры, и помещает в символьный массив, имя которого передаётся функции в качестве параметра.
Завершением работы функции gets будет являться символ, соответствующий клавише ввод и записываемый в строку как нулевой символ.
Заметили опасность? Если нет, то о ней вас любезно предупредит компилятор. Дело в том, что функция gets завершает работу только тогда, когда пользователь нажимает клавишу ввод. Это чревато тем, что мы можем выйти за рамки массива, в нашем случае — если введено более 20 символов.
К слову, ранее ошибки переполнения буфера считались самым распространенным типом уязвимости. Они встречаются и сейчас, но использовать их для взлома программ стало гораздо сложнее.

Итак, что мы имеем. У нас есть задача: записать строку в массив ограниченного размера. То есть, мы должны как-то контролировать количество символов, вводимых пользователем. И тут нам на помощь приходит функция fgets :

Функция fgets принимает на вход три аргумента: переменную для записи строки, размер записываемой строки и имя потока, откуда взять данные для записи в строку, в данном случае — stdin . Как вы уже знаете из 3 урока, stdin – это стандартный поток ввода данных, обычно связанный с клавиатурой. Совсем необязательно данные должны поступать именно из потока stdin , в дальнейшем эту функцию мы также будем использовать для чтения данных из файлов.

Обратите внимание, функция fgets считывает не 10 символов, а 9 ! Как мы помним, в строках последний символ зарезервирован для нуль-символа.

Давайте это проверим. Запустим программу из последнего листинга. И введём строку 1234567890 . На экран выведется строка 123456789 .

Пример работы функции fgets

Рис.3 Пример работы функции fgets

Возникает вопрос. А куда делся десятый символ? А я отвечу. Он никуда не делся, он остался в потоке ввода. Выполните следующую программу.

Вот результат её работы.

Непустой буфер stdin

Рис.4 Непустой буфер stdin

Поясню произошедшее. Мы вызвали функцию fgets . Она открыла поток ввода и дождалась пока мы введём данные. Мы ввели с клавиатуры 1234567890\n ( \n я обозначаю нажатие клавиша Enter ). Это отправилось в поток ввода stdin . Функция fgets , как и полагается, взяла из потока ввода первые 9 символов 123456789 , добавила к ним нуль-символ \0 и записала это в строку str . В потоке ввода осталось ещё 0\n .

Далее мы объявляем переменную h . Выводим её значение на экран. После чего вызываем функцию scanf . Тут-то ожидается, что мы можем что-то ввести, но т.к. в потоке ввода висит 0\n , то функция scanf воспринимает это как наш ввод, и записывается 0 в переменную h . Далее мы выводим её на экран.

Исправим последний пример так, чтобы его работа была предсказуемой.

Теперь программа будет работать так, как надо.

Сброс буфера stdin функцией fflush

Рис.4 Сброс буфера stdin функцией fflush

Подводя итог, можно отметить два факта. Первый. На данный момент использование функции gets является небезопасным, поэтому рекомендуется везде использовать функцию fgets .

Второй. Не забывайте очищать буфер ввода, если используете функцию fgets .

На этом разговор о вводе строк закончен. Идём дальше.

Практика

Решите предложенные задачи:


Для удобства работы сразу переходите в полноэкранный режим

Их можно разбить, например, так:

Если же нужно разбить строковую переменную, то тут может быть 2 основных варианта.
Например, дана такая строка:

Вариант 1, мультистрока с "@" - просто перед присвоением строки ставим символ @:
Например,

Вариант 2, конкатенация с "+" - разбиваем строку на части и применяем стандартную конкатенацию:

Если Вам понравилась статья, пожалуйста, поставьте лайк, сделайте репост или оставьте комментарий. Если у Вас есть какие-либо замечания, также пишите комментарии.

Читайте также: