Как перевести указатель на следующую строку в файле с

Обновлено: 07.07.2024

Я видел программы для обработки файлов и в одной из программ, использующих fseek , как показано ниже:

Таким образом можно переместить указатель файла на следующую строку сразу после этой строки

BO_ 377 FC_DM_MISC: 8 FC SG_ DATA3 m11 : 31|8@0+ (1,0) [0|0] "" DM

Это две строки, и я хочу запрограммировать таким образом, чтобы при идентификации числа 377 указатель переходил на следующую строку, то есть на строку SG_ DATA3 , несмотря на пробелы после 8 FC . Как это можно сделать, используя fseek в C?

fseek не знает и не заботится о том, что такое «линия». Все, что он может сделать, это переместить указатель чтения в указанное вами положение.

Мне нужно перейти к следующей строке, начинающейся, когда было идентифицировано число 377 . следует ли мне написать собственное условие для перемещения указателя файла на следующую строку?

Непонятно, почему вы хотите переместить позицию файла на следующую строку. Если вы читаете ввод с помощью fgets , указатель файла все равно перемещается на следующую строку. Использование fseek лучше подходит для файлов произвольного доступа с записями фиксированного размера, чем для последовательных текстовых файлов со строками переменной длины.

fseek действительно полезен только в том случае, если вы уже знаете свой пункт назначения. Если вам нужно отсканировать следующий символ новой строки, это что-то, что вам нужно сделать с чем-то вроде fread или fgets и некоторым кодом синтаксического анализа.

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

Как я могу использовать fgets для чтения построчно? Я вижу это как лучший вариант, которым можно манипулировать

Это все, что делает fgets , читает файл построчно.

В вашем коде даже нет буфера для чтения. Примеров while(fgets(buffer, sizeof buffer, stream) != NULL) < . >существует огромное количество.

Ответы 2

fseek используется для двоичных данных, если вы работаете с текстовым файлом, вы должны использовать либо fgets , либо getline (рекомендуется использовать getline ).

Существует открытое обсуждение «fgets () vs getline», и многие говорят, что «fgets устарел» - это всего лишь пропаганда gcc в пользу их конкретной функции getline ().

Возможный недостаток fgets() заключается в том, что он ничего не сообщает вам, если читаются нулевые байты, что вы можете избежать с помощью getline() .

Но опять же, если вам не нравится gcc или вы используете что-то другое, используйте fgets() . Если вы застряли с gcc, используйте getline() .

getline - это нестандартный C.

@Weather Vane Отредактированный ответ.

Редактирование не делает его лучше. getline() не существует в стандарте C. Это было - особенность библиотеки GNU C, которая теперь является частью стандарта POSIX. Никакой пропаганды ни с какой стороны - getline() просто удобен в использовании, но если вам нужна полная портативность, не используйте его. Я совершенно не понимаю ваш абзац про NULL .

gcc не обязывает использовать getline . Таким образом, "застревание" с gcc позволяет использовать стандартный fgets . NULL , возвращенный fgets , сообщает вам, что данных больше не было. Идиоматическое употребление показано в моем комментарии к основному вопросу.

В случае успеха getline () и getdelim () возвращают количество прочитанных символов, включая символ-разделитель, но не включая завершающий нулевой байт ('\ 0'). Это значение можно использовать для обработки встроенных нулевых байтов в прочитанной строке.

Почему текстовый файл должен содержать встроенные «нулевые байты»? Кто они такие?

@ малинчекуров, так что вы иметь в виду, что getline() позволяет читать что-то, содержащее символы NUL (это не NULL , который был бы указателем). Это несколько сомнительная особенность функции, имеющей дело с текст - если вы ожидаете байтов NUL , вам, вероятно, следует использовать fread() .

Обычный пользователь «тупой», он не знает, что в текстовом файле не может быть такого символа. Если вы читаете текстовый файл с помощью fgets и сталкиваетесь с таким байтом, это нарушит ваш код. Что касается значения NULL, я говорю не в смысле указателя, а в смысле чтения нулевого байта.

да, и этот персонаж называется NUL , а не NULL . NULL - это стандартная марка C, определенная для нулевой указатель, например (void *)0 .

Кстати, достаточно использовать среду выполнения Microsoft C для Windows, и у вас не будет реализации getline() .

На странице руководства GNU написано, что это null, я следую тому, что он говорит, и он говорит, что встроенные символы null, а не nul.

«он не знает, что текстовый файл не может иметь такого символа. Если вы читаете текстовый файл с помощью fgets и сталкиваетесь с таким байтом, это нарушит ваш код.» это противоречит самому себе. текстовый файл не содержит NUL . «Тупой» пользователь, пытающийся прочитать файл двоичный с помощью fgets() , должен сделать шаг назад и научиться. Возможность читать двоичные файлы с помощью getline() по-прежнему выглядит странно.

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

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

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

Функция, которую я написал до сих пор:

Мой вопрос: как перенести указатель файла inptr на следующую строку?

