How to read from stdin in C?

Asked

Viewed 12,710 times

29

How should I read characters, digits and strings stdin?

  • getchar;
  • fgetc;
  • fgets;
  • getc;
  • scanf;

I’m here trying to read from the console and there’s always something wrong with reading it. I have tried all these forms and there is always a problem. Every time I search on the subject I get more in doubt.

  • Related: http://answall.com/questions/42916/segmentation-fault-listas-ligadas-em-c

  • 1

    Each has its own character, in the case of scanf you can use it for anything, so you can read a char for example you use scanf("%c",&c);, so you can read 1 char no matter what it is[number, letter, dots, digits]. Remembering that if you type more than one charit will stay in the buffer, so no problems use some function to clean the buffer [__fpurge(),fflush()] before each scanf().

1 answer

29


It depends on the purpose, whether you want to read a character, a sequence or want a specific format. Some today depends more on taste.

getchar()

Read only one character, nothing more. It doesn’t matter what. Usually used when you want to control the input of data the way you want to. Can be used to compose more complex data reading functions.

fgetc(), getc()

It would only make sense to compare them to read the stdin if it were used as a parameter since these functions read some stream to be specified, the stdin is one of them.

So to read the stdin It ends up being a matter of taste. In general the person standardizes to use one or the other always. Many people prefer to ignore two of these three functions always. From what I understand fgetc() is the most chosen by the most experienced programmers.

The first must necessarily be a function and the second can be implemented as a macro. This makes no difference to current implementations since the former can be optimized by the compiler with inline.

fgets()

Read a string until you find one \n (which will be obtained, for example, when a ENTER is typed) simply without caring what these characters are, except the terminator. It specifies a maximum length of characters that can be read, so it will close when you reach this limit even if you do not find the terminator. The limit is always a character unless specified because at the end is included a character NULL to finish the string.

He’s waiting for the entrance of \n for buffer of stdin (possibly coming from the keyboard.

scanf()

This is the most powerful function because it reads sequences of characters according to a format, thus making some filter of what can enter.

With it you can determine the maximum number of characters typed, whether any character can be typed or only some are accepted (for example, only numeric digits). Finally you have to study all configuration parameters.

Note also that the sequence of characters entered can be converted to a specific type, i.e., you read a string of characters but the end result can be a number (int, float, etc..).

The use of the parameter "%c" is determined to read only one character, thus working as the first functions.

An important difference for others is that your return indicates the success or failure of reading. The result itself is "returned" through a reference to a variable (passed by pointer).

If you have more than one you may have problems with releasing buffer in some situations. I see a lot bug because of this. And solutions that don’t always work. It’s not useful apart from very simple things.

Inadequacy

Because it is a vulnerable function like so many others in C, it is common for someone to use other custom functions to do the same. Third-party or own ready library functions usually better meet real needs and better control possible exploits of poorly formatted entries.

And it’s not just about safety, a lot of things can go wrong when you use this function. I’m not saying she’s terrible to use, just that she expects a minimum of coherence from the typist. And a serious program can’t expect this, it must address the most extreme possibilities that anyone can do.

Outside of the naive, learning applications, one usually uses some other solution or at most reads everything as a character and then is made a conversion to a type through an algorithm (probably in a specific function) making a series of validations. We almost never see serious applications relying on the validation and conversion of scanf().

Good thing you didn’t want to know how to use the gets(). As it does not limit the size of the can receive data is used for security breach. It has a serious problem of buffer overflow. Of course any solution if it is misused can also have problems. The scanf() may have the same or other problems if not using with correct parameters.

Teaching in the simplest way seems appropriate to facilitate learning. The problem is that one learns so without understanding the whole and uses resources that only serve for learning in software that go to production. Fortunately many times these people end up not passing the learning using C and do not cause major problems for everyone.

Completion

If you don’t mind the fine processing of the data entry the most common is to use even the scanf() which gives you more possibilities than other options. The others are usually used in much more specific cases, usually when you are going to do something more low-level, possibly build a more complex reading function and more suitable to what you need.

In practice when data entry is important and needs more serious validation, creating a more complex and problem-appropriate function is the best solution.

It is also rare to have new serious console applications today. The preference today is for GUI or web and/or use of an API that controls data entry on its own.

When someone is going to do something for console nowadays it is almost always an internal utility that will be used by people who know how to properly use a poorly validated software. Other cases need better ways of data entry than the above.

Function example for handling data input:

int getUserInput(char * returnStr, int maxStringLength) {
   char    *tempStr;
   int     maxLen, totalCount = 0;
   size_t  len;
   maxLen = maxStringLength + 2;     //account for NULL and /newline
   tempStr = malloc(maxLen * sizeof(char));  //temporary holder
   do {
      fgets(tempStr, maxLen, stdin);  // get chars from input buffer
      len = strlen(tempStr);
      if (tempStr[len-1] == '\n') { // newline indicates end of string
         tempStr[len-1] = '\0';   // delete it
         len = strlen(tempStr);   // and recalc length
      }
      totalCount += (int)len;
   }
   while ((int)len > maxStringLength);  // continue to flush extras if too long
   strcpy(returnStr, tempStr);  // copy temp string into output
   free(tempStr);              // and release memory
   return totalCount;   // may be more than the number allowed
}

I put in the Github for future reference.

Withdrawn of this discussion. This code can be greatly improved.

  • The terminator of fgets() is a '\n'. In addition to the fgets() can devovler a string without the terminator if sufficient space is not specified.

  • That’s right, I’ll settle this. Thank you.

  • When you use fgets (buffer, size, stdin); the program stands still waiting for input, or continues?

  • 1

    Edited. If you’re not expecting probably had something on buffer that causes continuity. All these functions hope to come something from the buffer. What many do not understand is that the buffer may not be clean.

  • 1

    +1 It is by these answers that I love belonging to the Sopt community.

  • 1

    I’ll still try to improve some things later.

  • @bigown, if I’m following your example, getUserInput(s,8), before the entrance "1234567890", will return 10 and fills in s with "90". this was the intended behavior?

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.