由於需要可靠地檢測兩個underlength和超長線,並重新同步你輸入之後或者,它可能比較容易編寫使用getc()
讀取數據的功能。
你的標準功能選項包括:
fgets()
—將無法讀取數據太多,但你必須確定它是否有一個換行符(這將被包含在輸入)和處理閱讀長度過長的行時重新同步(不是非常困難)。
fread()
—將讀取正確的長度,並且如果您認爲長度過長和長度過短的行將是極少出現的情況,那麼這將是一個不錯的選擇。出現錯誤後的重新同步不是微不足道的,特別是如果出現相鄰的錯誤行。
getline()
— POSIX 2008.分配足夠的內存用於它讀取的行的長度,如果你只是要放棄長度過長的行,這是有點浪費。
因爲它們不合適,你最終會寫自己的。
現在測試的代碼。 (在第一個if
需要修復,通過Dave診斷出來,問題是我最初寫了反相條件(if ((c = getc(fp)) != EOF && c != '\n')
),然後在我將邏輯反轉後導致分心,導致條件「不完全倒置」。)
這個關鍵部分是兩個while循環。
第一次while循環讀取到行尾,存儲數據和計數字符—正常操作。如果該行長度正確,則在讀取換行符時循環將被中斷。請注意<=
的條件;如果你考慮linelen == 1
時的循環,你會發現<=
在這裏是正確的,儘管<
比較平常。如果線路短路,則count
將指示該線路。
while 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, sizeof(line), '\0');
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>>
$
@gbulmer'fgets' does not NOT ** discard the newline。 – Dave 2012-03-31 16:29:37
@Dave - 感謝您發現。非常容易混淆:-(我猜我在考慮gets()(這更難以使用,因爲它不需要緩衝區長度)我將刪除以保存混淆 – gbulmer 2012-03-31 16:38:56
@JonathanLeffler'c == EOF && c!=' \ n''?第二部分永遠不會失敗 – Dave 2012-03-31 16:47:45