我正在尝试编写一个获取矩阵9x9
的函数,并根据用户的输入更新它,并遵循以下规则:
scanf
之前,我必须使用EOF
。EOF
或空格的两位数字。超过两位数的字符串无效。例如(123%
不是有效但12%
有效)。示例:
输入: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
说明:10
和123
无效。 33
,55
和21
有效,因此我们会将1
放入22
,44
和10
。
我试图做的事情:
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所以我试图创建一个:
虽然它没有处理1234
(无效数字)或123
(也无效)的情况。最类似的事情是创建一个从second number
到symbol
的箭头(但它不是真的,因为只有1234%12
12
才有效。
答案 0 :(得分:1)
我认为您的FSM需要4个州加上最终状态:
也有4种不同的输入:
我在每种状态下都使用了一个开启状态和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
,10
和123
将被丢弃。