Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在输入格式错误的情况下正确使用带循环的sscanf?_C_Stdin - Fatal编程技术网

如何在输入格式错误的情况下正确使用带循环的sscanf?

如何在输入格式错误的情况下正确使用带循环的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

我试图从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(&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
逻辑就不会有明显问题。谢谢!那很有帮助!谢谢那很有帮助!