简体   繁体   中英

Reading From Stdin Twice in C

    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;
    }

Here is the part of my code, and my question is(as you can see):

I'm trying to read stdin's content twice, but after the getLineCount function, it stays at the EOF and I can't read it again in fill function.

Im taking stdin from the user with this command in Linux;

$./output < text_file.txt

Is there any way to roll back stdin to starting character? If not, how can I fix this problem?

Thanks.

You can use rewind(stdin) to set the stream back to the start of file, but be aware that it is not guaranteed to work, especially if the stream is a pipe, a terminal or a device.

Your allocation scheme is incorrect: you could compute the size of the file and then allocate that many bytes, but your current (char*)calloc(lineNum * 18,sizeof(int)); allocates 18 times the size of type int for each line. Some files with short lines will fit in this array while others will invoke undefined behavior.

Note that c must be defined as int for c = fgetc(stdin); to properly store all values including the EOF special value.

Don't use rewind .

You can, of course, save the data you read from stdin (potentially in a file if it's too large for main memory) and operate on that.

Another possibility is this:

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);
    }
  }
}

You inverse control, such that no longer your functions are "pulling data out of" stdin, but rather the data (characters) are "pushed to" them. Note that this can lead to callback hell, and in C you sacrifice a good portion of type safety (as well as code clarity .. no first class functions / closures ... sigh).

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;
}

As already noted, for your particular example, you should consider a completely different approach: If possible compute the required size beforehand. If you exceed that size (which you should always test for), then use realloc in order to get a larger chunk of memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM