I've been attempting to teach myself some C, as I have been tasked with maintaining a program written for a handheld barcode scanner that appears to be written in this language. (At least, I'm assuming that for the moment, considering the fact one of the first statements I saw when I started skimming the source code was a malloc).

I've decided that for my first test program (to be shifted to the scanner to see if I can get it to work there) should be a four-function calculator. The scanner has a numeric keypad setting, so the numbers and symbols shouldn't be any problem.

My problem here is a bit simpler. So far, the only input reading method I've found in the text I'm using for this is the getchar() function. From what I can see, that doesn't look as though it's going to be able to handle more than one input character at a time; ergo, any mathematical equation involving numbers 10 and up would be (as far as I can see) impossible to directly deal with.

What other methods of input reading (from command line; I'm assuming that's stdin) are there? Is there something designed to read in multiple characters, or do I need to look into developing a read/store loop pattern for my numbers?

All input highly welcomed.

Recommended Answers

All 27 Replies

>any mathematical equation involving numbers 10 and up would be (as
>far as I can see) impossible to directly deal with.
You can perform any kind of input using single character input. In fact, that's basically what all of the other input functions do: they read one character at a time, store it somewhere, and optionally do some kind of formatting. For example, let's say you want very basic integer input:

#include <stdio.h>
#include <ctype.h>

int getint ( void )
{
  char buff[BUFSIZ];
  int result = 0;
  int ch;

  /* Pull all digits and add them to the result value */
  while ( ( ch = getchar() ) != EOF && isdigit ( ch ) ) {
    result = 10 * result + ( ch - '0' );
  }

  /* Return the unconverted character to the stream */
  ungetc ( ch, stdin );

  return result;
}

However, most of the time you don't need to do that. Not to mention that it takes a great deal of skill and effort to do it properly. For example, you should never use the above function in real code because it lacks decent bulletproofing. In your case, you should look up the fgets function for reading a line of input. That will give you a string that you can then parse. You can parse it with sscanf, or a number of functions from string.h.

And don't try to shortcut the fgets()/sscanf() pair with scanf() . If someone suggests it, stare at him in horror and cast the daemon away! :icon_mrgreen: Here's why. Read the entire scanf() series...

A little example of using what it has been said so far.
Sorry, the proper c tagging is not working at this time.

#include <stdio.h>
#include <ctype.h>

int getinteger( int *result )
{
    int send = 0;
    char ch;
    char buffer [ 13 ] = { '\0' };
    if( fgets( buffer, sizeof buffer, stdin ) && !isspace( *buffer ) &&  sscanf( buffer, "%d%c", result, &ch ) == 2 && ( ch == '\n' || ch == '\0' ) )
    {
        send = 1;
    }
    else
    {
       if( buffer[ strlen( buffer ) - 1 ] != '\n' )  /* if newline is not found in string */
       {
           while( getchar() != '\n' );                /* clear stdin */
       }
       send = 0;
    }
    return send;
}

int main( void )
{
    int number = 0;

    do
    {
       fputs( "Enter an integer: ", stdout );
       fflush( stdout );
    }
    while ( !getinteger( &number ) );

    printf( "number = %d\n", number );
    
    getchar();
    return 0;
}
commented: helpful, although the example could have been a lot cleaner +9

Sorry, the proper c tagging is not working at this time.

would you please explain what you mean by that? you can use [ code=c ] if you want to see line numbers, but I assume you already know that. If something is broken maybe you should start a thread in DaniWeb Community Feedback.

I try to use the tagging way like I always use, but this time didn't work not matter what I try. Here I attached a snap-shot I took of it. I will do like you say and start a thread in the Community Feedback.[code=C] tagging way like I always use, but this time
didn't work not matter what I try. Here I attached a snap-shot I took of it.
I will do like you say and start a thread in the Community Feedback.

I just tried it and it was ok -- If it persists for you please report it to Dani so that she can fix it.

There was a bug yesterday. It was fixed early this morning.

if( fgets( buffer, sizeof buffer, stdin ) && !isspace( *buffer ) &&  sscanf( buffer, "%d%c", result, &ch ) == 2 && ( ch == '\n' || ch == '\0' ) )

