簡體   English   中英

從沒有最大緩沖區長度的C中的stdin讀取

[英]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手冊頁:

如果*lineptrNULL ,則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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM