[英]Read from stdin in C without max buffer length
The following code sets a maximum line size read from stdin. 以下代码设置从stdin读取的最大行大小。 I'd rather not hard-code a specific line length, and have the flexibility to handle any buffer length.
我宁愿不对特定的行长度进行硬编码,并且可以灵活地处理任何缓冲区长度。 What are good strategies to allow processing of any size?
什么是允许处理任何尺寸的好策略?
If these strategies are much more complex, is there a way to at least guarantee that getline
will not overflow? 如果这些策略复杂得多,有没有办法至少保证
getline
不会溢出? Thanks. 谢谢。
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define P 20
int main()
{
size_t size = 1920;
char *line;
// record row; /* structure to store fields */
char tokens[P][41];
int p;
char delims[] = ","; /* ", |" */
char *result = NULL;
line = ( char * ) malloc( size + 1 );
while( getline(&line, &size, stdin) != -1 )
{
/* chomp */
line[strlen(line)-1] = '\0';
/* load char array */
result = strtok( line , delims );
p = 0;
while( result != NULL && ( p < P ) )
{
strcpy( tokens[p++] , result );
result = strtok( NULL, delims );
}
if (p != P)
{
fprintf(stderr,"Wrong number of input fields.\nFormat: ID,x1, ... ,x%d\n",P);
exit(-1);
}
/* load record ( atol, atof etc... , skipped for brevity ) and work with record */
return 0;
}
You can have getline
allocate memory for you (which is the whole point of using the non-standard getline
function over the standard fgets
function ). 你可以让
getline
为你分配内存(这是使用非标准getline
函数而不是标准fgets
函数的全部要点)。 From the getline
manual page: 从获取
getline
手册页:
If
*lineptr
isNULL
, thengetline()
will allocate a buffer for storing the line, which should be freed by the user program.如果
*lineptr
为NULL
,则getline()
将分配用于存储该行的缓冲区,该缓冲区应由用户程序释放。 (The value in*n
is ignored.)(
*n
的值被忽略。)Alternatively, before calling
getline()
,*lineptr
can contain a pointer to amalloc
-allocated buffer*n
bytes in size.或者,在调用
getline()
之前,*lineptr
可以包含指向malloc
分配的缓冲区*n
字节大小的指针。 If the buffer is not large enough to hold the line,getline()
resizes it withrealloc
, updating*lineptr
and*n
as necessary.如果缓冲区不足以容纳该行,则
getline()
使用realloc
调整其大小,根据需要更新*lineptr
和*n
。
So you can do: 所以你可以这样做:
line = NULL;
while (getline(&line, &size, stdin))
{
// ... Do stuff with `line`...
}
free(line);
(Or leave your code as-is, since getline
will resize your allocated buffer for you.) (或保持代码原样,因为
getline
会为您调整分配的缓冲区大小。)
Here's the code I've been using - Fgetstr(FILE*, const char*). 这是我一直在使用的代码--Fgetstr(FILE *,const char *)。 It roughly doubles the buffer size for each realloc, and won't crash on a failed malloc/realloc.
它大约使每个realloc的缓冲区大小加倍,并且不会在失败的malloc / realloc上崩溃。 Called like: char *text = Fgetstr(stdin, "\\n");
调用如:char * text = Fgetstr(stdin,“\\ n”); or whatever.
管他呢。
The library getdelim() function is similar, although mine might be much older. 库getdelim()函数类似,虽然我的可能更老。 The manpage on getline and getdelim doesn't detail what happens if the malloc and realloc fail on my system, and only mention a possible error EINVAL (no ENOMEM).
getline和getdelim上的联机帮助页没有详细说明如果malloc和realloc在我的系统上失败会发生什么,并且只提到可能的错误EINVAL(没有ENOMEM)。 Hence, the behavior in the face of memory exhaustion may be undefined for getline/getdelim.
因此,对于getline / getdelim,面对内存耗尽的行为可能是未定义的。
Also, as starrify points out, many systems don't have getline. 此外,作为starrify指出,许多系统没有函数getline。
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#ifdef TEST
#define DEBUG
#endif
#ifdef DEBUG
#undef DEBUG
#define DEBUG(b) {b}
#else
#define DEBUG(b)
#endif
#ifdef TEST
int main (int argc, char **argv)
{
char *text = (char*)0;
char *ends = "\n";
if(argc > 1) ends = argv[1];
while(text = Fgetstr(stdin, ends))
{
puts(text);
free(text);
}
return 0;
}
#endif
/* return specifications -
*
* terminators include : ends, \0, and EOF
*
* root EOF? text? ended? stat returned value
* - - - ...
* 1 - - 1 return ""
* - 1 - ...
* 2 - 1 1 return "text"
* 3 1 - - return -null- EOF-*accepted*
* 4 1 - 1 return "" EOF-postponed
* 5 1 1 - return "text" EOF-postponed/fake-end
* 6 1 1 1 return "text" EOF-postponed/true-end
*
* on ENOMEM, return -null-
*
*/
static char *Fgetstr_R(FILE *ifp, const char *ends, unsigned int offset)
{
char *s = (char*)0; /* the crucial string to return */
unsigned int bufmax = offset; /* as large as so far */
unsigned int bufidx = 0; /* index within buffer */
char buffer[bufmax + 1]; /* on-stack allocation required */
int ended = 0; /* end character seen ? */
int eof = 0; /* e-o-f seen ? */
DEBUG(fprintf(stderr, "(%d", offset););
while(bufidx <= bufmax) /* pre-recurse - attempt to fill buffer */
{
int c = getc(ifp);
if( (ended = ( !c || (ends && strchr(ends,c)))) || (eof = (EOF==c)) )
break;
buffer[bufidx++] = (char)c;
}
/* note - the buffer *must* at least have room for the terminal \0 */
if(ended || (eof && offset)) /* root 1,2,4,6 5 */
{
unsigned int offset_max = offset + bufidx;
DEBUG(fprintf(stderr, " malloc %d", offset_max + 1););
if(s = (char*)malloc((offset_max + 1) * sizeof(char)))
s[offset_max] = '\0';
else
s = (char*)0, perror("Fgetstr_R - malloc");
}
else
{
if(eof && !offset) /* && !ended */ /* root 3 */
s = (char*)0;
else
s = Fgetstr_R(ifp, ends, offset + bufidx); /* recurse */
}
/* post-recurse */
if(s)
strncpy(&s[offset], &buffer[0], bufidx); /* cnv. idx to count */
DEBUG(fprintf(stderr, ")", offset););
return s;
}
char *Fgetstr (FILE *ifp, const char *ends)
{
register char *s = (char*)0;
DEBUG(fprintf(stderr, "Fgetstr "););
s = Fgetstr_R(ifp, ends, 0);
DEBUG(fprintf(stderr, ".\n"););
return s;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.