That's an unreadable and grotesque line of code.... Yuck! It certainly can be make much more readable and less convoluted.

Could you try to clean it up? :icon_confused: Remember, these are new programmers and showing an example that is too complex for them to understand is simply useless to them...

>Remember, these are new programmers and showing an example that is
>too complex for them to understand is simply useless to them...
Not to mention that no self-respecting programmer would be caught writing that. It's harder to follow the logic, harder to maintain, and harder to document. Don't try to do too much in the loop condition.

That's an unreadable and grotesque line of code.... Yuck! It certainly can be make much more readable and less convoluted.

Gee, Mr. WaltP, if I didn't know better I'll say you were describing The Hunchback Of Notre-Dame, or perhaps, what you'll find in the secret upper room of Dr. Frankenstein's castle.

Not to mention that no self-respecting programmer would be caught writing that.

Narue, Narue,...Madame Narue. Small in stature, but...oh, what a giant in ego.

Contrary to my better jugment, I am going to speak my mind about these comments, and then I will be prepared to the consecuences. Probably I will be crucified.

Remember, these are new programmers and showing an example that is too complex for them to understand is simply useless to them...

Mr. WaltP, with this comment you remainded me so much to any of the many politians that invoke the name of the collective "people" in vain."The American people this", "the American people that".

I am the OP, I am the new programmer,no, correction, I am the "new want to be" programmer, I am one, and every single newbie poster. I suppose that would make me a very arrogant person, if I were not speaking metaphorically, which I am. As such, their questions are my questions, their assigments are my assigments, their mistakes are my mistakes, and their frustation are also, mine.
Since you, Mr.WaltP desided to intercede, and become the patron of the new programmers, to thee I pray Saint WaltP. Listen to my plead.
...Their frustation is my frustation. I am frustated of the half answers, of the half hidden meaning of how to solve a problem. Frustated of the long explanations to solve a code problem, when with half of the characters used to explain, a piece of code could have be conjured and all doubts removed.

Oh, I forget, the noble code by which we go. Do not give away full code, least they will use it to cheat. We must protect them from themselves.
I wonder sometimes how much is in honor of that principle, and how much is the peer pressure of not wanting our code to be critized,..the fear of making a slip and to have to defend our ego. I am not a programmer so I don't have to defend my ego. Therefore I am not afraid of writing whatever I learn about C programming.

You both critized my post in the most clear terms. And I want, also, to be clear that I have the utmost admiration for your keen intellect.

What I learned I have learned here at Daniweb. The post I made is based in a snippet done by Mr. Dave Sinkula found here. He posted it, Aug 10th, 2005 and as far as I can tell no one of you have gone and posted any comment, telling him, ...how did Narue put it?. Ah, Yes:
>"Not to mention that no self-respecting programmer would be caught writing that."

#include <stdio.h>
#include <ctype.h>

int mygeti(int *result)
{
        char c, buff [ 13 ]; /* signed 32-bit value, extra room for '\n' and '\0' */
        return fgets(buff, sizeof buff, stdin) && !isspace(*buff) &&
        sscanf(buff, "%d%c", result, &c) == 2 && (c == '\n' || c == '\0');
}

int main(void)
{
        int value;
        do {
                fputs("Enter an integer: ", stdout);
                fflush(stdout);
        } while ( !mygeti(&value) );
        printf("value = %d\n", value);
        return 0;
}

Take a look at the function return. And then take another look at the line that I posted and you were so against it.

I am now ready for you to start throwing me rocks.

>Narue, Narue,...Madame Narue. Small in stature, but...oh, what a giant in ego.
Small people have to compensate somehow.

>as far as I can tell no one of you have gone and posted any comment,
>telling him, ...how did Narue put it?. Ah, Yes:
>>"Not to mention that no self-respecting programmer would be caught writing that."
I'm reasonably sure I expressed my displeasure in a private message. Or I meant to, but never got around to it. Don't feel like you're being treated unfairly. I would blast Dennis Ritchie too if he posted something like that. The function itself has some dubious design decisions in my opinion, but looking strictly at the formatting, tell me which you find easier to read:

#include <stdio.h>
#include <ctype.h>

