-1

Saying that the inputs(stdin) are:

6 4
0 1 1 1 1 0
1 0 0 0 0 1
1 0 0 0 0 1
0 1 1 1 1 0

In the first line, 6 and 4 are width and height respectively.

I did

fgets(buf, sizeof(buf), stdin);

if(strlen(buf) > 4 || strlen(buf) < 4)
{
    printf("Cannot decode\n");
    return 1;
}

So that if I put the number of integers that is greater than or less than 2 as for the first line(width and height), then press enter, it occurs error.

Next step is to put the rest of the inputs in 2D array, board[height][width].

What I did is:

for(i = 0; i < height; i++)
{
    for(j = 0; j < width; j++)
    {
        scanf("%d", &input);

        board[i][j] = input;
    }
}

But the problem is, the matrix needs to match the width and height.

For example, if I enter 6 and 4 as its width and height respectively, and then if I put

0 1 1 1 1 

then press enter, it needs to occur an error immediately as the number of integers and the width do not match.

scanf ignores the enter key... so how can I make the program occur an error if I put a number of integers that do not match width and height?

승기유
  • 133
  • 9
  • Why not use `scanf` to read the width and height as well? – Some programmer dude Mar 26 '18 at 07:11
  • If I enter 6 and 4 and press enter, it is fine but if I enter 1 2 3 for the first line, it should occur an error immediately after I press enter key, so I read the first line with fgets and counted the number of integers. – 승기유 Mar 26 '18 at 07:12
  • 1
    First of all, you did not "count the number of integers" in the first line, not that you show anyway. What you show is that you check the length of the string which is completely different. As for your apparent problem, you can't use `scanf` in that case for the loop. Instead read the whole line, parse it some other way (`strtok` and `strtol` perhaps?). – Some programmer dude Mar 26 '18 at 07:15
  • So what happens if I try to enter 1024 as the height and 2048 as the width? – babon Mar 26 '18 at 07:15
  • the height and width need to be in a rage from 0 to 255. I managed this problem by using if statements, but I am struggling with how to put rest of the inputs while matching with the length of width and height. – 승기유 Mar 26 '18 at 07:17
  • 5
    If you need to check that lines work, stop using `scanf()` which couldn't care less about lines. Use `fgets()` to read lines and read about [how to use `sscanf()` in a loop](https://stackoverflow.com/questions/3975236/how-to-use-sscanf-in-loops) to read the numbers on the line in turn. Note that when you read with `fgets()`, you need to test the value that it returns to be sure it succeeded. Similarly with `sscanf()`; you need to check that it was able to read a number. – Jonathan Leffler Mar 26 '18 at 07:24

1 Answers1

0

so how can I make the program occur an error if I put a number of integers that do not match width and height?

One approach could be:

1) Read a whole line into a string 2) Try to read width integers from the string

Repeat that height times.

To track the progress in the string (step 2), you can use %n in the sscanf calls to find how many chars that each call has used.

Something like:

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char *argv[])
{
  int i, j;
  int height, width;
  char buf[256];

  // Read size
  if (fgets(buf, sizeof(buf), stdin) == NULL)
  {
    printf("Illegal input\n");
    exit(1);
  }
  if (sscanf(buf, "%d %d", &width, &height) != 2)
  {
    printf("Illegal input\n");
    exit(1);
  }

  // Use VLA (note: only do this for small matrices)
  int board[height][width];

  // Read the matrix
  for (i=0; i < height; ++i)
  {
    if (fgets(buf, sizeof(buf), stdin) == NULL)
    {
      printf("Illegal input\n");
      exit(1);
    }
    int consumed = 0;
    int consumed_current;
    for (j=0; j < width; ++j)
    {
      // Scan from string offset "consumed"
      if (sscanf(buf+consumed, "%d%n", &board[i][j], &consumed_current) != 1)
      {
        printf("Illegal input\n");
        exit(1);
      }
      // Move the offset in the string
      consumed = consumed + consumed_current;
    }
  }

  // Print
  for (i=0; i < height; ++i)
  {
    for (j=0; j < width; ++j)
    {
      printf("%d ", board[i][j]);
    }
    printf("\n");
  }

  return(0);
}

Notice: This code only checks for too few data elements. If an input line contains too many elements, this code will just ignore the rest. Checking for "too many" elements can be done by verifying that the whole input string has been consumed by sscanf.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Thanks alot! I passed it by using what you wrote for me. Btw, could you please explain to me what is the role of consumed and consumed_current? – 승기유 Mar 26 '18 at 08:59
  • @승기유 The role of consumed and consumed current is to get a new starting point for each `sscanf`. So if the input string is "1 2 3" the first sscanf will look at "1 2 3" (and find 1), the second sscanf will look at " 2 3" (and find 2) and the third sscanf will look at " 3" (and find 3). So they are used for moving forward in the input string. – Support Ukraine Mar 26 '18 at 09:05
  • And could you also explain why we sscanf with buf+consumed? why do we add them up? after putting 6 and 4, then we input 0 1 1 1 1 0, what is the value for buf here? – 승기유 Mar 26 '18 at 09:19
  • @승기유 `buf+consumed` sets the starting point for each `sscanf`. `consumed_current` holds the number of chars consumed by a single `sscanf`. `consumed` holds the chars consumed by all `sscanf` done so far. Therefore we need to add `consumed_current` to `consumed` after each `sscanf` – Support Ukraine Mar 26 '18 at 09:27