When this program prompts the user for input, it works fine for the correct input. But for the wrong inputs, it returns a zero for every character, including the white spaces. My goal of this program is to return a roman numeral as an integer. For the wrong inputs, I would like to return only one zero and a prompt to reenter another value. What can I further do to fix this program?

Here is the code:
driver.c

/*  This file contains a test driver which reads a number in roman 
 *          numerals and prints it in decimal.  I uses the function
 *                  get_roman() in roman.c
 *                  */

#include <stdio.h>
#include "roman.h"
#define FLUSH while(getchar() != '\n')

main()
{  int number;

        /*  prompt for first roman number entry  */
        printf("Enter a number in roman numerals(EOF to quit): ");

        /*  while there are more numbers  */
        while((number = get_roman()) != EOF)
        {       printf("The number is %d\n",number);
                /* prompt for next number  */
                printf("Enter an number in roman numerals(EOF to quit): ");
        }
        /*  clean up screen  */
        printf("\n");
}

roman.h

/*  This file contains the  prototypes and macros for converting
 *          roman numerals.
 *          */


/*  These macros represent valid roman numerals and their values  */
#define M       1000
#define D       500
#define C       100
#define L       50
#define X       10
#define V       5
#define I       1

int get_roman(void);
/*  returns the next roman number in the input or EOF  */

roman.c

/*  This file contains the functions used to read and convert a number
 *          in roman numerals.
 *          */

#include <stdio.h>
#include "roman.h"
#include "romanutil.h"

int get_roman(void)
/*  This function reads the next number in roman numerals from the input
 *          and returns it as an integer  */
{  char rdigit;
   int  num = 0;
   int  dig_value, last_dig_value = M;

        /*  get the first digit  */
        rdigit = getchar();
        /*  while it is a roman digit  */
        while( is_roman(rdigit))
        {
                /*  convert roman digit to its value  */
                dig_value = convert_roman(rdigit);
                /*  if previous digit was a prefix digit  */
                if(dig_value > last_dig_value)
                        /*  adjust total  */
                        num = num - 2 * last_dig_value + dig_value;
                /*  otherwise accumulate the total  */
                else num = num + dig_value;
                /*  save this digit as previous  */
                last_dig_value = dig_value;
                /*  get next digit  */
                rdigit = getchar();
        }

        /*  return EOF if detected  */
        if(rdigit == EOF) return EOF;

        /*  return the number  */
        return num;
}

romanutil.h

/*  This file contains the  prototypes for utilities used in
 *           converting roman numerals.
 *           */


int is_roman(char c);
/*  tests if c is a valid roman numeral, returns true or false  */

int convert_roman(char c);
/*  converts roman numeral c to its value, NULL if invalid  */

char to_upper(char);
/*  converts a character to upper case  */

romanutil.c

/*  This file contains the functions used to read and convert a number
 *          in roman numerals.
 *          */

#include <stdio.h>
#include "roman.h"
#include "romanutil.h"
#include "tfdef.h"
#include "chrutil.h"


int is_roman(char c)
/*  This function is given a character and returns true if it is
 *          a valid roman numeral, flase otherwise.  */
{
        /*  convert digit to upper  */
        c = to_upper(c);
        /*  test the digit  */
        switch(c)
        {  case 'M':
           case 'D':
           case 'C':
           case 'L':
           case 'X':
           case 'V':
           case 'I':  return TRUE;
           default :  return FALSE;
        }
}



int convert_roman(char c)
/*  This function is given a roman numeral and returns its value.
 *          NULL is returned if the character is not valid  */
{  int digit;

        /*  convert digit to upper  */
        c = to_upper(c);
        /*  convert the digit  */
        switch(c)
        {  case 'M':
                digit = M;
                break;
           case 'D':
                digit = D;
                break;
           case 'C':
                digit = C;
                break;
           case 'L':
                digit = L;
                break;
           case 'X':
                digit = X;
                break;
           case 'V':
                digit = V;
                break;
           case 'I':
                digit = I;
                break;
           default :
                digit = (int)NULL;
        }

        /*  and return its value  */
        return digit;
}


char to_upper(char c)
{
        if(IS_LOWER(c)) return c - 'a' + 'A';
        return c;
}

tfdef.h

/* File: tfdef.h */
#define TRUE 1
#define FALSE 0

Edited 6 Years Ago by tquiva: n/a

After you test for EOF, test for an invalid character. If you got one, clear the rest of the input buffer and return 0.

I'm still kind of a beginner. I'm sorry, I don't understand. What do you mean by clearing the rest of the input buffer and return 0?

getchar() doesn't read anything until you press the ENTER key. Then is starts reading from the first character entered. If you enter "XILWVMCDI", when the program reaches W the loop exits. "VMCDI" and the ENTER is still in the buffer. You need to clear the buffer before continuing or your next input will get the V. I'm sure that's why "it returns a zero for every character"

If I were to do that, the only part I would edit would be roman.c?

Is it ok if I used this macro to flush the buffer?
#define FLUSH while(getchar() != '\n');

Edited 6 Years Ago by tquiva: n/a

Is it ok if I used this macro to flush the buffer?
#define FLUSH while(getchar() != '\n');

You could, but why? Just use the while line. Just make sure you haven't read it '\n' yet.

You could, but why? Just use the while line. Just make sure you haven't read it '\n' yet.

I'm a little lost again...
so I used the while line instead and edited driver.c

#include <stdio.h>
#include "roman.h"
#define FLUSH while(getchar() != '\n');

