С объявлением void get_line (char* filename)
вы никогда не сможете использовать строку, которую вы читаете и храните вне функции get_line
, потому что вы не возвращаете указатель на строку и не передаете адрес для любой указатель, который мог бы служить для выделения и чтения видимым обратно в вызывающей функции.
Хорошая модель (показывающая тип возвращаемого значения и полезные параметры) для любой функции для считывания неизвестного количества символов в одинбуфер всегда POSIX getline
.Вы можете реализовать свои собственные, используя fgetc
из fgets
и фиксированный буфер.Эффективность способствует использованию fgets
только в той степени, в которой это минимизирует количество необходимых вызовов realloc
.(обе функции будут использовать один и тот же низкоуровневый размер входного буфера, например, см. gcc source IO_BUFSIZ
константа - которая, если я помню, теперь LIO_BUFSIZE
после недавнего изменения имени, но в основном сводится к 8192
байтовому вводу-выводубуфер в Linux и 512
байт в Windows)
Пока вы динамически выделяете исходный буфер (используя malloc
, calloc
или realloc
), вы можете непрерывно читать с фиксированным буферомиспользуя fgets
добавление символов, считанных в фиксированный буфер, к выделенной строке и проверяя, является ли последний символ '\n'
или EOF
, чтобы определить, когда вы закончите.Просто прочитайте фиксированный буфер из символов с fgets
каждой итерацией и realloc
вашей строкой по ходу, добавляя новые символы в конец.
При перераспределении всегда realloc
с использованием временного указателя .Таким образом, если вам не хватит памяти и realloc
вернет NULL
(или произойдет сбой по любой другой причине), вы не будете перезаписывать указатель на выделенный в данный момент блок, если NULL
создаст утечку памяти.
Гибкая реализация, которая изменяет размер фиксированного буфера как VLA, используя либо SZINIT
для размера буфера (если пользователь передает 0
), либо размер, предоставленный пользователем для выделения начального хранилища для line
(передается как указатель на указатель на символ), а затем перераспределяется по мере необходимости, возвращая количество символов, прочитанных при успехе, или -1
при ошибке (так же, как это делает POSIX getline
), можно сделать так:
/** fgetline, a getline replacement with fgets, using fixed buffer.
* fgetline reads from 'fp' up to including a newline (or EOF)
* allocating for 'line' as required, initially allocating 'n' bytes.
* on success, the number of characters in 'line' is returned, -1
* otherwise
*/
ssize_t fgetline (char **line, size_t *n, FILE *fp)
{
if (!line || !n || !fp) return -1;
#ifdef SZINIT
size_t szinit = SZINIT > 0 ? SZINIT : 120;
#else
size_t szinit = 120;
#endif
size_t idx = 0, /* index for *line */
maxc = *n ? *n : szinit, /* fixed buffer size */
eol = 0, /* end-of-line flag */
nc = 0; /* number of characers read */
char buf[maxc]; /* VLA to use a fixed buffer (or allocate ) */
clearerr (fp); /* prepare fp for reading */
while (fgets (buf, maxc, fp)) { /* continuall read maxc chunks */
nc = strlen (buf); /* number of characters read */
if (idx && *buf == '\n') /* if index & '\n' 1st char */
break;
if (nc && (buf[nc - 1] == '\n')) { /* test '\n' in buf */
buf[--nc] = 0; /* trim and set eol flag */
eol = 1;
}
/* always realloc with a temporary pointer */
void *tmp = realloc (*line, idx + nc + 1);
if (!tmp) /* on failure previous data remains in *line */
return idx ? (ssize_t)idx : -1;
*line = tmp; /* assign realloced block to *line */
memcpy (*line + idx, buf, nc + 1); /* append buf to line */
idx += nc; /* update index */
if (eol) /* if '\n' (eol flag set) done */
break;
}
/* if eol alone, or stream error, return -1, else length of buf */
return (feof (fp) && !nc) || ferror (fp) ? -1 : (ssize_t)idx;
}
( примечание: , поскольку nc
уже содержит текущее количество символов в buf
, memcpy
можно использовать для добавления содержимого buf
к *line
без сканирования дляокончание nul-символ еще раз) Просмотрите его и дайте мне знать, если у вас есть дополнительные вопросы.
По сути вы можете использовать его в качестве замены для POSIX getline
(хотя это будет не так эффективно, но и неплохо)