Здесь вам не нужно увеличивать inptr , потому что, поскольку fscanf() in for цикл выполняет его указатель, продолжает увеличиваться, поэтому в следующем цикле вы будете на следующей строке.

В приведенном выше коде вам не хватает 1-го символа любой строки.,

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

Как я могу переместить указатель файла на следующую строку в файле?

Файлы - это набор байтов, значение байтов которых зависит от формата файла.

"Простой текст" - это группа файлов разных форматов; с различными способами кодирования символов (EBCDIC, ASCII, многими вариациями "расширенного ASCII", UTF-8, UCS-2, UTF-16. ) и различными способами представления "конца строки" ("\n", "\ r\n \", "\ r").

Первым шагом является принятие решения о том, будет ли ваше программное обеспечение принимать один конкретный вариант формата файла "обычный текст" (и будет ли оно повреждено для всего остального - например, когда кто-то передает файл из другой операционной системы), или поддерживать несколько форматов файлов с явным контролем. (с аргументом командной строки /s, чтобы пользователь мог указать ему, какой формат файла) и/или если он попытается автоматически обнаружить (например, предположим UTF-8, который будет работать и для ASCII, а затем автоматически определит, что " конец строки ", возможно, приняв"\r "или"\n ", а затем проверив, следует ли \n" за "\ r" или "\ r" следует за \n ").

Следующим шагом является преобразование символов из любого формата файла, который будет использоваться, в некий "стандартный для вас" набор символов (который может быть или не быть тем набором символов, который используется компилятором) при отбрасывании ненужных (например, таких как Unicode). "метки порядка байтов") и имеет дело с возможностью искаженных/поврежденных данных (например, последовательность байтов, которая недопустима для UTF-8, байт, который недопустим для ASCII. ) и имеет дело с нежелательными допустимыми символами (NULL), ЗВОН, УДАЛИТЬ. ).

Обратите внимание, что fscanf(inptr, "%c", &in); чрезвычайно плох (вы можете потратить большую часть своего ЦП на эту функцию, анализируя строку формата "%c" ), и вы можете использовать fgetc() в качестве "менее ужасной" альтернативы; и все эти функции ( fscanf() , fgetc() , fgets() . ) в любом случае в основном непригодны для использования (если только вы не делаете неизвестные специфичные для компилятора предположения о том, какой формат файла на самом деле является "простым текстом", а затем нарушается). и неправильно для всего остального), и большинство из этих функций работают медленно. Вместо; вы хотите рассмотреть возможность использования read() (чтобы можно было обработать весь буфер, полный байтов, и избежать накладных расходов функций библиотеки C и/или вызовов API ядра для каждого байта), или, возможно, mmap() .

Указатели. Часть 4. Указатели и строки символов. Использование указателей при преобразовании (конвертировании) строк

Данная тема основывается на следующих темах:

Содержание

Поиск на других ресурсах:

1. Как описать неуправляемый указатель ( * ) на строчный литерал? Примеры

Более подробно о литералах описывается здесь .

Строка символов представляет собой строчный литерал, который есть массивом символов типа char . Адрес первого символа строчного литерала есть начальным значением указателя. Указатель на первый элемент строчного литерала есть указателем на весь строчный литерал.

Пример. Указатель ps на строчный литерал. Попытка изменить символ в строчном литерале.

При попытке изменения значения символа строчного литерала возникает ошибка:

2. Как описать указатель на строку, который описан как массив символов? Пример

Имя массива символов есть указателем-константой. Если строка описана как массив символов, тогда можно изменять символы строки с помощью указателя.

Пример 1. Указатель на массив символов. Доступ к символу строки, который описан как массив символов.

3. Как с помощью неуправляемого указателя ( * ) получить значение i -го элемента строки символов? Пример

Пример. Чтение символа в строке символов с помощью указателя.

4. Преобразование из char в String . Пример использования управляемого указателя ( ^ )

Для работы с строками символов язык C/C++ CLI поддерживает класс System::String . В этом классе есть много методов для удобного оперирования строками символов.

Для преобразования из типа char в тип String используется управляемый указатель.

Пример 1. Преобразование из типа char* в тип String .

Пример 2. Преобразование из типа char[] в тип String .

В вышеприведенном примере использована функция

Чтобы использовать эту функцию нужно подключить библиотеку <cstring> или <string.h> .

5. Преобразование из wchar_t в String . Пример использования управляемого указателя ( ^ )

Тип wchar_t поддерживает большие символьные наборы, например Unicode . Для преобразования из wchar_t в String целесообразно использовать управляемый указатель ^ .

Более подробно об особенностях типа wchar_t в C/C++ CLI описывается в статье Базовые типы данных C++ .

Пример. Преобразование из типа wchar_t[] в тип String .

6. Преобразование из string в System.String . Пример использования управляемого указателя ( ^ )

Язык C++ CLI поддерживает тип string для работы со строками символов. Для преобразования из string в System.String используется метод c_str() .

Чтобы использовать тип string в программах нужно в начале модуля подключить библиотеку <string> и пространство имен std

