Если число четное, условие '!backshlash
' (строка 72) будет истинным. В этом случае конечный символ конца строки замещается байтом NUL, и код выходит из цикла.
С другой стороны, если число нечетно, строка содержит четное число пар обратных слешей (представляющих символы \\, как в С), и конечную комбинацию символов обратного слеша и конца строки.[43] В этом случае, если в буфере остались по крайней мере 80 свободных байтов, программа продолжает чтение в цикле следующей строки (строки 78–81). (Использование магического числа 80 не очень здорово; было бы лучше определить и использовать макроподстановку.)
По достижении строки 83 программе нужно больше места в буфере. Именно здесь вступает в игру динамическое управление памятью. Обратите внимание на комментарий относительно сохранения значения p
(строки 83-84); мы обсуждали это ранее в терминах повторной инициализации указателей для динамической памяти. Значение end также устанавливается повторно. Строка 89 изменяет размер памяти.
Обратите внимание, что здесь вызывается функция xrealloc()
. Многие программы GNU используют вместо malloc()
и realloc()
функции-оболочки, которые автоматически выводят сообщение об ошибке и завершают программу, когда стандартные процедуры возвращают NULL
. Такая функция-оболочка может выглядеть таким образом:
extern const char *myname; /* установлено в main() */
void *xrealloc(void *ptr, size_t amount) {
void *p = realloc(ptr, amount);
if (p == NULL) {
fprintf(stderr, "%s: out of memory!\n", myname);
exit(1);
}
return p;
}
Таким образом, если функция xrealloc()
возвращается, она гарантированно возвращает действительный указатель. (Эта стратегия соответствует принципу «проверки каждого вызова на ошибки», избегая в то же время беспорядка в коде, который происходит при таких проверках с непосредственным использованием стандартных процедур.) Вдобавок, это позволяет эффективно использовать конструкцию 'ptr = xrealloc(ptr, new_size)
', против которой мы предостерегали ранее.
Обратите внимание, что не всегда подходит использование такой оболочки. Если вы сами хотите обработать ошибки, не следует использовать оболочку. С другой стороны, если нехватка памяти всегда является фатальной ошибкой, такая оболочка вполне удобна.
97 if (ferror(ebuf->fp))
98 pfatal_with_name(ebuf->floc.filenm);
99
100 /* Если обнаружено несколько строк, возвратить их число.
101 Если не несколько, но _что-то_ нашли, значит, прочитана
102 последняя строка файла без завершающего символа конца
103 строки; вернуть 1. Если ничего не прочитано, это EOF;
104 возвратить -1. */
105 return nlines ? nlines : p == ebuf->bufstart ? -1 : 1;
106 }
В заключение, функция readline()
проверяет ошибки ввода/вывода, а затем возвращает описательное значение. Функция pfatal_with_name()
(строка 98) не возвращается.[44]
3.2.1.9. Только GLIBC: чтение целых строк: getline()
и getdelim()
Теперь, когда вы увидели, как читать строки произвольной длины, вы можете сделать вздох облегчения, что вам не нужно самим писать такую функцию. GLIBC предоставляет вам для этого две функции:
#define _GNU_SOURCE 1 /* GLIBC */
#include
#include
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);
Определение константы _GNU_SOURCE
вводит объявления функций getline()
и getdelim()
. В противном случае они неявно объявлены как возвращающие int
. Для объявления возвращаемого типа ssize_t
нужен файл
. (ssize_t
является «знаковым size_t
». Он предназначен для такого же использования, что и size_t
, но в местах, где может понадобиться использование также и отрицательных значений.)
Обе функции управляют для вас динамической памятью, гарантируя, что буфер, содержащий входную строку, достаточно большой для размещения всей строки. Их отличие друг от друга в том, что getline()
читает до символа конца строки, a getdelim()
использует в качестве разделителя символ, предоставленный пользователем. Общие аргументы следующие:
char **lineptr