我在想程序的问题是什么。键入quit时无法退出程序。
这是我所拥有的:

#include <stdio.h>
#include <string.h>

int main(void) {

    char string[200];

    printf("Enter a bunch of words: ");
    do
    {
        scanf("%[^\n]c", string);


    }while(strcmp(string,"quit")!=0);

    return 0;
}

最佳答案

您的两个最大问题是使用scanf困扰新C程序员的两个最常见问题:



让我们首先解决第一件事:

scanf("%[^\n]c", string);

您的格式字符串"%[^\n]c"使用字符类格式说明符"%[...]"来读取string的文本。然后是"c"-仅与您输入字符串末尾的文字'c'相匹配。由于"%[^\n]"将读取不是'\n'的所有字符,仅留下'\n'进行读取,而这与'c'不匹配,因此不会发生这种情况。

此外,"%[...]"说明符与"%c"说明符一起不占用前导空格('\n'为空格)。因此,将'\n'保留为未读状态时,您对stdin的下一次调用将失败,因为scanf不会读取"%[^\n]",并且它与'\n'不匹配,从而导致匹配失败,因此'c'仍未读入'\n'中,事情很快就失去了控制。

要解决所有问题,您需要记住上面的stdin,并使用field-width修饰符保护(2.)的数组边界,然后应阅读并保存提取的字符并将其放在string中以保存到中,以确保完整读取了输入行-如果没有,则是您的责任,负责在尝试下一次读取之前删除string 中剩余的所有多余字符。

对于初学者,您可以使用格式适当受限的字符串,该字符串开头应包含stdin,这将导致space放弃所有前导空格,例如
    " %199[^\n]%c"

请注意,上面将保存最终字符,将进行两次转换,因此您将需要一个字符变量来处理最终转换说明符的结果,例如
    do {
        char c;     /* final character read */
        int retn;   /* variable to save scanf return */
        /* prompt */
        fputs ("Enter a bunch of words ('quit' exits): ", stdout);
        /* read saving scanf return */
        retn = scanf (" %199[^\n]%c", string, &c);

(注意:,提示已在scanf循环内移动了)

接下来的负责每次检查do {...} while (..);返回。您必须处理三个条件
  • scanf用户通过按Ctrl + d(或在Windows上Ctrl + z)生成手动(return == EOF)来取消输入;
  • EOF,必须处理匹配或输入失败,并且必须考虑输入缓冲区中可能剩余的每个字符。 (通常,您将在输入缓冲区中向前扫描,直到找到(return < expected No. of conversions)'\n'丢弃任何剩余的多余字符,请参见示例中的EOF函数);和
  • empty_stdin()表示读取成功-然后由您检查输入是否满足任何其他条件(例如正整数,正浮点等)。

  • 综上所述,您可以使用(return == expected No. of conversions)循环阅读并寻找scanf作为提示退出的关键字,如下所示:
        do {
            char c;     /* final character read */
            int retn;   /* variable to save scanf return */
            /* prompt */
            fputs ("Enter a bunch of words ('quit' exits): ", stdout);
            /* read saving scanf return */
            retn = scanf (" %199[^\n]%c", string, &c);
            if (retn == EOF) {      /* check the return against EOF */
                fputs ("(user canceled input)\n", stderr);
                return 0;
            }
            else if (retn < 2) {    /* checking both string and c read */
                fputs ("input failure.\n", stderr);
                empty_stdin();
            }
            else if (c != '\n') {   /* check c is '\n', else string too long */
                fprintf (stderr, "warning: input exceeds %d characters.\n",
                        MAXC - 1);
                empty_stdin();
            }
            else    /* good input, output string */
                printf ("string: %s\n", string);
    
        } while (strcmp (string,"quit") != 0);
    

    最后,请勿在代码中使用幻数("quit"是幻数)。相反,如果您需要一个常量,请使用200一个(或多个)。您必须对数字进行硬编码的唯一地方是例如#define字段宽度修饰符-不能使用变量,宏或命名常量。这是该规则的一个例外。同样,请勿对文件名或路径进行硬编码。所有函数都带有参数,甚至是scanf,都将所需的信息传递给您的程序。

    综上所述,您可以执行以下操作:
    #include <stdio.h>
    #include <string.h>
    
    #define MAXC 200    /* constant - maximum characters in string */
    
    void empty_stdin (void)
    {
        int c = getchar();
        while (c != EOF && c != '\n')
            c = getchar();
    }
    
    int main (void) {
    
        char string[MAXC];    /* use constants for array bounds */
    
        do {
            char c;     /* final character read */
            int retn;   /* variable to save scanf return */
            /* prompt */
            fputs ("Enter a bunch of words ('quit' exits): ", stdout);
            /* read saving scanf return */
            retn = scanf (" %199[^\n]%c", string, &c);
            if (retn == EOF) {      /* check the return against EOF */
                fputs ("(user canceled input)\n", stderr);
                return 0;
            }
            else if (retn < 2) {    /* checking both string and c read */
                fputs ("input failure.\n", stderr);
                empty_stdin();
            }
            else if (c != '\n') {   /* check c is '\n', else string too long */
                fprintf (stderr, "warning: input exceeds %d characters.\n",
                        MAXC - 1);
                empty_stdin();
            }
            else    /* good input, output string */
                printf ("string: %s\n", string);
    
        } while (strcmp (string,"quit") != 0);
    
        return 0;
    }
    

    示例使用/输出
    $ ./bin/scanf_string_quit
    Enter a bunch of words ('quit' exits): Hello
    string: Hello
    Enter a bunch of words ('quit' exits): My dog has fleas and my cat has none.
    string: My dog has fleas and my cat has none.
    Enter a bunch of words ('quit' exits): quit
    string: quit
    

    使用Ctrl + d(或在windoze中为Ctrl + z)生成手动main():
    $ ./bin/scanf_string_quit
    Enter a bunch of words ('quit' exits): Hello
    string: Hello
    Enter a bunch of words ('quit' exits): (user canceled input)
    

    EOF重置为MAXC并将字段宽度修饰符重置为20更改为scanf,您可以检查对太长的行的处理,例如第一个输入合适,第二个输入太长:
    $ ./bin/scanf_string_quit
    Enter a bunch of words ('quit' exits): my dog has fleas and my cat has none.
    warning: input exceeds 19 characters.
    Enter a bunch of words ('quit' exits): 1234567890123456789
    string: 1234567890123456789
    Enter a bunch of words ('quit' exits): 12345678901234567890
    warning: input exceeds 19 characters.
    Enter a bunch of words ('quit' exits): quit
    string: quit
    

    仔细检查一下,如果您还有其他问题,请告诉我。

    09-04 09:49
    查看更多