程序在使用scanf("%c",&yn)等待用户输入时没有等待。

14
这是我写的一个用于练习在C语言中使用文件的基本程序代码。我试图检测输出文件是否已经存在,如果存在,我想要询问用户是否要覆盖它。这就是为什么我首先使用fopen(outfilename,"r");打开outfilename文件,而不是使用fopen(outfilename,"w");。
它可以检测文件不存在的情况,但如果文件存在,则会执行printf("Output file already exists, overwrite (y/n):");语句,但完全忽略scanf("%c",&yn);语句!
程序末尾的printf读取"yn=0",如果文件不存在,只读取"yn=",如果文件存在。有人能帮我吗?
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <string.h>

int main(void) {
    FILE *inf;
    FILE *outf;
    char filename[21],outfilename[21];
    char yn='0';

    printf("Please enter an input filename: ");
    scanf("%s",&filename);

    printf("Please enter an output filename: ");    
    scanf("%s",&outfilename);

    /* Open file for reading */
    inf=fopen (filename,"r");
    outf=fopen(outfilename,"r");

    /*check that input file exists*/
    if (inf!=NULL) {

        /*check that the output file doesn't already exist*/
        if (outf==NULL){
            fclose(outf);
            /*if it doesn't already exist create file by opening in "write" mode*/
            outf=fopen(outfilename,"w");
        } else {
            /*If the file does exist, give the option to overwrite or not*/
            printf("Output file already exists, overwrite (y/n):");
            scanf("%c",&yn);
        }
    }
    printf("\n yn=%c \n",yn);
    return 0;
}

2
如果 outf == NULL,不要执行 fclose(outf)。你不能关闭一开始就打开失败的文件。 - Staven
我不确定,所以我只是把它添加进去了!我意识到这不是很好的做法! - user1083734
5个回答

45
printf("Please enter an output filename: ");    
scanf("%s",&outfilename);

当您输入第二个字符串并按下 ENTER 键时,字符串和字符将被放置在输入缓冲区中,它们分别是:输入的字符串和换行符。字符串将被 scanf 消耗,但换行符仍然留在输入缓冲区中。

此外,

scanf("%c",&yn);

你接下来用于读取字符的scanf会读取/消耗掉换行符,从而不会等待用户输入。

解决方法是通过使用以下方式消耗额外的换行符:

scanf(" %c", &yn);
      ^^^   <------------Note the space

或者使用 getchar()

你可能想要查看我在这里的答案,详细地逐步解释了这个问题。


我确实是个新手,但我理解第二个scanf语句将"\nfile.txt"读取并存储到char类型的outfilename[21]中,而第三个scanf语句将剩余的"\n"存储到yn变量中,这个"\n"是在我输入outfilename后留在输入缓冲区中的。感谢您的帮助,干杯! - user1083734

1

使用

scanf("%20s",&filename);

请记住,stdin是行缓冲的,在Linux上遵循tty规则。

如果您想要更详细的控制,可以使用GNU readlinencurses


这与手头的问题有什么关系? - AProgrammer
使用readline将读取整行文本,具有编辑功能,这对于读取文件名和yn等内容非常相关... - Basile Starynkevitch
以下关于 tty 的 URL 链接与该问题非常相关。 它包含了许多解释(尤其是历史方面),解释了为什么在终端内从 stdin 读取数据如此复杂... - Basile Starynkevitch
难道不应该是 scanf("%20s",filename); 吗? - Jean-François Fabre

1

我发现处理这个问题的更好方法是在这里解释

它建议使用另一种处理输入的方式,并且解释得非常清楚。

我总是使用这个函数来获取用户输入。


char * read_line (char * buf, size_t length) {
    /**** Copyright de home.datacomm.ch/t_wolf/tw/c/getting_input.html#skip
    Read at most 'length'-1 characters from the file 'f' into
    'buf' and zero-terminate this character sequence. If the
    line contains more characters, discard the rest.
    */
    char *p;
    if ((p = fgets (buf, length, stdin))) {
        size_t last = strlen (buf) - 1;
        if (buf[last] == '\n') {
            /**** Discard the trailing newline */
            buf[last] = '\0';
        } else {
            /**** There's no newline in the buffer, therefore there must be
            more characters on that line: discard them!
            */
            fscanf (stdin, "%*[^\n]");
            /**** And also discard the newline... */
            (void) fgetc (stdin);
        } /* end if */
    } /* end if */
    return p;
} /* end read_line */

旧答案

我用以下规则解决了这类问题:

// first I get what I want.
c = getchar();
// but after any user input I clear the input buffer
// until the \n character:
while (getchar() != '\n');
// this also discard any extra (unexpected) character.

如果您在任何输入后执行此操作,那么不应该有问题。


0

scanf("%s", ...) 会在输入中保留终止行的 \n。这不会对下一个 scanf("%s", ...) 造成问题,因为它会跳过空格。但是 scanf("%c", ...) 不会跳过空格,因此你会读取到 \n

顺便说一句,如果你在文件名中加入空格(%s 不会读取它们),或者输入太长的名称(%s 没有输入长度限制),你可能会遇到其他问题。

解决你抱怨的问题的一个方法(但不是另一个问题)是使用 scanf(" %c", ...)(看到 %c 前面的空格了吗?scanf 的使用有点棘手),它会从跳过空格开始。


0
scanf("%s",&filename);

同时也要移除 &

scanf.c:13: 警告:格式“%s”期望类型为“char ”,但参数2的类型为“char ()[20u]”


我不确定我理解你的回答。 - user1083734

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接