fgets()替换 [英] fgets() replacement
问题描述
大家好,
这个小组最近有一个帖子讨论了fgets()的
缺点。我决定尝试使用fgetc()和realloc()来为fgets()写一个
替换来读取一行
任意长度。我知道这个小组中更好的程序员可以写一个更强大的功能,但不管怎么说,这是我的镜头。
我会很感激人们的评论我的fget_line()代码如下
(包括用法示例)。任何建设性的批评欢迎
逻辑,设计,风格等等。谢谢。
Paul
/ * fget_line():一个读取任意长度输入行的函数。
*
*参数:
*''in'' - 需要数据的输入流。
*''buf'' - 指向char的指针的地址。读取结果
*将在fget_line返回后包含在此缓冲区中。
* *** CALLER必须释放此指针***
*''sz'' - 调用者可以提供行长度的估计值
*读入。如果此参数为0,则fget_line()使用
*默认值。
*''validate'' - 用户提供的回调函数,用于验证每个输入字符的
*。这个参数可能是NULL,其中
*表示没有输入验证。
*
* RETURN值:
* fget_line()成功:返回读取的字节数
* realloc()相关失败:返回-1(下面#dede''dd为ERROR_MEMORY)
*非法输入:返回-2(下面#dede''d为ERROR_ILLEGAL_CHAR)
* /
#include< stdio.h>
#include< stdlib.h>
#include< string.h>
#include< ctype.h>
#include< errno.h>
#ifndef USER_DIALOG_H / *如果我不使用它作为我的
*''user_dialog''实用程序的一部分。
* /
#define LINE_LEN 80
#define DELIMITER''\ n''
#定义ERROR_MEMORY(-1)
#define ERROR_ILLEGAL_CHAR(-2)
#else
#include" user_dialog.h"
#endif
int fget_line(FILE * in,char ** buf,size_t sz,int(* validate)(int))
{
int n_bytes = 0; / *读取的总字节数或错误标志* /
size_t n_alloc = 0; / *分配的字节数* /
unsigned int mult = 1;
char * tmp,* local_buffer = NULL;
int read_in;
* buf = NULL;
if(0 == sz)sz = LINE_LEN;
read_in = fgetc(in))!= DELIMITER&& read_in!= EOF){
if(0 == n_alloc){
n_alloc = sz * mult + n_bytes + 1;
tmp = realloc(local_buffer,n_alloc);
if(NULL!= tmp){
local_buffer = tmp;
mult ++;
}
else {
local_buffer [n_bytes] = ''\''';
* buf = local_buffer;
返回ERROR_MEMORY;
}
}
if(NULL!= validate){
if(0!= validate(read_in)){
local_buffer [n_bytes ++ ] = read_in;
n_alloc--;
}
else {
local_buffer [n_bytes] ='' \0'';
* buf = local_buffer;
返回ERROR_ILL EGAL_CHAR;
}
}
}
local_buffer [n_bytes] = ''\ 0'';
/ *修剪多余的内存(如果有的话)* /
if(n_alloc> (size_t)n_bytes){
tmp = realloc(local_buffer,n_bytes);
if(NULL!= tmp){
local_buffer = tmp ;
}
}
local_buffer [n_bytes] =''\''';
* buf = local_buffer;
返回n_bytes;
}
/ *用法示例* /
int main(无效)
{
char * line = NULL;
int ret_value;
size_t len;
fputs("输入一个字符串:",stdout);
fflush(stdout);
ret_value = fget_line(stdin,& line,0,isalnum);
len = strlen(line);
fprintf(stdout, " fget_line()返回%d \ nstrlen()返回%d bytes \ n",
ret_value,len);
fprintf(stdout," String是:\"%s \" \ n",line);
free(line);
退出(EXIT_SUCCESS);
}
-
保罗D. Boyle
bo***@laue.chem.ncsu.edu
北卡罗来纳州立大学
http://www.xray.ncsu.edu
" Paul D. Boyle" <博*** @ laue.chem.ncsu.edu>写了大家好,
这个小组最近有一个帖子谈到了fgets()的缺点。我决定尝试使用fgetc()和realloc()来写一个替换fgets()来替换
任意长度的行。
为什么不看一下CB Falconer's" ggets()"
< http://cbfalconer.home.att.net>
>
或发送电子邮件至
Chuck F(cb********@yahoo.com)
你觉得你的做事方式更好吗?
Malcolm< ma ***** @ 55bank.freeserve.co.uk>写道:
:" Paul D. Boyle" <博*** @ laue.chem.ncsu.edu>写了
:>大家好,
:>
:>这个小组最近有一个帖子谈到了
:> fgets()的缺点。我决定尝试写一个
:>使用fgetc()和realloc()替换fgets()来读取一行
:>任意长度。
:>
:为什么不看一下CB Falconer's" ggets()"?
我做了,但我想尝试使用
fgetc()和realloc()来做它(主要是为了它)。
:你觉得你的做事方式更好吗?
我不认为这是更好的事情。我写了一个函数来完成
我认为会成为一个安全有用的函数的东西,我想要其他人对我所做的事情的看法。特别是在fget_line()中,
我提供了一种进行输入验证的方法。这是一个好的和有用的
设计决定吗?
Paul
-
Paul D. Boyle
bo***@laue.chem.ncsu.edu >
北卡罗来纳州立大学
http://www.xray.ncsu .edu
Paul D. Boyle< bo *** @ laue.chem.ncsu.edu>写道:
:if(NULL!= validate){
:if(0!= validate(read_in)){
:local_buffer [ n_bytes ++] = read_in;
:n_alloc--;
:}
:else {
:local_buffer [ n_bytes] =''\''';
:* buf = local_buffer;
:返回ERROR_ILLEGAL_CHAR;
:}
:}
:
:}
:local_buffer [n_bytes] =''\'0' ';
当然,我必须在*发布到
comp.lang.c之后发现一点(?)*。 (哎呀)。我错过了一个''else''块来覆盖案例
其中''validate''函数指针为NULL。上面的代码应该是:
if(NULL!= validate){
if(0!= validate(read_in)){
local_buffer [n_bytes ++] = read_in;
n_alloc--;
}
else {
local_buffer [n_bytes] =''\''';
* buf = local_buffer;
返回ERROR_ILLEGAL_CHAR;
}
}
else {
local_buffer [n_bytes ++] = read_in;
n_alloc--;
}
}
local_buffer [n_bytes] =''\ 0'';
/ *等...... * /
保罗
-
Paul D. Boyle
< a href =mailto:bo *** @ laue.chem.ncsu.edu> bo *** @ laue.chem.ncsu.edu
北卡罗来纳州立大学/> http://www.xray.ncsu.edu
Hi all,
There was a recent thread in this group which talked about the
shortcomings of fgets(). I decided to try my hand at writing a
replacement for fgets() using fgetc() and realloc() to read a line of
arbitrary length. I know that the better programmers in this group could
write a more robust function, but here is my shot at it anyway.
I would appreciate people''s comments on my fget_line() code below
(usage example included). Any constructive criticism welcome regarding
logic, design, style, etc. Thanks.
Paul
/* fget_line(): a function to read a line of input of arbitrary length.
*
* Arguments:
* ''in'' -- the input stream from which data is wanted.
* ''buf'' -- the address of a pointer to char. The read in results
* will be contained in this buffer after the fget_line returns.
* *** THE CALLER MUST FREE THIS POINTER ***
* ''sz'' -- the caller can supply an estimate of the length of line to be
* read in. If this argument is 0, then fget_line() uses a
* default.
* ''validate'' -- a user supplied callback function which is used to validate
* each input character. This argument may be NULL in which
* case no input validation is done.
*
* RETURN values:
* fget_line() on success: returns the number of bytes read
* realloc() related failure: returns -1 (#define''d below as ERROR_MEMORY)
* illegal input: returns -2 (#define''d below as ERROR_ILLEGAL_CHAR)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#ifndef USER_DIALOG_H /* if I am not using this as part of my
* ''user_dialog'' utilities.
*/
#define LINE_LEN 80
#define DELIMITER ''\n''
#define ERROR_MEMORY (-1)
#define ERROR_ILLEGAL_CHAR (-2)
#else
#include "user_dialog.h"
#endif
int fget_line( FILE *in, char **buf, size_t sz, int (*validate)(int) )
{
int n_bytes = 0; /* total number of bytes read or error flag */
size_t n_alloc = 0; /* number of bytes allocated */
unsigned int mult = 1;
char *tmp, *local_buffer = NULL;
int read_in;
*buf = NULL;
if( 0 == sz ) sz = LINE_LEN;
while( (read_in = fgetc( in )) != DELIMITER && read_in != EOF ) {
if( 0 == n_alloc ) {
n_alloc = sz * mult + n_bytes + 1;
tmp = realloc( local_buffer, n_alloc );
if ( NULL != tmp ) {
local_buffer = tmp;
mult++;
}
else {
local_buffer[n_bytes] = ''\0'';
*buf = local_buffer;
return ERROR_MEMORY;
}
}
if( NULL != validate ) {
if( 0 != validate( read_in ) ) {
local_buffer[n_bytes++] = read_in;
n_alloc--;
}
else {
local_buffer[n_bytes] = ''\0'';
*buf = local_buffer;
return ERROR_ILLEGAL_CHAR;
}
}
}
local_buffer[n_bytes] = ''\0'';
/* trim excess memory if any */
if( n_alloc > (size_t)n_bytes ) {
tmp = realloc( local_buffer, n_bytes );
if( NULL != tmp ) {
local_buffer = tmp;
}
}
local_buffer[n_bytes] = ''\0'';
*buf = local_buffer;
return n_bytes;
}
/* usage example */
int main( void )
{
char *line = NULL;
int ret_value;
size_t len;
fputs( "Enter a string: ", stdout );
fflush( stdout );
ret_value = fget_line( stdin, &line, 0, isalnum );
len = strlen( line );
fprintf( stdout, "fget_line() returned %d\nstrlen() returns %d bytes\n",
ret_value, len );
fprintf( stdout, "String is: \"%s\"\n", line );
free( line );
exit( EXIT_SUCCESS );
}
--
Paul D. Boyle
bo***@laue.chem.ncsu.edu
North Carolina State University
http://www.xray.ncsu.edu
"Paul D. Boyle" <bo***@laue.chem.ncsu.edu> wroteHi all,
There was a recent thread in this group which talked about the
shortcomings of fgets(). I decided to try my hand at writing a
replacement for fgets() using fgetc() and realloc() to read a line of
arbitrary length.
Why not look a CB Falconer''s "ggets()"?
<http://cbfalconer.home.att.net>
or email him on
Chuck F (cb********@yahoo.com)
Do you think your way of doing things is better?
Malcolm <ma*****@55bank.freeserve.co.uk> wrote:
: "Paul D. Boyle" <bo***@laue.chem.ncsu.edu> wrote
:> Hi all,
:>
:> There was a recent thread in this group which talked about the
:> shortcomings of fgets(). I decided to try my hand at writing a
:> replacement for fgets() using fgetc() and realloc() to read a line of
:> arbitrary length.
:>
: Why not look a CB Falconer''s "ggets()"?
I did, but I wanted to try doing it (mostly for the heck of it) using
fgetc() and realloc().
: Do you think your way of doing things is better?
I don''t see it as a matter of better. I wrote a function which did the
things I thought would make a safe and useful function, and I wanted
other people''s opinion of what I had done. In particular, in fget_line(),
I provided a way to do some input validation. Was that a good and useful
design decision?
Paul
--
Paul D. Boyle
bo***@laue.chem.ncsu.edu
North Carolina State University
http://www.xray.ncsu.edu
Paul D. Boyle <bo***@laue.chem.ncsu.edu> wrote:
: if( NULL != validate ) {
: if( 0 != validate( read_in ) ) {
: local_buffer[n_bytes++] = read_in;
: n_alloc--;
: }
: else {
: local_buffer[n_bytes] = ''\0'';
: *buf = local_buffer;
: return ERROR_ILLEGAL_CHAR;
: }
: }
:
: }
: local_buffer[n_bytes] = ''\0'';
Naturally, I have to discover a little(?) *after* I post to
comp.lang.c. (grrr). I am missing an ''else'' block to cover the case
where the ''validate'' function pointer is NULL. The above code should be:
if( NULL != validate ) {
if( 0 != validate( read_in ) ) {
local_buffer[n_bytes++] = read_in;
n_alloc--;
}
else {
local_buffer[n_bytes] = ''\0'';
*buf = local_buffer;
return ERROR_ILLEGAL_CHAR;
}
}
else {
local_buffer[n_bytes++] = read_in;
n_alloc--;
}
}
local_buffer[n_bytes] = ''\0'';
/* and so on ... */
Paul
--
Paul D. Boyle
bo***@laue.chem.ncsu.edu
North Carolina State University
http://www.xray.ncsu.edu
这篇关于fgets()替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!