main()
{  int number;

        /*  prompt for first roman number entry  */
        printf("Enter a number in roman numerals(EOF to quit): ");

        /*  while there are more numbers  */
        while((number = get_roman()) != EOF)
        {       printf("The number is %d\n",number);
                /* prompt for next number  */
                while(getchar() != '\n')
                {
                printf("Enter an number in roman numerals(EOF to quit): ");
                }
        }
        /*  clean up screen  */
        printf("\n");
}

is this what you meant by using just the while line?

Almost. Doesn't that print the message multiple times?

Use while(getchar() != '\n'); Be sure the ; is at the end and you will read all the leftover characters in the input buffer.
But you have to place it in the code after you are done with your input and you know there are more characters unread. So you need to think a little more on the placement.

Hint: Somewhere in get_roman(void) is where it needs to go.

Almost. Doesn't that print the message multiple times?

Use while(getchar() != '\n'); Be sure the ; is at the end and you will read all the leftover characters in the input buffer.
But you have to place it in the code after you are done with your input and you know there are more characters unread. So you need to think a little more on the placement.

Hint: Somewhere in get_roman(void) is where it needs to go.

I tested almost every line for for while(getchar() != '\n');
and found only one suitable line for it, line 27. I am now getting my expected output for invalid inputs. However, the valid inputs are now behaving differently than before. I have to press enter twice in order to get the output. What am I doing wrong here?

int get_roman(void)
/*  This function reads the next number in roman numerals from the input
 *          and returns it as an integer  */
{  char rdigit;
   int  num = 0;
   int  dig_value, last_dig_value = M;

        /*  get the first digit  */
        rdigit = getchar();
        /*  while it is a roman digit  */
        while( is_roman(rdigit))
        {
                /*  convert roman digit to its value  */
                dig_value = convert_roman(rdigit);
                /*  if previous digit was a prefix digit  */
                if(dig_value > last_dig_value)
                        /*  adjust total  */
                        num = num - 2 * last_dig_value + dig_value;
                /*  otherwise accumulate the total  */
                else num = num + dig_value;

                /*  save this digit as previous  */
                last_dig_value = dig_value;
                /*  get next digit  */
                rdigit = getchar();
}
        while(getchar() != '\n');
        /*  return EOF if detected  */
        if(rdigit == EOF) return EOF;
        /*  return the number  */
        return num;
}

Edited 6 Years Ago by tquiva: n/a

If you enter XI the input buffer contains X, I, ENTER.
The only way to exit your main while loop is to not see a Roman Numeral. That would be ENTER. Therefore the input buffer is empty and you exit the loop.

Now you enter the next while with:
* rdigit = '\n'
* input buffer empty

You need a little more code to make it work -- very little.

If you enter XI the input buffer contains X, I, ENTER.
The only way to exit your main while loop is to not see a Roman Numeral. That would be ENTER. Therefore the input buffer is empty and you exit the loop.

Now you enter the next while with:
* rdigit = '\n'
* input buffer empty

You need a little more code to make it work -- very little.

I'm really lost. Could you please give me a hint?
I was thinking of putting another if statement, but that might not be right?

this is the if statement that I added to the code. (starting at line 29) could you please check if it compiles and runs fine?

int get_roman(void)
/*  This function reads the next number in roman numerals from the input
 *          and returns it as an integer  */
{  char rdigit;
   int  num = 0;
   int  dig_value, last_dig_value = M;

        /*  get the first digit  */
        rdigit = getchar();

        /*  while it is a roman digit  */
        while( is_roman(rdigit))
        {
                /*  convert roman digit to its value  */
                dig_value = convert_roman(rdigit);
                /*  if previous digit was a prefix digit  */
                if(dig_value > last_dig_value)
                        /*  adjust total  */
                        num = num - 2 * last_dig_value + dig_value;
                /*  otherwise accumulate the total  */
                else num = num + dig_value;
                /*  save this digit as previous  */
                last_dig_value = dig_value;

                /*  get next digit  */
                rdigit = getchar();
        }

        if (rdigit != '\n')
        {
        while (getchar() != '\n' && getchar() != EOF);
        }

        /* while(getchar() != '\n' && getchar() != EOF);
        */
        /*  return EOF if detected  */
        if(rdigit == EOF) return EOF;


        /*  return the number  */
        return num;
}

Edited 6 Years Ago by tquiva: n/a

So close! You just overdid it. Your while statement (why did you change it?) now reads 2 characters, not 1. And why do you have to check for EOF anyway?

So close! You just overdid it. Your while statement (why did you change it?) now reads 2 characters, not 1. And why do you have to check for EOF anyway?

So I edited it again, and everything seems to run great now. Is this correct?

int get_roman(void)
/*  This function reads the next number in roman numerals from the input
 *          and returns it as an integer  */
{  char rdigit;
   int  num = 0;
   int  dig_value, last_dig_value = M;

        /*  get the first digit  */
        rdigit = getchar();

        /*  while it is a roman digit  */
        while( is_roman(rdigit))
        {
                /*  convert roman digit to its value  */
                dig_value = convert_roman(rdigit);
                /*  if previous digit was a prefix digit  */
                if(dig_value > last_dig_value)
                        /*  adjust total  */
                        num = num - 2 * last_dig_value + dig_value;
                /*  otherwise accumulate the total  */
                else num = num + dig_value;
                /*  save this digit as previous  */
                last_dig_value = dig_value;

                /*  get next digit  */
                rdigit = getchar();
        }

        if (rdigit != '\n')
        {
        while (getchar() != '\n' && getchar());
        }

        /*  return EOF if detected  */
        if(rdigit == EOF) return EOF;


        /*  return the number  */
        return num;
}
This article has been dead for over six months. Start a new discussion instead.