使用特殊情况更新矩阵

时间:2018-06-10 19:37:59

标签: c

我正在尝试编写一个获取矩阵9x9的函数,并根据用户的输入更新它,并遵循以下规则:

  1. 有效数字介于1和9之间(零无效)。
  2. 在获得scanf之前,我必须使用EOF
  3. 输入有数字和符号。有效输入是一对带有符号或EOF或空格的两位数字。超过两位数的字符串无效。例如(123%不是有效但12%有效)。
  4. 示例:

    输入:10 33%55^21 $123%

    输出:

    0     0     0     0     0     0     0     0     0
    1     0     0     0     0     0     0     0     0
    0     0     1     0     0     0     0     0     0
    0     0     0     0     0     0     0     0     0
    0     0     0     0     1     0     0     0     0
    0     0     0     0     0     0     0     0     0
    0     0     0     0     0     0     0     0     0
    0     0     0     0     0     0     0     0     0
    0     0     0     0     0     0     0     0     0
    

    说明:10123无效。 335521有效,因此我们会将1放入224410

    我试图做的事情:

    void updateMarix(int matrix[][9]) {
        int digits = 0, one_previous, two_previous;
        char input;
        while (scanf("%c", &input) != EOF) {
            if(isValidDigit(input)) {
                digits++;
                if(digits == 1) {
                    two_previous = input - '0' - 1;
                    continue;
                } else if(digits == 2){
                    one_previous = input - '0' -1;
                    continue;
                }
            } else if(digits == 2) {
                matrix[two_previous][one_previous]++;
            }
            digits = 0; // reset
        }
    }
    

    大多数测试都以成功结束,但其中一些测试失败了。我认为这是因为我没有处理最后一个输入(例如,如果它以22结尾,它不会更新它,因为我的实现,更新是在下一次迭代时符号作为输入)。

    这有更好的实施吗?我的代码变得混乱而且不干净。

    *修改:它应忽略无效输入且a3b不计数,a03b也不算,但a13b计为13这意味着我们应该增加matrix[0][2]中的数字。

    编辑2:@JonathanLeffler menationed FSM所以我试图创建一个:

    enter image description here

    虽然它没有处理1234(无效数字)或123(也无效)的情况。最类似的事情是创建一个从second numbersymbol的箭头(但它不是真的,因为只有1234%12 12才有效。

2 个答案:

答案 0 :(得分:1)

我认为您的FSM需要4个州加上最终状态:

  1. 读取零位数(D0)。
  2. 读取一位数字(D1)。
  3. 读取两位数字(D2)。
  4. 数字无效,但不再需要错误报告(DI)。
  5. 也有4种不同的输入:

    1. 数字1-9。
    2. 数字0。
    3. 其他。
    4. EOF。
    5. 我在每种状态下都使用了一个开启状态和if / else代码,但它会导致一些冗长的代码。 OTOH,我相信它能正确处理输入。

      /*
      ** FSM
      ** States: 0 digits (D0), 1 digit (D1), 2 digits (D2), digits invalid (DI)
      ** Inputs: digit 1-9 (D), digit 0 (0), other (O), EOF.
      ** Action: S - save, E - error, I - ignore, P - print
      ** Body of FSM encodes "action;state"
      **
      ** State    D0      D1      D2      DI
      ** Input
      **     D    S;D1    S;D2    E;D2    I;DI
      **     O    I;D0    E;D0    P;D0    I;D0
      **     0    E;D2    E;D2    E;D2    I;DI
      **   EOF    I;end   E;end   P;end   I;end
      */
      
      #include <assert.h>
      #include <ctype.h>
      #include <stdio.h>
      
      enum State { D0, D1, D2, DI };
      enum Input { Digit, Zero, Other, End };
      
      static int debug = 0;
      
      static enum Input input(int *rv)
      {
          int c = getchar();
          if (debug)
              printf("Input: %c\n", (c == EOF) ? 'X' : c);
          *rv = c;
          if (c == EOF)
              return End;
          if (isdigit(c))
          {
              *rv = c - '0';
              return (c == '0') ? Zero : Digit;
          }
          return Other;
      }
      
      static void updateMatrix(int matrix[9][9])
      {
          char pair[2] = { 0, 0 };
          enum State state = D0;
      
          int c;
          enum Input value;
          while ((value = input(&c)) != End)
          {
              switch (state)
              {
              case D0:
                  if (value == Digit)
                  {
                      pair[0] = c;
                      state = D1;
                  }
                  else if (value == Zero)
                  {
                      fprintf(stderr, "Received zero digit - invalid\n");
                      state = DI;
                  }
                  else
                  {
                      assert(value == Other);
                  }
                  break;
      
              case D1:
                  if (value == Digit)
                  {
                      pair[1] = c;
                      state = D2;
                  }
                  else if (value == Zero)
                  {
                      fprintf(stderr, "Received zero digit - invalid\n");
                      state = DI;
                  }
                  else
                  {
                      assert(value == Other);
                      fprintf(stderr, "Received one digit where two expected\n");
                      state = D0;
                  }
                  break;
      
              case D2:
                  if (value == Digit)
                  {
                      fprintf(stderr, "Received more than two digits where two were expected\n");
                      state = DI;
                  }
                  else if (value == Zero)
                  {
                      fprintf(stderr, "Received zero digit - invalid\n");
                      state = DI;
                  }
                  else
                  {
                      assert(value == Other);
                      printf("Valid number %d%d\n", pair[0], pair[1]);
                      matrix[pair[0]-1][pair[1]-1] = 1;
                      state = D0;
                  }
                  break;
      
              case DI:
                  if (value == Other)
                      state = D0;
                  break;
              }
          }
      
          if (state == D2)
          {
              printf("Valid number %d%d\n", pair[0], pair[1]);
              matrix[pair[0]-1][pair[1]-1] = 1;
          }
          else if (state == D1)
              fprintf(stderr, "Received one digit where two expected\n");
      }
      
      static void dump_matrix(const char *tag, int matrix[9][9])
      {
          printf("%s:\n", tag);
          for (int i = 0; i < 9; i++)
          {
              for (int j = 0; j < 9; j++)
                  printf("%4d", matrix[i][j]);
              putchar('\n');
          }
      }
      
      int main(void)
      {
          int matrix[9][9] = { 0 };
      
          updateMatrix(matrix);
          dump_matrix("After input", matrix);
      
          return 0;
      }
      

      在测试输入上,它产生输出:

      Received zero digit - invalid
      Valid number 33
      Valid number 55
      Valid number 21
      Received more than two digits where two were expected
      After input:
         0   0   0   0   0   0   0   0   0
         1   0   0   0   0   0   0   0   0
         0   0   1   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   1   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
      

      在大多数无效的输入文件中:

      123345132
      bbbb12cccc1dddd011dd
      

      它产生输出:

      Received more than two digits where two were expected
      Valid number 12
      Received one digit where two expected
      Received zero digit - invalid
      After input:
         0   1   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
         0   0   0   0   0   0   0   0   0
      

      您可以(轻松地)证明错误消息可以提供更多信息(识别错误字符,可能还有先前的有效数字),但它只会为每个无效序列生成一条错误消息,这是有益的。

答案 1 :(得分:0)

您可以将fgets()sscanf()strpbrk()组合使用。

将输入行读入字符数组str,并指向指向正在处理的ptr中字符串部分的指针str

首先,设置一个循环来逐行读取输入。 fgets()会在NULL上返回EOF

for(; fgets(str, sizeof(str), stdin); )
{
    ...
    ...
    ...
}

fgets()也会在尾随换行符中读取。您可以将其删除,如

str[strlen(str)-1]='\0';

现在在上面的循环中,使用另一个循环来处理str中的输入行,如

    for(ptr=str; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
    {
        sscanf(ptr, "%d%n", &n, &len);

        if(n>10 && n<100)
        {
             //accepted
             printf("\n%d", n);
             arr[n/10][n%10]=1;
        }
        //else discarded
    }

strpbrk()的原型是

char *strpbrk(const char *s1, const char *s2);

并返回指向s1中第一个字符的指针,该字符是字符串s2中的一个字符。如果没有匹配项,则返回NULL

因此,我们希望查看str中仍需要使用strpbrk(ptr, "0123456789")处理的第一个数字部分。

此数字部分通过n读入sscanf()。如果此数字在您需要的范围内,您可以接受它。

%n格式说明符用于查找使用sscanf()扫描的字符数,以便找到ptr必须更新的值。请参阅this帖子。

一个地方的数字将为n%10,而数十位的数字将为n/10,因为您需要的数字是一个2​​位数字。

您可以设置表示矩阵的数组,如

arr[n/10][n%10]=1;

所以整个事情看起来像

char *ptr, str[50];
for(; fgets(str, sizeof(str), stdin); )
{
    for(ptr=str, str[strlen(str)-1]=0; (ptr=strpbrk(ptr, "0123456789"))!=NULL; ptr+=len)
    {
        sscanf(ptr, "%d%n", &n, &len);
        if(n>10 && n<100)
        {
             printf("\n%d", n);
             arr[n/10][n%10]=1;
        }
    }
}

对于您的输入10 33%55^21 $123%,输出将为

33
55
21

10123将被丢弃。