How to read from stdin in C?

How should I read characters, digits and strings of the stdin in C?

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

I'm here trying to read from the console and there is always some problem with reading it. I have tried all these ways and there is always any problem. Every time I research on the subject I become more in doubt.

Author: Maniero, 2014-12-05

1 answers

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()

Reads only one character, nothing more than this. No matter what. Typically used when you want to control data entry in the way you see fit. It can be used to compose data reading functions in a more complex way.

fgetc(), getc()

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

So to read the stdin turns out to be 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 like a macro. Which makes no difference to current implementations since the former can be optimized by the compiler with inline.

fgets()

Reads a string until it finds a \n (which will be obtained, for example, when an ENTER is typed) simply without caring what those characters are, except for the Terminator. It specifies a maximum size of characters that can be read, so it will be terminated when it reaches this limit even if you do not find the Terminator. The limit is always one character unless specified because a character NULL is included at the end to end the string.

It is waiting for the input of \n by the buffer of the stdin (possibly coming from the keyboard.

scanf()

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

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

Also note that the input string can be converted to a specific type, i.e. you read a string but the end result can be a number (int, float, etc.).

The use of the parameter "%c " ends up determining the reading of only one character, working just like the first functions.

An important difference to the others is that your return indicates the success or failure of the reading. The result itself is "returned" via 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 being. And solutions that do not always work. She is not useful other than 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 proprietary out-of-the-box library functions often better meet actual needs and better control possible exploits of poorly formatted entries.

And it's not just about security, a lot can go wrong when uses this function. I'm not saying that she is terrible to use, just that she expects a minimum of consistency on the part of the digitizer. And a serious program cannot expect this, it must address the most extreme possibilities one can do.

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

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

Teaching the simplest way seems appropriate to facilitate learning. The problem is the person learns this way without understanding the whole and spends using resources that only serve for learning in software that goes to production. Fortunately many times these people end up not moving on from learning using C and do not cause major problems for everyone.

Conclusion

If you don't care much about fine processing of data entry the most common is to use even the scanf() which gives more possibilities than other options. The rest are usually used in much more specific cases, in general 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 for new ones to exist serious applications for console nowadays. The preference today is for GUI or web and/or use of an API that controls data entry in its own way.

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

Example function for manipulating input from data:

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 on GitHub for future reference .

Removed from this discussion . This code can be well improved.

 25
Author: Maniero, 2020-09-11 19:10:48