以下代码设置从stdin读取的最大行大小。我不是硬编码特定的行长度,而是可以灵活地处理任何缓冲区长度。什么是允许处理任何规模的好策略?
如果这些策略复杂得多,是否有办法至少保证getline
不会溢出?谢谢。
#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;
}
答案 0 :(得分:7)
您可以getline
为您分配内存(这是使用non-standard getline
function over the standard fgets
function的全部要点)。从getline
手册页:
如果
*lineptr
为NULL
,则getline()
将分配缓冲区进行存储 该行,应该由用户程序释放。 (*n
中的值 被忽略了。)或者,在调用
getline()
之前,*lineptr
可以包含指针 到malloc
- 分配的缓冲区*n
字节大小。如果缓冲区不是 大到足以保持该行,getline()
使用realloc
调整其大小, 根据需要更新*lineptr
和*n
。
所以你可以这样做:
line = NULL;
while (getline(&line, &size, stdin))
{
// ... Do stuff with `line`...
}
free(line);
(或者按原样保留您的代码,因为getline
会为您调整分配的缓冲区大小。)
答案 1 :(得分:2)
这是我一直在使用的代码--Fgetstr(FILE *,const char *)。它大约使每个realloc的缓冲区大小加倍,并且不会在失败的malloc / realloc上崩溃。调用如:char * text = Fgetstr(stdin,“\ n”);或者其他什么。
库getdelim()函数类似,虽然我的可能会更老。 getline和getdelim上的联机帮助页没有详细说明如果malloc和realloc在我的系统上失败会发生什么,并且只提到可能的错误EINVAL(没有ENOMEM)。因此,面对内存耗尽的行为可能未定义getline / getdelim。
另外,正如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;
}