int mygeti(int *result)
{
  char c, buff [ 13 ]; /* signed 32-bit value, extra room for '\n' and '\0' */
  return fgets(buff, sizeof buff, stdin) && !isspace(*buff) &&
    sscanf(buff, "%d%c", result, &c) == 2 && (c == '\n' || c == '\0');
}

int mygeti2 ( int *result )
{
  char buff[13]; /* Signed 32-bit value, extra room for '\n' and '\0' */
  char c;

  if ( fgets ( buff, sizeof buff, stdin ) != NULL ) {
    /* Comment explaining why you fail on leading whitespace */
    if ( isspace ( *buff ) )
      return 0;

    if ( sscanf ( buff, "%d%c", result, &c ) == 2 ) {
      /* Success only if the line has one field and it's an integer */
      if ( c == '\n' || c == '\0' )
        return 1;
    }
  }

  return 0;
}

Dave Sinkula, a very talented C programmer, has given quite a bit of attention to this issue. Take a look at one or more of his code snippets at DaniWeb:
http://www.daniweb.com/code/snippet266.html

>Dave Sinkula, a very talented C programmer, has given quite a bit of attention to this issue.
You realize that we're talking about the very conventions that Dave used in his code, right?

I'm reasonably sure I expressed my displeasure in a private message. Or I meant to, but never got around to it

Wrinting in English I do poorly; speaking it, there's not much improvement, neither. However let me assure you, my reasoning is not impaired by the language barrier, and when I see a pile of dung I can recognize it. Perhaps by the slippering feeling at the moment of stepping on it.

As I read your comment I had the same queasy slippering feeling.
You sound like any of these "hot-shots" that are brought before a congressional commiting, to give a report of their stewardship.

Are you telling me that you, the embodiment of code correctness; by the way, I like your article about random numbers in your webpage;...that you allowed 1,625 viewiers, possible "new programmers seeking knowlegde", and didn't do anything?.

I call that "horse excrement", pardon my language.

Dave Sinkula, a very talented C programmer, has given quite a bit of attention to this issue. Take a look at one or more of his code snippets at DaniWeb:
http://www.daniweb.com/code/snippet266.html

Yes he is. And I have learn many good coding from him.

The function itself has some dubious design decisions in my opinion, but looking strictly at the formatting, tell me which you find easier to read:

I admire that you posted your take of how to write that piece of code. That allow us to learn and compare.

My opinion is that all that you did was to separate what it was in one expression, into
multiple ifs statements. If you understand those expressions in the ifs, there's no trouble at all, reading the one single return.
In fact your code suffers of the same short comming that Mr. Dave's, which I tried to remedy and I did butcher it.
If a user inputs more that what the buffer array can hold, of course the wrong input is
entered and the result will be manifested when in the next loop the buffer stdin is read.

If I had to post again I would have done it like:

int getinteger( int *integer )
{
    char ch;
    char buffer [ 13 ] = { '\0' };
    
    if( fgets( buffer, sizeof buffer, stdin ) )
    {
   /*  check that nothing is left in the stdin  */
       if( buffer[ strlen( buffer ) - 1 ] != '\n' )
       {
           while( getchar() != '\n' ); /* clean stream */
       }
    }
   /*  expression that will tell if user inputed an integer and nothing else */
    return !isspace( *buffer ) &&  sscanf( buffer, "%d%c", integer, &ch ) == 2 && ( ch == '\n' || ch == '\0' );
}

> The function itself has some dubious design decisions in my opinion

May I ask you, then, why you don't teach us the way you would do it, instead of letting us guess what you mean by; and then, ...how did you said it? ...blast[ing] us, when we try to emulate your code?.

>Are you telling me that you, the embodiment of code correctness; ...that
>you allowed 1,625 viewiers, possible "new programmers seeking knowlegde", and didn't do anything?.
Dave's code is correct. I don't agree with the style he used, but I respect his choices. I do this because I respect him as a programmer and he knows what he's doing. However, when one of those "new programmers seeking knowledge" uses a bad style, I'll call them on it because they likely don't know better.

>My opinion is that all that you did was to separate what it was in one expression, into multiple ifs statements.
Your opinion is extremely close to fact. Well done. Now can you explain why I changed what I changed?

