The following code sets a maximum line size read from 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? 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 ). From the getline
manual page:
If
*lineptr
isNULL
, thengetline()
will allocate a buffer for storing the line, which should be freed by the user program. (The value in*n
is ignored.)Alternatively, before calling
getline()
,*lineptr
can contain a pointer to amalloc
-allocated buffer*n
bytes in size. If the buffer is not large enough to hold the line,getline()
resizes it withrealloc
, updating*lineptr
and*n
as necessary.
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.)
Here's the code I've been using - Fgetstr(FILE*, const char*). It roughly doubles the buffer size for each realloc, and won't crash on a failed malloc/realloc. Called like: char *text = Fgetstr(stdin, "\\n"); or whatever.
The library getdelim() function is similar, although mine might be much older. 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). Hence, the behavior in the face of memory exhaustion may be undefined for getline/getdelim.
Also, as starrify points out, many systems don't have 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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.