繁体   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