代码之家  ›  专栏  ›  技术社区  ›  anisotropic

用C语言从Stdin读取两次

  •  1
  • anisotropic  · 技术社区  · 8 年前
        int getLineCount() {
            int ret = 0;
            char c;
            while ((c = fgetc(stdin)) != EOF)
                if (c == '\n')
                    ret++;
            return ret + 1;
        }
    
        void fill(char *WORD) {
            int charIndex = 0;
            char c;
            while ((c = fgetc(stdin)) != EOF) {
               *(WORD + charIndex++) = c;
            }
        }
    
        int main() {
            int lineNum = getLineCount();
            char *WORD = (char*)calloc(lineNum * 18,sizeof(int));
    
            fill(WORD);
            return 0;
        }
    

    这是我代码的一部分,我的问题是(如你所见):

    我试着读了两次stdin的内容,但在 获取行计数 函数,它停留在EOF,我无法在中再次读取 填满 作用

    我在Linux中使用此命令从用户处获取stdin;

    $./output < text_file.txt
    

    有什么方法可以将stdin回滚到起始字符吗?如果没有,我如何解决这个问题?

    谢谢

    2 回复  |  直到 8 年前
        1
  •  1
  •   chqrlie    8 年前

    您可以使用 rewind(stdin) 将流设置回文件的开头,但要注意,它不能保证工作,尤其是当流是管道、终端或设备时。

    您的分配方案不正确:您可以计算文件的大小,然后分配那么多字节,但当前 (char*)calloc(lineNum * 18,sizeof(int)); 分配类型大小的18倍 int 每一行。一些具有短行的文件将适合此数组,而其他文件将调用未定义的行为。

    请注意 c 必须定义为 整数 对于 c = fgetc(stdin); 正确存储所有值,包括 EOF 特殊价值。

        2
  •  1
  •   Daniel Jour    8 年前

    不要使用 rewind .

    当然,您可以保存从stdin读取的数据(如果对于主内存来说太大,可能会保存在一个文件中)并对其进行操作。

    另一种可能性是:

    struct callback {
      void (*call) (char, void *);
      void * data;
    };
    
    void with_characters_from(FILE * file, struct callback const * callbacks, size_t count) {
      int c;
      while ((c = fgetc(file)) != EOF) {
        char character = c & 0xFF;
        for (size_t i = 0; i < count; ++i) {
          callbacks[i].call(character, callbacks[i].data);
        }
      }
    }
    

    您可以反向控制,这样,您的函数不再“从”stdin中提取数据,而是将数据(字符)“推送到”它们。请注意,这可能会导致回调地狱,在C中,您牺牲了很大一部分类型安全性(以及代码的清晰性……没有第一类函数/闭包……叹息)。

    A small test :

    struct counter_data {
      char const character;
      unsigned count;
    };
    
    void counter (char character, void * vptr) {
      struct counter_data * data = vptr;
      if (character == data->character) {
        ++(data->count);
      }
    }
    
    int main() {
      struct counter_data data [2] = {
        {'a', 0}, {'x', 0}};
      struct callback callbacks [2] = {
        {&counter, &(data [0])},
        {&counter, &(data [1])}};
      with_characters_from (stdin, callbacks, 2);
      printf("Counted %c %u times \n", data [0].character, data [0].count);
      printf("Counted %c %u times \n", data [1].character, data [1].count);
      return 0;
    }
    

    如前所述,对于您的特定示例,您应该考虑一种完全不同的方法:如果可能,请预先计算所需的大小。如果您超过了该尺寸(您应该始终测试该尺寸),则使用 realloc 以便获得更大的内存块。