Linux программирование в примерах
Обратите внимание, что не всегда подходит использование такой оболочки. Если вы сами хотите обработать ошибки, не следует использовать оболочку. С другой стороны, если нехватка памяти всегда является фатальной ошибкой, такая оболочка вполне удобна.
97 if (ferror(ebuf->fp))98 pfatal_with_name(ebuf->floc.filenm);99100 /* Если обнаружено несколько строк, возвратить их число.101 Если не несколько, но _что-то_ нашли, значит, прочитана102 последняя строка файла без завершающего символа конца103 строки; вернуть 1. Если ничего не прочитано, это EOF;104 возвратить -1. */105 return nlines ? nlines : p == ebuf->bufstart ? -1 : 1;106 }В заключение, функция
проверяет ошибки ввода/вывода, а затем возвращает описательное значение. Функцияreadline()(строка 98) не возвращается. [44]pfatal_with_name()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Обе функции управляют для вас динамической памятью, гарантируя, что буфер, содержащий входную строку, достаточно большой для размещения всей строки. Их отличие друг от друга в том, что
читает до символа конца строки, agetline()использует в качестве разделителя символ, предоставленный пользователем. Общие аргументы следующие:getdelim()char **lineptrУказатель на
указатель для адреса динамически выделенного буфера. Чтобыchar*сделала всю работу, он должен быть инициализированgetline(). В противном случае, он должен указывать на область памяти, выделенную с помощьюNULL.malloc()size_t *nУказатель на размер буфера. Если вы выделяете свой собственный буфер,
должно содержать размер буфера. Обе функции обновляют*nновым значением размера буфера, если они его изменяют.*nFILE* 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 llliiiiiiiiiiiiiiiiiiinnnnnnnnnnnnnnnnnnnneeeeeeeeee3.2.2. Копирование строк:
strdup()Одной чрезвычайно типичной операцией является выделение памяти для копирования строки. Это настолько типично, что многие программисты предусматривают для нее простую функцию вместо использования внутритекстового кодирования, и часто эта функция называется
:strdup()#include <string.h>/* strdup --- выделить память с malloc() и скопировать строку */char *strdup(const char *str) {size_t len;char *copy;len = strlen(str) + 1;/* включить место для завершающего '\0' */copy = malloc(len);if (copy != NULL) strcpy(copy, str);