[英]Read from stdin in C without max buffer length
以下代碼設置從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;
}
你可以讓getline
為你分配內存(這是使用非標准getline
函數而不是標准fgets
函數的全部要點)。 從獲取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
會為您調整分配的緩沖區大小。)
這是我一直在使用的代碼--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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.