#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    5
    Rep Power
    0

    Question What am I doing wrong? (very simple C program)


    I just started learning C, this program I wrote is supposed to convert an entered binary number to a decimal number as follows: you enter the desired binary number 1 character at a time, with enters between them, and then when you enter another character than "1" or "0", it displays the decimal number, and asks if you want to run the program again.

    When I run this program (using Netbeans) it asks for a binary number, if I enter "1" (or any other character) it will give the decimal value right away, so it doesn't stay in the loop.

    it seems to have difficulties with getchar(), i tried replacing both with scanf, but then i couldn't restart the program at the end, it would ask "would you like to restart" but I can't enter anything after that, it would just say the program is finished.
    What am I doing wrong here? Thanks in advance.
    EDIT: I've got it working now with scanf, but I would still like to see it working with getchar()
    Code:
    int main() 
    {
    char chAgain = 'y';
        
        while (chAgain == 'y')
        {
            printf("Enter binary number: \n");  
            
            int nOutput = 0;
            char chInput;
            
    
            do
            {            
                chInput = getchar();
                    
                if ((chInput == '0') || (chInput == '1'))
                {
                    if (chInput == '0') 
                    {
                        nOutput = nOutput * 2;
                    }
                    else
                    {
                        nOutput = nOutput * 2 + 1;
                    }                    
                }    
                else;          
            }
            while ((chInput == '0') || (chInput == '1'));
                    
            printf("Decimal value is: %i", nOutput);
            printf("Do you want to run this program again? [y/n]: ");
            
            chAgain = getchar();
        }
    
        return 0;
    }
  2. #2
  3. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,392
    Rep Power
    1871
    With getchar(), you'll also need to deal with the \n character you get when the user presses enter.

    scanf usually ignores newlines (and other white space), so this could explain your other success.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    5
    Rep Power
    0
    Originally Posted by salem
    With getchar(), you'll also need to deal with the \n character you get when the user presses enter.
    I know \n is used to go to the next line, but I don't understand what you mean with this, could you give an example how I should use getchar() here?
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,172
    Rep Power
    2222
    For historical reasons (circa 1970 when the only terminals were remote dumb and smartish terminals; PCs were about a decade away), C input functions are line-oriented. That means that your program will not even begin to start processing the keyboard input until you press the Enter key. All the input is stored in a keyboard buffer until it gets process by your program's calls to getchar, etc. That includes the newline character(s) for the Enter key.

    Your program processes the input buffer only so long as the character is a '1' or a '0'. As soon as the character is something else, you drop out of the loop. Maybe that last getchar that wasn't a '1' or a '0' ate that newline character, maybe not. What if the user input a space before the Enter? Or a punctuation mark? What if the Enter key enters two characters into the buffer (eg, CRLF, '\x0D' and '\x0A'), which is the convention in Windows/DOS text files?

    For that matter, what if the user entered white space such as a space before the binary string you asked for? How do you handle that?

    The Standard C Library has functions which test a character for the type of character that it is. Those functions are prototyped in ctype.h. They test for it being a whitespace character, a punctuation mark, a letter, a digit, a letter or digit, a printable character, etc. You want to input a letter, 'y' or 'n'? Place that getchar call inside a loop that will repeatedly call it until it does get a letter.

    In the meantime for your own debugging purposes, you can output the character you just read in so you can see exactly what was read. I would recommend also displaying its ASCII code, since 33 characters are not printable.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    5
    Rep Power
    0
    Originally Posted by dwise1_aol
    For historical reasons (circa 1970 when the only terminals were remote dumb and smartish terminals; PCs were about a decade away), C input functions are line-oriented. That means that your program will not even begin to start processing the keyboard input until you press the Enter key. All the input is stored in a keyboard buffer until it gets process by your program's calls to getchar, etc. That includes the newline character(s) for the Enter key.

    Your program processes the input buffer only so long as the character is a '1' or a '0'. As soon as the character is something else, you drop out of the loop. Maybe that last getchar that wasn't a '1' or a '0' ate that newline character, maybe not. What if the user input a space before the Enter? Or a punctuation mark? What if the Enter key enters two characters into the buffer (eg, CRLF, '\x0D' and '\x0A'), which is the convention in Windows/DOS text files?

    For that matter, what if the user entered white space such as a space before the binary string you asked for? How do you handle that?

    The Standard C Library has functions which test a character for the type of character that it is. Those functions are prototyped in ctype.h. They test for it being a whitespace character, a punctuation mark, a letter, a digit, a letter or digit, a printable character, etc. You want to input a letter, 'y' or 'n'? Place that getchar call inside a loop that will repeatedly call it until it does get a letter.

    In the meantime for your own debugging purposes, you can output the character you just read in so you can see exactly what was read. I would recommend also displaying its ASCII code, since 33 characters are not printable.
    Thank you very much for your reply.
    I had some difficulties with understandig it at first, for I'm an absolute newbie in (C) programming, but I think I understand most of it now. More important is that I've got it working like I want now, by adding
    Code:
    while (getchar() != '\n');
    After the last getchar(). However, I'm still not completely satisfied because even though I know this provides what I want ('ignoring' the \n), I don't really understand why; while the input char is not equal to \n, it does what? How can I make sense of that tiny line I added? And why does it work when I place it AFTER the last getchar() call? And why is there nothing between {}?

    So then I had a look at this ctype.h and found this:
    Code:
    _BEGIN_STD_C
    
    int _EXFUN(isalnum, (int __c));
    int _EXFUN(isalpha, (int __c));
    int _EXFUN(iscntrl, (int __c));
    int _EXFUN(isdigit, (int __c));
    int _EXFUN(isgraph, (int __c));
    int _EXFUN(islower, (int __c));
    int _EXFUN(isprint, (int __c));
    int _EXFUN(ispunct, (int __c));
    int _EXFUN(isspace, (int __c));
    int _EXFUN(isupper, (int __c));
    int _EXFUN(isxdigit,(int __c));
    int _EXFUN(tolower, (int __c));
    int _EXFUN(toupper, (int __c));
    so what should my getchar() call look like with one of these in it? (And which one represents letter character?)

    And finally, I just looked up what ASCII is, but what's up with 33 characters?
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,172
    Rep Power
    2222
    Originally Posted by Oarta
    And finally, I just looked up what ASCII is, but what's up with 33 characters?
    Read this in Wikipedia for a more complete explanation: ASCII control characters.

    ASCII was developed from earlier teletype codes to be used with teletype machines; the earlier codes go back to 1874. Some characters were for data, those being printable characters. Some characters were for teletype control, those not being printable. ASCII codes 0 to 31 are control characters, including tab, bell, carriage return, line feed, and escape. That makes 32. The last 7-bit character, code 127, DEL (AKA "delete", AKA "rubout"), makes the count 33. 33 control characters. The link I gave above describes the control characters far better than I could here.

    In addition, there's the question of 7-bit vs 8-bit ASCII. Since the 8-th bit would often be used for parity (a form of error checking), most of the time only seven bits were available for data and control. This limits ASCII to 128 codes, 0 to 127. Applications that allowed for the 8-th bit to also be used, such as computers, provided an additional 128 codes. These are called extended ASCII codes and could be used to encode special symbols such as accented vowels and other letters not found in English. There was no standard for extended ASCII codes so each set of extended codes would be different.

    There are other encoding systems, such as ISM's Extended Binary Coded Decimal Interchange Code (EBCDIC). And now we have Unicode which provides a wide range of codes to computer applications. The first 127 codes in Unicode correspond to 7-bit ASCII.



    Originally Posted by Oarta
    So then I had a look at this ctype.h and found this:

    . . .

    so what should my getchar() call look like with one of these in it? (And which one represents letter character?)
    The prototypes I was referring to were these (from MinGW gcc's header file):
    Code:
    int	isalnum(int);
    int	isalpha(int);
    int	iscntrl(int);
    int	isdigit(int);
    int	isgraph(int);
    int	islower(int);
    int	isprint(int);
    int	ispunct(int);
    int	isspace(int);
    int	isupper(int);
    int	isxdigit(int);
    To find out what each one does, read the manual (RTFM!). If your development environment does not have a help file and if your system does not have man pages, you can look up the appropriate man pages on-line with Google or whatever search engine you use; eg, man page isalnum. They are very probably combined on the same man page.

    Basically, you pass the character to the function and the function will return zero if it's not the type that the function tests for and non-zero if it is. isdigit tests for '0'-'9'. isspace tests for it being whitespace. isalnum tests for it being a letter or a digit. isprint tests for it being a printable character. iscntrl tests for it being a control character. Needless to say, these functions can come in handy if you're processing data character by character.

    So then your example could look something like this:
    Code:
    while (isspace(getchar()));
    But that would also skip tab and space characters as well as newlines. If instead you want to skip all characters except letters or digits, then you could use isalnum; eg:
    Code:
    while (!isalnum(ch=getchar()));
    That would loop until the input character is a letter or a digit. Please note how I'm assigning the return value of getchar to a char variable. That way, you can remember what that character was so that you can still use it once you get out of the loop.

    Originally Posted by Oarta
    However, I'm still not completely satisfied because even though I know this provides what I want ('ignoring' the \n), I don't really understand why; while the input char is not equal to \n, it does what? How can I make sense of that tiny line I added? And why does it work when I place it AFTER the last getchar() call? And why is there nothing between {}?
    This tells me that you researched that line from somewhere. No problem with that, so long as you understand what it does. And you are trying to understand that, which is good.

    getchar gets the next character from the input buffer. All that you do with it is to test whether it is a '\n'. If it is a '\n', then you remain in the loop; if it isn't then you drop out of the loop. An unfortunate side-effect is that you also use up the non-'\n' character that drops you out of the loop, which could be the one you want. Please note how the example I gave above saves that character.

    A while or for loop doesn't need a body so long as the statement does all the work you need. Most of the time, yes, it does have a body and the cases in which it doesn't need one are rather rare. When you do it, be sure to comment that loop to state explicitly that, yes, you meant to do that and why you meant to do that.

    To read code and understand just what it's doing, it can be helpful to "play computer" with pencil and paper. Sketch an input buffer of every character that you type in, including the spaces and new-lines. Also sketch the variables. Then step through your code and take a character out for each getchar(). This will give you practice in reading and understanding code without having to write everything down.

IMN logo majestic logo threadwatch logo seochat tools logo