0

I'm writing a program that adds line numbers to C files. I get the filenames as command line arguments but I wanted the user to have a chance to enter them if they forget to when they run the program. I ask the user to if they want to enter filenames and then they answer 'y' or 'n'. They are given five tries to answer correctly if an invalid character is entered but after five tries the program prints an error message and terminates. If the user enters an invalid character I have it print '[y/n]?' to the screen to prompt the user for those letters. If an invalid character is entered though it goes through the loop twice and prints them out side by side. Why does this happen?

Compiler.c file:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lineNumAdderHeader.h"
#include "miscellaneousHeader.h"
#include "errorCheckedFunctionsHeader.h"

int main(int argc, char *argv[]){
int i = 1;
char ch;
int answerTries = 0;
char *seperatedFilenames[argc - 1];

if (argc < 2){
    fprintf(stderr, "No files were entered for compiling.\n");

    answer: do{
        if (answerTries == 0)
            printf("Would you like to enter files for compiling [y/n]? ");
        else if (!(answerTries < 5))
             fatal("in main(). An invalid character was entered too many times.");
        else
            printf("[y/n]? ");

        ch = getchar();

        if (ch == 'n' || ch == 'N')
            exit(0);

        answerTries++;
    } while (ch != 'y' && ch != 'Y');
}
else{
    while (i < argc){
        seperatedFilenames[i - 1] = argv[i];
        i++;
    }
}

i = 0;
while (i < (argc - 1)){
    lineNumAdder(seperatedFilenames[i]);
    i++;
}
}

Fatal Funciton:

/*Displays a fatal error*/
void fatal(char *errorMessage){
/*Holds the errorMessage*/
char completedErrorMessage[strlen(errorMessage) + 17];

/*Copies the error message into completedErrorMessage*/
strcpy(completedErrorMessage, "[!!] Fatal Error ");
strcat(completedErrorMessage, errorMessage);

/*Prints the error message to the screen*/
fprintf(stderr, "%s\n", completedErrorMessage);

/*Exit the program in failure*/
exit(-1);
}
user3273091
  • 33
  • 1
  • 1
  • 6

2 Answers2

0

Your getchar() call returns one character from the standard input. When a users enters an answer, he then hits an enter/return key which translates to new line character which is part of the line that is then sent to standard input.

What you should probably do is to only check first character returned by getchar and then, in loop, read and discard all characters until you get new line character (\n). Only then, you can proceed to ask the question another time.

You should use this loop because your user may enter several characters at once. For example he may enter "yes" which will count as 4 characters.

Krzysztof Adamski
  • 2,039
  • 11
  • 14
  • The user does not have to press enter for getchar(). It reads the input immediatly after one character has been enter. There's no oppurtunity for them to enter more characters. – user3273091 Apr 06 '14 at 15:11
  • @user3273091: That depends on the type of terminal your program will run on. Most terminals I know are configured in so called "canonical" mode which, simplifying things, means that input will be sent in lines, not using single characters. You can disable this behavior using `stty -icanon`, however. So on what kind of terminal do you run your program? – Krzysztof Adamski Apr 06 '14 at 15:24
  • I run it on the bash terminal. However I would like the program to be able to be run on any OS – user3273091 Apr 06 '14 at 16:05
  • @user3273091: Bash is not a terminal, it's a shell. Terminal is a program you run your shell in. Anyway, the easiest way to figure out what is the 2nd character you get from `getchar()` is to just print enclosed with two printable characters (like for example `printf("#%c#\n", ch)`). – Krzysztof Adamski Apr 06 '14 at 16:14
  • I have been missing it because it is such a habit, but I do press enter for getchar(). It is the extra \n character. I will do what you suggested above and loop and discard all extra characters. Thank you for being patient with me on this. – user3273091 Apr 07 '14 at 21:56
-1

Try flushing the stream before completing the loop, with

fflush(stdin);

If you don't want to use this function, you could try this,

do{
    if(answerTries!=0)  //it should clear your newline char input
         getchar();
    if (answerTries == 0)
        printf("Would you like to enter files for compiling [y/n]? ");
    else if (!(answerTries < 5))
         fatal("in main(). An invalid character was entered too many times.");
    else
        printf("[y/n]? ");

    ch = getchar();

    if (ch == 'n' || ch == 'N')
        exit(0);

    answerTries++;
} while (ch != 'y' && ch != 'Y');

hope it helped..

deb_rider
  • 570
  • 2
  • 12
  • 6
    `fflush(stdin)` is undefined behavior, but in practice, if you are lucky, it doesn't do anything. – Pascal Cuoq Apr 05 '14 at 21:43
  • :O I never knew the correct prototype of this function???? :( But how come it worked for me always??? – deb_rider Apr 05 '14 at 21:48
  • 1
    @deb_rider `fflush(stdin)` still matches the `fflush` prototype, so it won't generate a compilation error. "Undefined behavior" means that *anything* can happen. *Maybe* it'll happen to behave in a way that you think is sane. You should never rely on it, though. http://www.c-faq.com/ansi/undef.html – jamesdlin Apr 05 '14 at 21:57
  • 1
    @deb_rider: That's the beauty of undefined behaviour :) BTW, prototype of the function has nothing to do with this. C++ and C are different languages so I will refer to C99 standard: `If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.` So while similar, C definition is a little bit different - it allows `stream` to point to input but defines behaviour as undefined. – Krzysztof Adamski Apr 05 '14 at 22:01
  • _anything can happen._ There is a case where the operation is defined by the processing system. – BLUEPIXY Apr 05 '14 at 22:11