>If you understand those expressions in the ifs, there's no trouble at all, reading the one single return.
I see. Can you tell at a glance that all of the necessary expressions are present, that they're in the correct order, and that they work together to give you the desired return value? I can't. I have to look at it closely to verify that it's correct where a more carefully formatted function would be easier to check. Since you seem to believe that I'm some kind of amazing programmer, that should tell you something.

>In fact your code suffers of the same short comming that Mr. Dave's
Indeed. My code is logically identical to his because any change to the logic would defeat the purpose of comparing the two styles.

>May I ask you, then, why you don't teach us the way you would do it,
>instead of letting us guess what you mean by
Leading whitespace isn't treated intuitively. It simply errors when removal is a safe and expected alternative. The function only allows exactly a valid number, and nothing else. 12345test fails, 123 456 fails, etc... And the fact that a full buffer isn't handled appropriately are among the problems I saw.

The reason I didn't teach you the way I would do it is because the solution is dependent on what is needed. There are a number of ways to read a single integer, and all of them are suited to different situations. In the generic case, my way would probably amount to scanf, so there's no need to do anything.

Your opinion is extremely close to fact. Well done. Now can you explain why I changed what I changed?

I can not read your intention off your mind, but I believe I can.
Your code will evaluate the first if

if ( fgets ( buff, sizeof buff, stdin ) != NULL ) {
    /* Comment explaining why you fail on leading whitespace */
    if ( isspace ( *buff ) )
      return 0;

and if it fails the test, it doesn't have the need for evaluating the third comming if.
However you used multiple returns, which according to Mr WaltP is something "real" programmers frown upon it.

>However you used multiple returns, which according to Mr WaltP is
>something "real" programmers frown upon it.
Real programmers do what most clearly illustrates the code's intentions. If you can pull off single entry/single return without it being awkward, more power to you. But while that guideline of structured programming is a nice starting point, it's far too restrictive for most real world code.

But while that guideline of structured programming is a nice starting point, it's far too restrictive for most real world code.

Kind of like you go to driving-school to learn how to drive a car; you get your driver license and then you have to forget everything you learned there just to survive in the road?. Let's drive like there is no "mañana".

You seem to be confused about the difference between a guideline and a rule. A rule shouldn't be broken, but a guideline is a suggestion. And after decades of experience, programmers have learned that some of the guidelines in structured programming are impractical.

>You seem to be confused about the difference between a guideline and a rule. A rule shouldn't be >broken, but a guideline is a suggestion.
Nice spin. Your good.
What's a rule except a guideline suggestion gone dictatorial?.

>And after decades of experience, programmers have learned that some of the guidelines in structured >programming are impractical.
After all they were who suggested those guidelines. Oh, well.
Thank you Lady Narue.
I will think about what you just said. And next time that you "blast" any newbie I'll be there with encouragement saying to her or him. It is nothing more that her "suggestion; a guideline".

Good grief Charlie Brown, where is the answer to EnderX in all this senseless squabble?

Good grief Charlie Brown, where is the answer to EnderX in all this senseless squabble?

Search your hart "little grasshopper". What do you feel?. Can you hear the bits of your hart?. There lies the answer.

>Good grief Charlie Brown, where is the answer to EnderX in all this senseless squabble?
That would be posts 2 and 4. And squabbles are only useless if they're uninformative.

>Nice spin. Your good.
I've never claimed to be anything but.

>What's a rule except a guideline suggestion gone dictatorial?.
Not much. What's your point?

>After all they were who suggested those guidelines. Oh, well.
Believe it or not, people and opinions change.

>And next time that you "blast" any newbie I'll be there with
>encouragement saying to her or him. It is nothing more that her "suggestion; a guideline".
And when it's actually a rule, I'll be sure to trim your little ego back to size.

commented: Yeah you go girl! +9
commented: Yeah, you go girl! +3

> And when it's actually a rule, I'll be sure to trim your little ego back to size.
If you can trim it is because it would have grown and it needs it.

commented: Girl's need to trim it. Guys not so much. +9

I guess this is what Narue gets for letting budding programmers close to her. ;-)

>I guess this is what Narue gets for letting budding programmers close to her. ;-)
It's amazing too, seeing as how I do my best to keep people at arm's length.

My apologies for my choice of wording in post 11 and 15.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.