如何在输入格式错误的情况下正确使用带循环的sscanf?
我试图从stdin读取堆栈数据结构的命令,有效的命令是“push[number]”和“pop”,下面是我的代码:如何在输入格式错误的情况下正确使用带循环的sscanf?,c,stdin,C,Stdin,我试图从stdin读取堆栈数据结构的命令,有效的命令是“push[number]”和“pop”,下面是我的代码: while(getline(&input, &len, stdin) > 0){ while ((n = sscanf(input,"%64s%d%n",cmd,&num,&offset)) > 0){ if (n == 1){ if (!strcmp("pop",cmd)){ pop(&am
while(getline(&input, &len, stdin) > 0){
while ((n = sscanf(input,"%64s%d%n",cmd,&num,&offset)) > 0){
if (n == 1){
if (!strcmp("pop",cmd)){
pop(&head);
} else if (!strcmp("push",cmd)){
//Doing something
} else if (isNumeric(cmd) && need_num){
push(&head, num);
} else{
//error
}
}
else if (n == 2){
if (!strcmp("push",cmd)){
push(&head, num);
} else {
//error
}
}
else {
//error
}
input += offset;
}
}
当然,这个程序有很多缺陷,因为我不熟悉sscanf和循环。第一个问题是,如果我在一行中读入一系列命令,例如:
push 1 push 2 pop push 3
它实际上会导致错误,因为推后有数字,而pop后没有数字,这样,“pop”命令的这行代码就错了:
但我不知道如何解决这个问题。
另一个问题是,如果我假设将“push[number]”命令拆分为两行是可以接受的:
push 5 pop push
4
我不知道除了我所做的以外,还有什么更简单的方法来决定这一行是否以“推”结束,下面这一行是否以数字开始:
else if (!strcmp("push",cmd)){
//Doing something
} else if (isNumeric(cmd) && need_num){
push(&head, num);
}
任何帮助都将不胜感激 如果大小不变,可以在
字符**
或字符选项卡[][]
中使用“
作为分隔符拆分行
然后,您将检查您的
选项卡[i]
是否是一个数字,然后根据需要使用它,或者使用一个命令,如果后面跟着(选项卡[i+1])
一个数字,则将是«推»,否则是«弹出»。您可以在字符**
或字符选项卡[]中使用作为分隔符拆分行
如果大小不变
然后你会检查你的tab[i]
是否是一个数字,然后根据你的需要使用它,或者一个命令,如果后面跟着(tab[i+1])
一个数字,就会是«推»,否则就是«弹出»。好吧,在你的使用中没有任何明显的错误,但是有一些微妙的错误导致了你的问题
您面临的主要问题是,在转换字符串和整数之后,只使用一个偏移量。在“pop”
的情况下,%d
在格式字符串中达到%n
之前发生匹配失败,导致n
保持未设置状态(保留最后设置的值——在这种情况下导致偏移量的增量过大)
相反,您需要在格式字符串中使用两个这样的检查,例如:
while ((rtn = sscanf (input, "%63s %n%d %n",
cmd, &off1, &num, &off2)) > 0) {
这样,如果读取了“pop”
,则在off1
中有适当的偏移量;如果读取了“push num”
,则在off2
中有适当的偏移量。(每个%n
之前的附加空格是可选的(但建议使用)。同时使用%s
和%d
会消耗前导空格,但最好养成考虑前导空格的习惯,因为%[…]
或%c
不会消耗前导空格
在一个简短的示例中,您可以执行以下类似操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCMD 64 /* max characters for command */
int main (void) {
char *buf = NULL; /* buffer for getline */
size_t n = 0; /* alloc size (0 getline decides) */
ssize_t nchr = 0; /* getline returns (no. of chars read */
while ((nchr = getline (&buf, &n, stdin)) > 0) { /* read each line */
char cmd[MAXCMD] = "", /* buffer for command */
*input = buf; /* pointer to advance */
int num = 0, /* number to push */
off1 = 0, /* offset if single conversion */
off2 = 0, /* offset if double conversion */
rtn = 0; /* sscanf return */
while ((rtn = sscanf (input, "%63s %n%d %n",
cmd, &off1, &num, &off2)) > 0) {
switch (rtn) { /* switch on sscanf return */
case 1: /* handle "pop" case */
if (strcmp (cmd, "pop") == 0) {
printf ("pop\n");
input += off1; /* set offset based on off1 */
}
else
fprintf (stderr, "error: invalid single cmd '%s'.\n",
cmd);
break;
case 2: /* handle "push num" case */
if (strcmp (cmd, "push") == 0) {
printf ("push %d\n", num);
input += off2; /* set offset based on off2 */
}
else
fprintf (stderr, "error: invalid single cmd '%s'.\n",
cmd);
break;
default:
fprintf (stderr, "error: invalid input.\n");
break;
}
}
}
free (buf); /* free memory allocated by getline */
return 0;
}
仔细检查一下,如果您还有任何问题,请告诉我。您的使用中没有任何明显的错误,但是有一些细微的错误导致了您的问题
您面临的主要问题是在转换字符串和整数后只取一个偏移量。在“pop”
的情况下,%d
在您的格式字符串达到%n
之前发生匹配失败,导致n
保持未设置(保留最后一个设定值——在这种情况下,会导致偏移量的增量过大)
相反,您需要在格式字符串中使用两个这样的检查,例如:
while ((rtn = sscanf (input, "%63s %n%d %n",
cmd, &off1, &num, &off2)) > 0) {
这样,如果读取了“pop”
,则在off1
中有一个适当的偏移量;如果读取了“push num”
,则在off2
中有一个适当的偏移量(每个%n
之前的附加空格是可选的(但建议)。同时使用了%s
和%d
前导空格,但最好养成考虑前导空格的习惯,因为%[…]
或%c
不使用前导空格
在一个简短的示例中,您可以执行以下类似操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCMD 64 /* max characters for command */
int main (void) {
char *buf = NULL; /* buffer for getline */
size_t n = 0; /* alloc size (0 getline decides) */
ssize_t nchr = 0; /* getline returns (no. of chars read */
while ((nchr = getline (&buf, &n, stdin)) > 0) { /* read each line */
char cmd[MAXCMD] = "", /* buffer for command */
*input = buf; /* pointer to advance */
int num = 0, /* number to push */
off1 = 0, /* offset if single conversion */
off2 = 0, /* offset if double conversion */
rtn = 0; /* sscanf return */
while ((rtn = sscanf (input, "%63s %n%d %n",
cmd, &off1, &num, &off2)) > 0) {
switch (rtn) { /* switch on sscanf return */
case 1: /* handle "pop" case */
if (strcmp (cmd, "pop") == 0) {
printf ("pop\n");
input += off1; /* set offset based on off1 */
}
else
fprintf (stderr, "error: invalid single cmd '%s'.\n",
cmd);
break;
case 2: /* handle "push num" case */
if (strcmp (cmd, "push") == 0) {
printf ("push %d\n", num);
input += off2; /* set offset based on off2 */
}
else
fprintf (stderr, "error: invalid single cmd '%s'.\n",
cmd);
break;
default:
fprintf (stderr, "error: invalid input.\n");
break;
}
}
}
free (buf); /* free memory allocated by getline */
return 0;
}
仔细检查一下,如果您还有任何问题,请告诉我。您为什么要按现在的方式进行输入?您可以轻松地将输入分为两部分-a)使用sscanf读取命令内容,b)如果命令为“推送”使用scanf读取一个数字,否则我就明白了,但是,考虑到我使用的古怪函数,可以做些什么来让它工作呢?谢谢!(不要忘记在调用getline
和之间设置偏移量=0;
,而使用sscanf
循环)。否则,您的sscanf
或if
或offset
逻辑没有明显的问题。您有什么理由想按现在的方式进行输入吗?您可以轻松地将输入分为两部分-a)使用sscanf读取命令是什么,b)如果命令是“push”使用scanf读取一个数字,否则我就明白了,但是,考虑到我使用的古怪函数,可以做些什么来让它工作呢?非常感谢。(不要忘记设置offset=0;
在调用getline
和使用sscanf
循环时的之间)。否则,您的sscanf
或if
或offset
逻辑就不会有明显问题。谢谢!那很有帮助!谢谢那很有帮助!