Пример. Преобразование из string в System::String .

7. Преобразование из String в char . Пример использования управляемого указателя (^)

Преобразование происходит в 2 этапа.
На первом этапе происходит преобразование из типа String в тип wchar_t . Это осуществляется с помощью функции

где s – строка типа String . Функция PtrToStringChars() возвращает объект типа wchar_t .

На втором этапе происходит преобразование из типа wchar_t в тип char . Это осуществляется с помощью функции wcstombs() , которая получает 5 параметров. Ниже приводится описание функции wcstombs() :

    • numChars – количество символов, которые удалось конвертировать (преобразовать);
      • mbs – адрес буфера памяти, в котором будет записан результат;
        • size_mbs – размер буфера памяти для символов, которые конвертируются;
          • wcs – строка, которая конвертируется (исходная строка);
          • len – максимальная длина исходной строки wcs или значение _TRUNCATE .

          Тип size_t есть результатом оператора sizeof() и составляет длину объекта.

          Пример.

          8. Преобразование из char в wchar_t . Пример использования неуправляемого указателя ( * )

          Пример. Преобразование из char* в wchar_t* .

          В вышеприведенном примере использована функция

          которая реализована в модуле <cstring> (или <string.h> ). Функция возвращает длину строки src .

          Функция mbstowcs_s() получает 5 параметров и имеет описание:

          • numChars – количество символов, которые удалось сконвертировать (преобразовать);
          • wcs – адрес буфера памяти, в котором будет записан результат (тип wchar_t *);
          • size_wcs – размер буфера памяти для символов, которые конвертируются;
          • mbs – строка, которая конвертируется (исходная строка);
          • len – максимальная длина исходной строки mbs или значение _TRUNCATE .

          Тип size_t есть результатом оператора sizeof() и составляет длину объекта.

          9. Преобразование из String в wchar_t . Пример изпользования управляемого указателя ( ^ )

          При данном преобразовании используется метод

          где входной параметр dest – строка типа String . Метод возвращает указатель на первый символ строки типа String . Этот указатель можно передавать в функцию wcscpy_s() .

          Чтобы использовать методы PtrToStringChars() и wcscpy_s() нужно подключить модули <vcclr.h> и <cstring> .

          Пример. Преобразование строки src типа String в строку dest типа wchar_t .

          Метод PtrToStringChars() получает входным параметром строку типа String .

          В программе строки могут определяться следующим образом:

          • как строковые константы;
          • как массивы символов;
          • через указатель на символьный тип;
          • как массивы строк.

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

          Под хранение строки выделяются последовательно идущие ячейки оперативной памяти. Таким образом, строка представляет собой массив символов. Для хранения кода каждого символа строки отводится 1 байт.

          Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf() .

          При определении массива символов необходимо сообщить компилятору требуемый размер памяти.

          Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:

          char m2[]= "Горные вершины спят во тьме ночной." ;
          char m3[]=< 'Т','и','х','и','е',' ','д','о','л','и','н','ы',' ','п','о','л','н','ы',' ','с','в','е','ж','е','й',' ','м','г','л','о','й','\0' >;

          В этом случае имена m2 и m3 являются указателями на первые элементы массивов:


          При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:

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

          В этом случае объявление массива переменной m4 может быть присвоен адрес массива:

          m4 = m3;
          *m4 эквивалентно m3[0]= 'Т'
          *(m4+1) эквивалентно m3[1]= 'и'

          Здесь m3 является константой-указателем. Нельзя изменить m3 , так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4 .

          Для указателя можно использовать операцию увеличения (перемещения на следующий символ):

          Массивы символьных строк

          Иногда в программах возникает необходимость описание массива символьных строк . В этом случае можно использовать индекс строки для доступа к нескольким разным строкам.

          Инициализация выполняется по правилам, определенным для массивов.
          Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние
          последовательности.
          Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:

          Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину.

          Массив строк

          Свободный массив


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

          Операции со строками

          Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:

          • выделить блок оперативной памяти под массив;
          • проинициализировать строку.

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

          Функции ввода строк

          Для ввода строки может использоваться функция scanf() . Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат "%s" для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.

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

          В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

          Функции вывода строк

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

          или в сокращенном формате

          Для вывода строк также может использоваться функция

          которая печатает строку s и переводит курсор на новую строку (в отличие от printf() ). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.

          Функция ввода символов

          Для ввода символов может использоваться функция

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

          Функция вывода символов

          Для вывода символов может использоваться функция

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

          Пример Посчитать количество введенных символов во введенной строке.

          Количество введенных символов в строке

          Результат выполнения

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

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

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

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

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

          Рис.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 , в дальнейшем эту функцию мы также будем использовать для чтения данных из файлов.

          Если в ходе выполнения этой программы мы введем строку длиннее, чем 10 символов, в массив все равно будут записаны только 9 символов с начала и символ переноса строки, fgets «обрежет» строку под необходимую длину.

          Обратите внимание, функция 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 .

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

          Практика

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


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

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