Linux программирование в примерах - Роббинс Арнольд
Шрифт:
Интервал:
Закладка:
Обратите внимание, что не всегда подходит использование такой оболочки. Если вы сами хотите обработать ошибки, не следует использовать оболочку. С другой стороны, если нехватка памяти всегда является фатальной ошибкой, такая оболочка вполне удобна.
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 <stdio.h>
#include <sys/types.h> /* для ssize_t */
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 нужен файл <sys/types.h>. (ssize_t является «знаковым size_t». Он предназначен для такого же использования, что и size_t, но в местах, где может понадобиться использование также и отрицательных значений.)
Обе функции управляют для вас динамической памятью, гарантируя, что буфер, содержащий входную строку, достаточно большой для размещения всей строки. Их отличие друг от друга в том, что getline() читает до символа конца строки, a getdelim() использует в качестве разделителя символ, предоставленный пользователем. Общие аргументы следующие:
char **lineptr
Указатель на char* указатель для адреса динамически выделенного буфера. Чтобы getline() сделала всю работу, он должен быть инициализирован NULL. В противном случае, он должен указывать на область памяти, выделенную с помощью malloc().
size_t *n
Указатель на размер буфера. Если вы выделяете свой собственный буфер, *n должно содержать размер буфера. Обе функции обновляют *n новым значением размера буфера, если они его изменяют.
FILE* stream
Место, откуда следует получать входные символы.
По достижении конца файла или при ошибке функция возвращает -1. Строки содержат завершающий символ конца строки или разделитель (если он есть), а также завершающий нулевой байт. Использование getline() просто, как показано в ch03-getline.с:
/* ch03-getline.c --- демонстрация getline(). */
#define _GNU_SOURCE 1
#include <stdio.h>
#include <sys/types.h>
/* main - прочесть строку и отобразить ее, пока не достигнут EOF */
int main(void) {
char *line = NULL;
size_t size = 0;
ssize_t ret;
while ((ret = getline(&line, &size, stdin)) != -1)
printf("(%lu) %s", size, line);
return 0;
}
Вот эта функция в действии, показывающая размер буфера. Третья входная и выходная строки намеренно длинные, чтобы заставить getline() увеличить размер буфера:
$ <b>ch03-getline</b> /* Запустить программу */
<b>this is a line</b>
(120) this is a line
<b>And another line.</b>
(120) And another line.
<b>A llllllllllllllllloooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnngnnnggggggggggg llliiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnneeeeeeeeee</b>
(240) A llllllllllllllllloooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnngnnnggggggggggg llliiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnneeeeeeeeee
3.2.2. Копирование строк: strdup()
Одной чрезвычайно типичной операцией является выделение памяти для копирования строки. Это настолько типично, что многие программисты предусматривают для нее простую функцию вместо использования внутритекстового кодирования, и часто эта функция называется strdup():
#include <string.h>
/* strdup --- выделить память с malloc() и скопировать строку */
char *strdup(const char *str) {
size_t len;
char *copy;
len = strlen(str) + 1;
/* включить место для завершающего ' ' */
copy = malloc(len);
if (copy != NULL) strcpy(copy, str);