通过C中的stdin读取大型列表

时间:2015-03-19 01:54:19

标签: c list stdin bufferedreader

如果我的程序将通过stdin传入大量的数字列表,那么最有效的方法是什么呢?

我将要传入该计划的输入将采用以下格式:

3,5;6,7;8,9;11,4;; 

我需要处理输入,以便我可以使用冒号之间的数字(即我希望能够使用3和5,6和7等等)。 ;;表示它是该行的结尾。

我正在考虑使用缓冲读取器来读取整行,然后使用parseInt。

这是最有效的方法吗?

6 个答案:

答案 0 :(得分:3)

这是一个有效的解决方案 一种方法是使用strtok()并将值存储在数组中。理想情况下,动态分配。

 int main(int argc, char *argv[])
{
    int lst_size=100;
    int line_size=255;

    int lst[lst_size];
    int count=0;

    char buff[line_size];
    char * token=NULL;
    fgets (buff, line_size, stdin); //Get input

通过'使用strtok,'和';'作为代理人。

    token=strtok(buff, ";,");
    lst[count++]=atoi(token); 
    while(token=strtok(NULL, ";,")){
          lst[count++]=atoi(token);
    }

最后你需要考虑双重&#34 ;;;"通过将计数减少1,因为atoi(令牌)将为该情况返回0并将其存储在第n个索引中。你不想要的。

  count--;

}

答案 1 :(得分:2)

我在C上有点生疏,但这对你有用吗?

char[1000] remainder;
int first, second;
fp = fopen("C:\\file.txt", "r"); // Error check this, probably.
while (fgets(&remainder, 1000, fp) != null) { // Get a line.
    while (sscanf(remainder, "%d,%d;%s", first, second, remainder) != null) {
        // place first and second into a struct or something
    }
}

答案 2 :(得分:2)

您可以使用 fgets fgetc stdin 中读取内容。您也可以使用 getline() ,因为您正在从stdin读取。

读完该行后,您可以将 strtok() 与分隔符一起使用";"将字符串拆分为分号。你可以循环直到strok()为null,或者在这种情况下,&#39 ;;'。同样在C中,您应该使用 atoi() 将字符串转换为整数。

例如:

int length = 256;
char* str = (char*)malloc(length);
int err = getline(&str, &length, stdin);

答案 3 :(得分:2)

我会在命令args中读取,然后使用strtok()库方法

进行解析

http://man7.org/linux/man-pages/man3/strtok.3.html

(以上网址引用的网页甚至包含如何使用它的代码示例。)

答案 4 :(得分:2)

另一种相当优雅的方法是允许strtol通过将要读取的字符串推进到endptr返回strtol来解析输入。结合根据需要分配/重新分配的数组,您应该能够处理任何长度的行(直到内存耗尽)。下面的示例使用单个数组作为数据。如果要存储多行,每个行作为一个单独的数组,可以使用相同的方法,但从指向int的指针数组的指针开始。 (即int **numbers并分配指针,然后分配每个数组)。如果您有疑问,请告诉我们:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define NMAX 256

int main () {

    char *ln = NULL;                /* NULL forces getline to allocate  */
    size_t n = 0;                   /* max chars to read (0 - no limit) */
    ssize_t nchr = 0;               /* number of chars actually read    */
    int *numbers = NULL;            /* array to hold numbers            */
    size_t nmax = NMAX;             /* check for reallocation           */
    size_t idx = 0;                 /* numbers array index              */

    if (!(numbers = calloc (NMAX, sizeof *numbers))) {
        fprintf (stderr, "error: memory allocation failed.");
        return 1;
    }

    /* read each line from stdin - dynamicallly allocated   */
    while ((nchr = getline (&ln, &n, stdin)) != -1)
    {
        char *p = ln;       /* pointer for use with strtol  */
        char *ep = NULL;

        errno = 0;
        while (errno == 0)
        {
            /* parse/convert each number on stdin   */ 
            numbers[idx] = strtol (p, &ep, 10);
            /* note: overflow/underflow checks omitted */
            /* if valid conversion to number */
            if (errno == 0 && p != ep)
            {
                idx++;              /* increment index      */
                if (!ep) break;     /* check for end of str */
            }

            /* skip delimiters/move pointer to next digit   */
            while (*ep && (*ep <= '0' || *ep >= '9')) ep++;
            if (*ep) 
                p = ep;
            else 
                break;

            /* reallocate numbers if idx = nmax */
            if (idx == nmax)
            {
                int *tmp = realloc (numbers, 2 * nmax * sizeof *numbers);
                if (!tmp) {
                    fprintf (stderr, "Error: struct reallocation failure.\n");
                    exit (EXIT_FAILURE);
                }
                numbers = tmp;
                memset (numbers + nmax, 0, nmax * sizeof *numbers);
                nmax *= 2;
            }
        }
    }

    /* free mem allocated by getline */
    if (ln) free (ln);

    /* show values stored in array   */
    size_t i = 0;
    for (i = 0; i < idx; i++)
        printf (" numbers[%2zu]  %d\n", i, numbers[i]);

    /* free mem allocate to numbers  */
    if (numbers) free (numbers);

    return 0;
}

<强>输出

$ echo "3,5;6,7;8,9;11,4;;" | ./bin/prsistdin
 numbers[ 0]  3
 numbers[ 1]  5
 numbers[ 2]  6
 numbers[ 3]  7
 numbers[ 4]  8
 numbers[ 5]  11
 numbers[ 6]  4

也适用于将字符串存储在文件中的位置:

$ cat dat/numsemic.csv | ./bin/prsistdin
or
$ ./bin/prsistdin < dat/numsemic.csv

使用fgets而不使用size_t

需要做一些修改才能提出一个我很满意的修订版本{@ 1}}并替换getlinefgets更加灵活,为您处理空间分配,getline由您决定。 (更不用说fgets返回实际读取的字符数而无需调用getline)。

我的目标是保持阅读任何长度线以满足您的要求的能力。这或者意味着最初分配一些巨大的行缓冲区(浪费)或提出一个方案,如果它比最初分配给strlen的空间长,它将根据需要重新分配输入行缓冲区。 (这是ln做得很好的事情)。我对结果非常满意。 注意:我将重新分配代码放在函数中以保持getline合理清洁。 脚注2

看看以下代码。注意,我已经在代码中保留了main预处理程序指令,允许您使用DEBUG标志进行编译,如果您希望每次分配时都将其吐出。 [脚注1] 您可以使用以下代码编译代码:

-DDEBUG

或者如果您想要调试输出(例如将LMAX设置为gcc -Wall -Wextra -o yourexename yourfilename.c 或小于行长度),请使用以下命令:

2

如果您有任何疑问,请与我们联系:

gcc -Wall -Wextra -o yourexename yourfilename.c -DDEBUG

脚注1

