【问题标题】:Parse lines of integers in C解析C中的整数行
【发布时间】:2010-06-10 15:03:02
【问题描述】:

这是一个经典问题,但我找不到简单的解决方案。

我有一个输入文件,例如:

1 3 9 13 23 25 34 36 38 40 52 54 59 
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114 
2 4 9 15 23 27 34 36 63 67 76 85 86 90 93 99 108 115 
1 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113 
2 3 9 16 24 28 
2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76 

由空格分隔的不同整数行数。

我想将它们解析为一个数组,并用标记分隔每一行,比如说-1

困难在于我必须处理整数和换行符。

这是我现有的代码,它在 scanf 循环上循环(因为 scanf 不能从给定位置开始)。

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {

  if (argc != 4) {
    fprintf(stderr, "Usage: %s <data file> <nb transactions> <nb items>\n", argv[0]);
    return 1;
  }
  FILE * file;
  file = fopen (argv[1],"r");
  if (file==NULL) {
    fprintf(stderr, "Error: can not open %s\n", argv[1]);
    fclose(file);
    return 1;
  }
  int nb_trans = atoi(argv[2]);
  int nb_items = atoi(argv[3]);
  int *bdd = malloc(sizeof(int) * (nb_trans + nb_items));
  char line[1024];
  int i = 0;

  while ( fgets(line, 1024, file) ) {
    int item;
    while ( sscanf (line, "%d ", &item )){
      printf("%s %d %d\n", line, i, item);
      bdd[i++] = item;
    }
    bdd[i++] = -1;
  }

  for ( i = 0; i < nb_trans + nb_items; i++ ) {
    printf("%d ", bdd[i]);
  }
  printf("\n");
}

【问题讨论】:

  • 为什么不用多维数组?
  • 请,请,请立即停止使用 atoi()。是的,现在。将每次调用 atoi() 更改为 strtol() 并使用基数珠说十五个冰雹错误。
  • @Tim,如果您要提供建议,请至少支持推理。否则,这只是互联网上的一些随机乔:-)

标签: c parsing filehandle


【解决方案1】:

你有很多选择,但总的来说我会这样攻击它:

使用 fgets() 将输入文件作为文本文件读入 - 即作为一堆字符串。这将一直读取,直到遇到换行符或 EOF。使用字符串标记器函数扫描读取的每一行以查找空格并返回空格之前的子字符串。您现在有一个整数的字符串表示形式。如果您愿意,可以将其解析为实际的 int,或者将子字符串本身存储在数组中。如果确实将其切换为 int,则需要注意如果它变得太大,则溢出。

【讨论】:

  • 这似乎比我的回答更有效率。嗯,好久没用C了,应该多练习一下。
  • 对我来说也有一段时间了,但我还不需要太多使用 C++ 字符串的东西,所以这一切对我来说还是很新鲜的。感谢您的评论。
【解决方案2】:

将输入作为字符串读入,搜索换行符,在换行符所在的位置创建一个带有 -1 的新字符串,然后重复此操作,直到所有换行符都替换为 -1。当你这样做时,你还可以计算空格的数量,这样你就会知道声明你的数组有多大。 (不过,您可能应该在替换换行符后这样做。)

然后创建你的数组。

接下来,在循环中使用 sscanf 或其他东西来解释字符串中的整数,并将它们添加到数组中正确的位置,直到所有整数(包括 -1)都被解释完。

编辑:...这似乎与您已经在做的非常接近,根据您在我输入答案时添加到您的问题中的代码。

【讨论】:

    【解决方案3】:

    好的,我找到了解决方案,抱歉打扰了,我应该搜索更多...

    reading unknown number of integers from stdin (C)

    用这个代替我的 scanf 循环:

      while ( fgets(line, 1024, file) ) {
        int item;
        for (p = line; ; p = e) {
            item = strtol(p, &e, 10);
            if (p == e)
                break;
            bdd[i++] = item;
        }
        bdd[i++] = -1;
      }
    

    【讨论】:

    • 大声笑,看起来很像我的建议 :)
    • 是的。此解决方案中的主要信息是函数 strtol,它为您返回搜索的结束指针。
    • 再次提醒,注意整数溢出。我不确定 strol 将如何处理一个太大而无法放入长的字符串。
    • 好的,谢谢。就我而言,我确信条目不超过一个整数(实际上不超过10000),这方面没有问题
    【解决方案4】:

    这是一个完整的 C 程序,展示了如何做到这一点。它基本上使用fgets 一次读取行,然后使用sscanf 处理该行上的每个inetegr。

    它具有基本的错误检查功能,但尚未使用不良数据(非数字行)进行测试,但它应该是一个好的开始。只需将 printf 语句替换为将每个数字附加到数组的代码即可:

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    int main (void) {
        char line[1000];
        FILE *fIn;
        char *str;
        int val, num;
    
        // Open input file and process line by line.
    
        if ((fIn = fopen ("infile.txt", "r")) == NULL) {
            fprintf (stderr, "Cannot open infile.txt, errno = %d\n", errno);
            return 1;
        }
    
        while (fgets (line, sizeof (line), fIn) != NULL) {
            // Check if line was too long.
    
            if (line[strlen (line) - 1] != '\n') {
                fprintf (stderr, "Line too long: [%s...]\n", line);
                fclose (fIn);
                return 1;
            }
    
            // Oyput the line and start processing it.
    
            printf ("%s   ", line);
            str = line;
    
            // Skip white space and scan first inetegr.
    
            while (*str == ' ') str++;
    
            num = sscanf (str, "%d", &val);
    
            // Process the integer if it was there.
    
            while ((num != 0) && (num != EOF)) {
                // Print it out then skip to next.
    
                printf ("[%d] ", val);
                while ((*str != ' ') && (*str != '\0')) str++;
                while (*str == ' ') str++;
                num = sscanf (str, "%d", &val);
            }
    
            // -1 for line separator.
    
            printf ("[%d]\n", -1);
        }
    
        // Close input file and exit.
    
        fclose (fIn);
    
        return 0;
    }
    

    这是显示它正在工作的输出:

    1 3 9 13 23 25 34 36 38 40 52 54 59
       [1] [3] [9] [13] [23] [25] [34] [36] [38] [40] [52] [54] [59] [-1]
    2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114
       [2] [3] [9] [14] [23] [26] [34] [36] [39] [40] [52] [55] [59] [63] [67] [76] [85] [86] [90] [93] [99] [108] [114] [-1]
    2 4 9 15 23 27 34 36 63 67 76 85 86 90 93 99 108 115
       [2] [4] [9] [15] [23] [27] [34] [36] [63] [67] [76] [85] [86] [90] [93] [99] [108] [115] [-1]
    1 25 34 36 38 41 52 54 59 63 67 76 85 86 90 93 98 107 113
       [1] [25] [34] [36] [38] [41] [52] [54] [59] [63] [67] [76] [85] [86] [90] [93] [98] [107] [113] [-1]
    2 3 9 16 24 28
       [2] [3] [9] [16] [24] [28] [-1]
    2 3 10 14 23 26 34 36 39 41 52 55 59 63 67 76
       [2] [3] [10] [14] [23] [26] [34] [36] [39] [41] [52] [55] [59] [63] [67] [76] [-1]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 2011-04-03
      • 1970-01-01
      • 2017-08-24
      • 2010-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多