Поскольку вам необходимо надежно обнаруживать линии как нижней, так и сверхдлинной длины, а также синхронизировать ввод после каждой из них, вероятно, проще всего написать функцию, которая использует getc()
для чтения данных.
Ваши стандартные функции включают в себя:
fgets()
& mdash; не будет читать слишком много данных, но вам нужно будет определить, получил ли он новую строку (которая будет включена во входные данные), и иметь дело с ресинхронизацией при чтении слишком длинной строки (не очень сложно).
fread()
& mdash; будет читать точно правильную длину, и будет хорошим выбором, если вы думаете, что линии длины и длины будут исчезающе редкими случаями. Ресинхронизация после ошибки совсем не тривиальна, особенно если вы получаете соседние ошибочные строки.
getline()
& mdash; из POSIX 2008. Выделяет достаточное количество памяти для длины строки, которую он читает, что немного расточительно, если вы просто собираетесь отбрасывать слишком длинные строки.
Поскольку они не подходят, вы заканчиваете тем, что пишете свои собственные.
Теперь проверенный код. (Исправление было необходимо в первом if
, как было установлено Дейвом . Проблема заключалась в том, что я изначально написал обратное условие (if ((c = getc(fp)) != EOF && c != '\n')
), а затем отвлекся после того, как перевернул логику, что привело к ' неполная инверсия 'условия.)
Ключевыми частями этого цикла являются два цикла while.
Первый цикл while читает до конца строки, сохраняя данные и считая символы & mdash; нормальная работа. Если строка имеет правильную длину, цикл будет прерван при чтении новой строки. Обратите внимание на условие <=
; если учесть цикл, когда linelen == 1
, вы увидите, что <=
здесь правильный, хотя <
является более обычным. Если линия короткая, count
укажет, что.
Второй цикл while имеет дело с слишком длинными строками, считывая до конца строки и отбрасывая результаты. Он использует x
вместо c
, поскольку в операторе возврата требуется c
.
/*
@(#)File: $RCSfile: rdfixlen.c,v $
@(#)Version: $Revision: 1.2 $
@(#)Last changed: $Date: 2012/04/01 00:15:43 $
@(#)Purpose: Read fixed-length line
@(#)Author: J Leffler
*/
/* Inspired by https://stackoverflow.com/questions/9957006 */
#include <stdio.h>
#include <assert.h>
extern int read_fixed_length_line(FILE *fp, char *buffer, int linelen);
/* Read line of fixed length linelen characters followed by newline. */
/* Buffer must have room for trailing NUL (newline is not included). */
/* Returns length of line that was read (excluding newline), or EOF. */
int read_fixed_length_line(FILE *fp, char *buffer, int linelen)
{
int count = 0;
int c;
assert(fp != 0 && buffer != 0 && linelen > 0);
while (count < linelen)
{
if ((c = getc(fp)) == EOF || c == '\n')
break;
buffer[count++] = c;
}
buffer[count] = '\0';
if (c != EOF && c != '\n')
{
/* Gobble overlength characters on line */
int x;
while ((x = getc(fp)) != EOF && x != '\n')
count++;
}
return((c == EOF) ? EOF : count);
}
#ifdef TEST
#include "posixver.h"
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
enum { MAXLINELEN = 10 };
int actlen;
char line[16];
int lineno = 0;
memset(line, '\0', sizeof(line));
while ((actlen = read_fixed_length_line(stdin, line, MAXLINELEN)) != EOF)
{
lineno++;
if (actlen != MAXLINELEN)
{
if (actlen > MAXLINELEN)
printf("%2d:L: length %2d <<%s>>\n", lineno, actlen, line);
else
printf("%2d:S: length %2d <<%s>>\n", lineno, actlen, line);
}
else
printf("%2d:R: length %2d <<%s>>\n", lineno, actlen, line);
assert(line[MAXLINELEN-0] == '\0');
assert(line[MAXLINELEN+1] == '\0');
}
return 0;
}
#endif /* TEST */
Данные испытаний и вывод
$ cat xxx
abcdefghij
a
Abcdefghij
ab
aBcdefghij
abc
abCdefghij
abcd
abcDefghij
abcde
abcdEfghij
abcdef
abcdeFghij
abcdefg
abcdefGhij
abcdefgh
abcdefgHij
abcdefghi
abcdefghIj
abcdefghiJ
abcdefghiJ1
AbcdefghiJ
abcdefghiJ12
aBcdefghiJ
abcdefghiJ123
$ ./rdfixlen < xxx
1:S: length 0 <<>>
2:R: length 10 <<abcdefghij>>
3:S: length 1 <<a>>
4:R: length 10 <<Abcdefghij>>
5:S: length 2 <<ab>>
6:R: length 10 <<aBcdefghij>>
7:S: length 3 <<abc>>
8:R: length 10 <<abCdefghij>>
9:S: length 4 <<abcd>>
10:R: length 10 <<abcDefghij>>
11:S: length 5 <<abcde>>
12:R: length 10 <<abcdEfghij>>
13:S: length 6 <<abcdef>>
14:R: length 10 <<abcdeFghij>>
15:S: length 7 <<abcdefg>>
16:R: length 10 <<abcdefGhij>>
17:S: length 8 <<abcdefgh>>
18:R: length 10 <<abcdefgHij>>
19:S: length 9 <<abcdefghi>>
20:R: length 10 <<abcdefghIj>>
21:R: length 10 <<abcdefghiJ>>
22:L: length 11 <<abcdefghiJ>>
23:R: length 10 <<AbcdefghiJ>>
24:L: length 12 <<abcdefghiJ>>
25:R: length 10 <<aBcdefghiJ>>
26:L: length 13 <<abcdefghiJ>>
$