Search code examples
cbufferingfread

Buffered reading from stdin using fread in C


I am trying to efficiently read from the stdin by using setvbuf in `_IOFBF~ mode. I am new to buffering. I am looking for working examples.

The input begins with two integers (n,k). The next n lines of input contain 1 integer. The aim is to print how many integers are divisible by k.

#define BUFSIZE 32
int main(){
  int n, k, tmp, ans=0, i, j;
  char buf[BUFSIZE+1] = {'0'};
  setvbuf(stdin, (char*)NULL, _IONBF, 0);
  scanf("%d%d\n", &n, &k);
  while(n>0 && fread(buf, (size_t)1, (size_t)BUFSIZE, stdin)){
    i=0; j=0;
    while(n>0 && sscanf(buf+j, "%d%n", &tmp, &i)){
    //printf("tmp %d - scan %d\n",tmp,i); //for debugging
      if(tmp%k==0)  ++ans;
      j += i; //increment the position where sscanf should read from
      --n;
    }
  }
  printf("%d", ans);
  return 0;
}

The problem is if number is at the boundary, the buffer buf will read 23 from 2354\n, when it should have either read 2354 (which it cannot) or nothing at all.

How can I solve this issue?


Edit
Resolved now (with analysis).

Edit
Complete Problem Specification


Solution

  • Version 1 : Using getchar_unlocked as suggested by R Samuel Klatchko (see comments)

    #define BUFSIZE 32*1024
    int main(){
      int lines, number=0, dividend, ans=0;
      char c;
      setvbuf(stdin, (char*)NULL, _IOFBF, 0);// full buffering mode
      scanf("%d%d\n", &lines, ÷nd);
      while(lines>0){
        c = getchar_unlocked();
        //parse the number using characters
        //each number is on a separate line
        if(c=='\n'){
          if(number % dividend == 0)    ans += 1;
          lines -= 1;
          number = 0;
        }
        else
          number = c - '0' + 10*number;
      }
    
      printf("%d are divisible by %d \n", ans, dividend);
      return 0;
    }

    Version 2: Using fread to read a block and parsing number from it.

    #define BUFSIZE 32*1024
    int main(){
    int lines, number=0, dividend, ans=0, i, chars_read;
    char buf[BUFSIZE+1] = {0}; //initialise all elements to 0
    scanf("%d%d\n",&lines, &dividend);
    
    while((chars_read = fread(buf, 1, BUFSIZE, stdin)) > 0){
      //read the chars from buf
      for(i=0; i < chars_read; i++){
        //parse the number using characters
        //each number is on a separate line
        if(buf[i] != '\n')
          number = buf[i] - '0' + 10*number;
        else{
          if(number%dividend==0)    ans += 1;
          lines -= 1;
          number = 0;
        }       
      }
    
    if(lines==0)  break;
    }
    
    printf("%d are divisible by %d \n", ans, dividend);
    return 0;
    }
    

    Results: (10 million numbers tested for divisibility by 11)

    Run 1: ( Version 1 without setvbuf ) 0.782 secs
    Run 2: ( Version 1 with setvbuf ) 0.684 secs
    Run 3: ( Version 2 ) 0.534

    P.S. - Every run compiled with GCC using -O1 flag