单词#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define NMAX 256 #define LMAX 1024 char *realloc_char (char *sp, unsigned int *n); /* reallocate char array */ int *realloc_int (int *sp, unsigned int *n); /* reallocate int array */ char *fixshortread (FILE *fp, char **s, unsigned int *n); /* read all stdin */ int main () { char *ln = NULL; /* dynamically allocated for fgets */ int *numbers = NULL; /* array to hold numbers */ unsigned int nmax = NMAX; /* numbers check for reallocation */ unsigned int lmax = LMAX; /* ln check for reallocation */ unsigned int idx = 0; /* numbers array index */ unsigned int i = 0; /* simple counter variable */ char *nl = NULL; /* initial allocation for numbers */ if (!(numbers = calloc (NMAX, sizeof *numbers))) { fprintf (stderr, "error: memory allocation failed (numbers)."); return 1; } /* initial allocation for ln */ if (!(ln = calloc (LMAX, sizeof *ln))) { fprintf (stderr, "error: memory allocation failed (ln)."); return 1; } /* read each line from stdin - dynamicallly allocated */ while (fgets (ln, lmax, stdin) != NULL) { /* provide a fallback to read remainder of line if the line length exceeds lmax */ if (!(nl = strchr (ln, '\n'))) fixshortread (stdin, &ln, &lmax); else *nl = 0; char *p = ln; /* pointer for use with strtol */ char *ep = NULL; errno = 0; while (errno == 0) { /* parse/convert each number on stdin */ numbers[idx] = strtol (p, &ep, 10); /* note: overflow/underflow checks omitted */ /* if valid conversion to number */ if (errno == 0 && p != ep) { idx++; /* increment index */ if (!ep) break; /* check for end of str */ } /* skip delimiters/move pointer to next digit */ while (*ep && (*ep <= '0' || *ep >= '9')) ep++; if (*ep) p = ep; else break; /* reallocate numbers if idx = nmax */ if (idx == nmax) realloc_int (numbers, &nmax); } } /* free mem allocated by getline */ if (ln) free (ln); /* show values stored in array */ for (i = 0; i < idx; i++) printf (" numbers[%2u] %d\n", (unsigned int)i, numbers[i]); /* free mem allocate to numbers */ if (numbers) free (numbers); return 0; } /* reallocate character pointer memory */ char *realloc_char (char *sp, unsigned int *n) { char *tmp = realloc (sp, 2 * *n * sizeof *sp); #ifdef DEBUG printf ("\n reallocating %u to %u\n", *n, *n * 2); #endif if (!tmp) { fprintf (stderr, "Error: char pointer reallocation failure.\n"); exit (EXIT_FAILURE); } sp = tmp; memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */ *n *= 2; return sp; } /* reallocate integer pointer memory */ int *realloc_int (int *sp, unsigned int *n) { int *tmp = realloc (sp, 2 * *n * sizeof *sp); #ifdef DEBUG printf ("\n reallocating %u to %u\n", *n, *n * 2); #endif if (!tmp) { fprintf (stderr, "Error: int pointer reallocation failure.\n"); exit (EXIT_FAILURE); } sp = tmp; memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */ *n *= 2; return sp; } /* if fgets fails to read entire line, fix short read */ char *fixshortread (FILE *fp, char **s, unsigned int *n) { unsigned int i = 0; int c = 0; i = *n - 1; realloc_char (*s, n); do { c = fgetc (fp); (*s)[i] = c; i++; if (i == *n) realloc_char (*s, n); } while (c != '\n' && c != EOF); (*s)[i-1] = 0; return *s; } 的选择没有什么特别之处(可能是DEBUG等等),要带走的一点是,如果你想有条件地包含/排除代码,你可以只需使用预处理器标志即可。您只需添加DOG即可将-Dflagname传递给编译器。

脚注2

您可以将重新分配函数组合到单个flagname函数中,该函数接受void指针作为其参数以及要重新分配的类型的void*,并返回指向重新分配空间的void指针 - - 但我们将把它留给以后。

答案 5 :(得分:1)

getchar_unlocked()正是您要找的。

以下是代码:

#include <stdio.h>

inline int fastRead_int(int * x)
{
  register int c = getchar_unlocked();
  *x = 0;

  // clean stuff in front of + look for EOF
  for(; ((c<48 || c>57) && c != EOF); c = getchar_unlocked());
  if(c == EOF)
    return 0;

  // build int
  for(; c>47 && c<58 ; c = getchar_unlocked()) {
    *x = (*x<<1) + (*x<<3) + c - 48;
  }
  return 1;
}

int main()
{
  int x;
  while(fastRead_int(&x))
    printf("%d ",x);
  return 0;
}

对于输入1;2;2;;3;;4;;;;;54;;;;,上面的代码会生成1 2 2 3 4 54

我保证,此解决方案比本主题中介绍的其他解决方案快得多。它不仅使用getchar_unlocked(),还使用registerinline以及乘以10个棘手的方式:(*x<<1) + (*x<<3)

祝你找到更好的解决方案,祝你好运。