Program doesn't wait for user input with scanf("%c",&yn);
Asked Answered
M

5

14

This is the basic code to a program I am writing to practise using files in C. I am trying to detect whether the output file already exists and if it does exist I want to ask the user if they would like to overwrite it or not. This is the reason that I have first opened the outfilename file in with fopen(outfilename,"r"); as opposed to fopen(outfilename,"w");.

It detects the case of the file not existing, however, if it does exist it executes the printf("Output file already exists, overwrite (y/n):"); statement but completely ignores the scanf("%c",&yn); statement!

The printf at the end of the program reads "yn=0" if the file doesn't exist and just "yn=" if it does exist. Can anybody help me?

#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;
}
Miler answered 11/12, 2011 at 14:17 Comment(2)
Don't fclose(outf) if outf == NULL. You can't close a file you failed to open in the first place.Unciform
i wasnt sure so i just added it in! not very good pracice i realise!Miler
L
46
printf("Please enter an output filename: ");    
scanf("%s",&outfilename);

When you enter the second string and hit the ENTER key, a string and a character are placed in the input buffer, they are namely: the entered string and the newline character.The string gets consumed by the scanf but the newline remains in the input buffer.

Further,

scanf("%c",&yn);

Your next scanf for reading the character just reads/consumes the newline and hence never waits for user input.

Solution is to consume the extra newline by using:

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

Or by using getchar()

You may want to check out my answer here for a detailed step by step explanation of the problem.

Lapland answered 11/12, 2011 at 14:22 Comment(1)
definitely, I am new to all of this but I understand that the second scanf reads and stores "\nfile.txt" to char outfilename[21] and that the 3rd scanf statement stores the remaining "\n" to char yn that was in the input buffer after I inputted the outfilename. Cheers for your helpMiler
I
1

Use

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

and remember that stdin is line buffered and on Linux is following a tty discipline

You could use GNU readline or ncurses if you want more detailed control.

Irresolvable answered 11/12, 2011 at 14:25 Comment(4)
How is that related to the problem at hand?Periodontal
Using readline will read a whole line, with editing abilities, which is relevant for reading e.g. the filename and the yn...Irresolvable
And following the URL link about tty is very relevant to the question. It contains a lot of explanations (notably historical) which explains why reading from stdin inside a terminal is so complex....Irresolvable
wouldn't it be scanf("%20s",filename); ?All
O
1

The better way to handle this problem I found is explained here.

It recomends to use an alternative way of handle input and is very well explained.

I use always this function to get user input.


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 */

Old Answer

I fixed this sort of problems with this rule:

// 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.

If you make this after any input, there should be not problem.

Obstacle answered 13/4, 2012 at 0:12 Comment(0)
P
0

scanf("%s", ...) leaves the \n terminating the line in the input. It isn't causing a problem for the next one as scanf("%s", ...) starts by skipping whites. scanf("%c", ...) doesn't and thus you read the \n.

BTW You'll probably meet other problems is you put spaces in your file name (%s doesn't read them) and if you enter too long names (%s has no input length limitations).

One solution for the problem you complained (but not the other one) is to use scanf(" %c", ...) (see the space before %c? scanf is tricky to use) which starts by skipping white spaces.

Periodontal answered 11/12, 2011 at 14:28 Comment(0)
H
0
scanf("%s",&filename);

also remove the &

scanf.c:13: warning: format '%s' expects type 'char ', but argument 2 has type 'char ()[20u]'

Hundredth answered 11/12, 2011 at 14:32 Comment(1)
i'm not sure i understand your answerMiler

© 2022 - 2024 — McMap. All rights reserved.