2

I have a problem with filling a fixed size 2D array with the fgetc() function.

My program should read only '-', '+' or '!' and the chars entered on one line must be equal to size of the columns.

Here is the problematic part of my code:

for(i = 0; i < rows; i++) {
  for(j = 0; j < cols; j++) {
    c = fgetc( stdin );
    if( (c != '-') && (c != '+') && (c != '!') ) {
      printf( "Incorrect value.\n" );
      return 1;
    }
    array[i][j] = c;
  }
  if(array[i+1][0] != '\n') {
    printf( "Incorrect value (size does not equal to columns).\n" );
    return 1;
  }
}/*---end of for---*/

Here is how I understand it:

fgetc() scans newline char ('\n') as well and puts it in the following row - which means that array[1][0] should be '\n'. If the user enter more chars than cols are set to, it will be other character than newline and program will end with an error. However this does not work.

Is there a better way to ignore newline from a stdin and check if the user did not enter more chars than specified earlier?

Magisch
  • 7,312
  • 9
  • 36
  • 52
Filip N.
  • 141
  • 1
  • 3
  • 11
  • the function: `fgetc()` only returns one keystroke. So when the user enters: `+ then the first call to `fgetc()` will return the `+`. The next call to `fgetc()` will return the key. the posted code only allows `+`, `-`, and `!` to be placed into the array, However, only a limited number of times through the `for()` loops is implemented, so every other entry in the array will be empty. Suggest, calling `fgetc()` in a loop, check if the input is an allowed value, and if not, loop again – user3629249 Dec 01 '15 at 14:37

2 Answers2

1

Test the value against '\n' and use int.

Do not save the return value from fgetc() into the char array and later test. This loses the ability to distinguish EOF from other char.

When an '\n' is expected (or EOF), that is good.

Recommend using positive logic tests as it is easier to understand

for (i = 0; i < rows; i++) {
  int c;
  for (j = 0; j < cols; j++) {
    c = fgetc( stdin );
    if (c == '-' || c == '+' || c == '!') {
      array[i][j] = c;
    } else {
      puts("Incorrect value.");
      return 1;
    }
  }
  c = fgetc( stdin );  // Read and consume the end-of-line
  if (!(c == '\n' || c == EOF)) {
    printf( "Incorrect value (size does not equal to columns).\n" );
    return 1;
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    Great! Thank you very much for your help. Now it seems that it works correctly. I just needed to remove return 1 in the first if statement and change that "ch == EOF" to "c". Thank you once again. – Filip N. Dec 01 '15 at 19:17
  • BTW `fgetc()` if fine to use. Alternative: `fgets()` for text or `fread()` for binary. Avoid `scanf()` and never use `gets()`. – chux - Reinstate Monica Dec 01 '15 at 19:23
0

I don't particularly condone the use of fgetc() but if you insist on it, I think a working version of what you want to do is below.

The key bit being, after reading a character with fgetc(), you read another to swallow the newline, and then proceed...

#include <stdio.h> 

int main() {
  int rows = 3, cols = 3; 
  int i, j;  
  char array[rows][cols]; 
  char c; 
  for(i = 0; i < rows; i++) {
    for(j = 0; j < cols; j++) {
      c = fgetc(stdin); 
      if( (c != '-') && (c != '+') && (c != '!') ) {
        printf( "Incorrect value.\n" );
        return 1;
      }
      else {
        array[i][j] = c;
        // swallow the newline 
        fgetc(stdin);   
      }
    }
  }

  // print all 
  for(i = 0; i < rows; i++) {
    for(j = 0; j < cols; j++) {
      printf("%c ", array[i][j]); 
    }
    printf("\n"); 
  }
}

EDIT

As per a below suggestion, if you want to enter all characters on one line and then hit newline, as such:

val00 val01 val02 [newline] val10 val11 val12 [newline] val20 val21 val22 [newline]

then the below will work. [Be careful not to have trailing whitespace as it may break the intended functionality]:

#include <stdio.h> 

int main() {
  int rows = 3, cols = 3; 
  int i, j;  
  char array[rows][cols]; 
  char c; 
  for(i = 0; i < rows; i++) {
    for(j = 0; j < cols; j++) {
      c = fgetc(stdin); 
      if( (c != '-') && (c != '+') && (c != '!') ) {
        printf( "Incorrect value.\n" );
        return 1;
      }
      else if (c == '\n') {
        fgetc(stdin); 
        continue;   
      }
      array[i][j] = c;
      fgetc(stdin); // swallow space
    }
  }

  // print all 
  for(i = 0; i < rows; i++) {
    for(j = 0; j < cols; j++) {
      printf("%c ", array[i][j]); 
    }
    printf("\n"); 
  }
}
Sami Farhat
  • 1,164
  • 8
  • 12
  • The newline would only be at the end of each line, so the `fgetc` to swallow the newline should be outside the inner loop (but inside the outer loop). – Klas Lindbäck Dec 01 '15 at 14:03
  • I agree this would be a neater implementation, but as far I understood he was trying to enter (0,0) newline, (0,1) newline, (0,2) newline, (1,0), newline (1,1) newline (1,2) ... – Sami Farhat Dec 01 '15 at 14:16
  • the function: `fgetc()` returns an 'int' value, not a 'char' value. so the variable `c` should be defined as 'int' – user3629249 Dec 01 '15 at 14:28
  • 1
    Unfortunately this does not work. Yes the input should be in format: (if cols == 3; rows == 3 ) --+[newline] +--[newline] !!-[newline] *end of fgetc()* Your code does not stop after reading 3 rows but continue and reads 5 rows (*I have no idea why*), then for cycle ends,and it prints array[3][3]. – Filip N. Dec 01 '15 at 19:03
  • fgetc() was the only function that came to my mind for this case (I am beginning with C). Which other function would you suggest? – Filip N. Dec 01 '15 at 19:19