C - fgets () - длина символа новой строки

Я пытаюсь прочитать 1 строку, и я не уверен, как представлен символ новой строки. Должен ли я рассматривать его как 2 символа или 1 символ при чтении из файла с помощью fgets ()? Например, у меня есть строка из 15 символов + новая строка в файле. Итак, как мне безопасно выделить строку и прочитать эту строку?

Сначала я попробовал это:

char buf[16];
fgets(buf, 16, f);

Он правильно прочитал строку без символа новой строки, и я предполагаю, что buf [15] содержит нулевой символ.

Однако, когда я хочу прочитать и сохранить символ новой строки, он работает не так, как я думал. Насколько я знаю, '\ n' следует рассматривать как один символ и занимать всего один байт, поэтому, чтобы его прочитать, мне просто нужно прочитать еще один символ.

Но когда я пробую это

char buf[17];
fgets(buf, 17, f);

он делает то же самое, что и предыдущий пример - теперь в моей строке хранится символ новой строки (я не уверен, где в этом случае хранится нулевой символ)

Чтобы прочитать всю строку с новой строкой, мне нужно сделать это

char buf[18];
fgets(buf, 18, f);

ИЛИ это (это работает, но я не уверен, безопасно ли это)

char buf[17];
fgets(buf, 18, f);

Возникает вопрос: зачем мне выделять и читать 18 символов, если в строке всего 15 символов + новая строка?


person user10099    schedule 17.11.2012    source источник
comment
это работает, но я не уверен, безопасно ли это ‹- это небезопасно. Если строка достаточно длинная, fgets пишет вне буфера.   -  person Daniel Fischer    schedule 17.11.2012
comment
cplusplus.com/reference/clibrary/cstdio/fgets   -  person Johnny Mopp    schedule 17.11.2012
comment
Можете ли вы проверить содержимое строки (с 18-байтовым буфером и fgets), есть ли '\ r' в позиции 15?   -  person Daniel Fischer    schedule 17.11.2012
comment
В Windows символ новой строки состоит из двух символов: "\r\n".   -  person Some programmer dude    schedule 17.11.2012
comment
в buf [15] есть что-то с кодом ASCI 13 (который, вероятно, является '\ r'), buf [16] содержит '\ n', а buf [17] является нулевым символом. Хорошо, спасибо за помощь, теперь я понимаю, почему мне нужно 2 символа для новой строки.   -  person user10099    schedule 17.11.2012


Ответы (2)


Вам необходимо предоставить буферное пространство для 15 символов текста, до 2 символов для новой строки (для обработки завершения строки Windows \r\n) и еще одного для нулевого завершения. Итак, это 18.

Как и здесь:

char buf[18]; fgets(buf, 18, f);

Параметр num для fgets сообщает вызову размер вашего буфера, в который выполняется запись.

person JohnnyHK    schedule 17.11.2012
comment
Хорошо, я знал это, я просто не знал, ПОЧЕМУ мне нужно выделить 2 символа для новой строки. Теперь я вижу, что новая строка на самом деле состоит из двух символов - ›'\ r' + '\ n'. Спасибо, в любом случае - person user10099; 17.11.2012
comment
@ user10099 А, ладно. Добавлено примечание, почему. - person JohnnyHK; 17.11.2012
comment
Нет, обычно вам не нужно выделять 2 символа для новой строки. Откройте файл в текстовом режиме, и библиотека преобразует все, что использует ОС, в один символ '\n'. (Если вы не читаете файл, созданный в другой ОС и неправильно преобразованный.) - person Keith Thompson; 18.11.2012

Я пытаюсь прочитать 1 строку, и я не уверен, как представлен символ новой строки.

В текстовом режиме новая строка - это '\ n', и это верно для любой соответствующей реализации C, и я бы не использовал fgets ни для чего, кроме потока текстового режима (я не знаю - и я не хочу знать - как он работает в двоичном режиме в реализации, использующей \ r в качестве маркера конца строки, или, что еще хуже, используя внеполосный маркер конца строки, я не удивлюсь, что он ищет \ n и никогда не находит его, поэтому попробуйте прочитать до конца файла).

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

person AProgrammer    schedule 17.11.2012
comment
Спасибо за ответ, но я не совсем понимаю, что вы имеете в виду под текстовым режимом и двоичным режимом. На данный момент я просто выделю 2 символа для новой строки + 1 символ для nullchar + x символов для максимальной длины строки, и это не должно вызывать никаких проблем, когда я использую его на той же машине. - person user10099; 17.11.2012
comment
@ user10099 Файл можно открыть в двоичном или текстовом режиме, пожалуйста, прочтите документацию fopen. В большинстве Unix / Linux они одинаковы, но в Mac и Win совсем не одинаковы, поэтому важно использовать правильный режим. В текстовом режиме строка C всегда имеет только \ n в качестве новой строки, независимо от того, что это за файл на диске. - person hyde; 17.11.2012
comment
Я читал некоторые документы, и там говорится, что каждый файл по умолчанию открывается в текстовом режиме, а фильтрация символов новой строки зависит от компилятора. Так что я думаю, мне просто нужно обработать как '\ n', так и '\ r \ n', чтобы сделать это безопасным. - person user10099; 17.11.2012
comment
@ user0099, если вы откроете его в текстовом режиме, вы не должны увидеть \ r \ n для действительных текстовых файлов. (Существует возможность импорта файла с \ r \ n в ОС, которая просто использует \ n без преобразования и где среда выполнения не будет отфильтровывать \ r). - person AProgrammer; 17.11.2012
comment
Я пытался открыть файл с помощью fopen (FILE_PATH, rt); вместо fopen (FILE_PATH, r); и да, нет \ r \ n, просто \ n .. так что это в значительной степени решает все, я надеюсь .. думал, что текстовые файлы по умолчанию открываются в текстовом режиме. Спасибо - person user10099; 17.11.2012
comment
@ user10099, r - стандартный способ запросить текстовый файл, а rt не определен стандартом (но это совместимое расширение, которое дает ему значение). - person AProgrammer; 17.11.2012
comment
@hyde: Современная MacOS использует LF в стиле Unix для завершения строк. - person Keith Thompson; 18.11.2012