|Fundamental C - String I/O|
|Written by Harry Fairhead|
|Monday, 27 June 2022|
Page 1 of 2
This extract, from my book on programming C in an IoT context explains that strings are not so user friendly after all. You need to know how to get strings from the outside world and convert them to C data types.
Fundamental C: Getting Closer To The Machine
Now available as a paperback and ebook from Amazon.
Also see the companion volume: Applying C
This is going to be a shock if you program in almost any other language - C doesn’t actually have strings in the sense of most languages. All it has are char arrays and a few conventions on how these are used. It is still important to know how these work and there are some extra features over and above a simple array.
In Chapter but not in this extract
Convert to String - sprintf
You already know how to convert a bit pattern to a human readable string using printf. The string function sprintf – string print formatted – works in exactly the same way but it returns a string rather than printing the string.
All of the format strings work with sprintf the only real difference is that it returns a string.
sprintf(myString,"The result = %10d",1234);
If you are worried about the function returning a string, notice that you have to supply a string that has enough storage to store the result. The example really should be:
char myString; sprintf(myString,"The result = %10d",1234);
The result is a formatted string exactly as you see printed stored in myString. You might not see the full reason for sprintf at the moment, but it is very useful if you are working with any sort of non-standard display and need to get a character representation to send to it. More generally you can use it as a way of converting any data type into a string which can be further processed.
There are also some simpler functions which convert particular data types into strings without any format specification. See later.
Input – Buffer Problems
It is also worth knowing that the scanf function will read in a string from standard input device, usually the keyboard, using a format string that is the same as printf. The user is expected to supply the data that would otherwise come from the variables in a printf.
For example, to get the user to enter some characters as a string you would use:
Most introductions to C explain how this can be used to get input and show examples that often don’t work as expected. There are a number of significant problems with scanf and indeed with trying to get input from a user.
The biggest problem is that if you are running C under a full operating system then the input from the keyboard will generally be buffered. That is, as the user types on the keyboard the character codes are stored in a buffer even if you aren’t using the input. When scanf is used in your program it reads from the buffer rather than interacting with the keyboard directly.
It is also worth knowing that your output sent to the display device is also buffered and it only appears on the screen when you send a newline or when the program terminates. This too often causes problems as you wonder why what you have “printf-ed” to the screen isn’t appearing.
Consider the following simple program:
char myString; printf("What is your name"); scanf("%s",myString); printf("Hi %s",myString);
The intent is that the user sees the “What is your name” prompt and then types a reply. Under most systems, including Windows and Linux, the program just seems to hang. The reason is that the message goes into the output buffer and just sits there. If there is nothing in the input buffer the scanf also just waits for something to be typed. The user has no indication that they should type anything. If they do type anything then nothing happens until they press return once or perhaps twice and then you see the question and the answer as the program comes to an end and the output buffer is flushed.
There are many ways to solve the problem, but by far the most common is to use the system specific fflush(stdin) and fflush(stdout) which empty the buffers concerned under many operating systems.
So if you try the program using fflush:
char myString; printf("What is your name"); fflush(stdout); fflush(stdin); scanf("%s",myString); printf("Hi %s",myString);
you will see the message appear, and you will be able to type in a name. However, you might not see what you type and you might have to enter two returns to make it work.
Whether or not you see what you type depends on the console your program is using and whether or not it has echo on or off. If echo is off then you will not see what you type. Under NetBeans the internal console doesn’t echo what you type. To turn echo on right-click on the project and select Properties. Under the Run tab select Standard Output for Console type. Now you will be able to see what you type in response to a scanf.
Another problem with using scanf is that the format strings fail at the first mismatch and this leaves characters in the buffer to confuse the next attempt at reading. The %s format specifier only reads until the first white space character, which means including spaces in names, say, causes it to stop. What is worse is that a white space doesn’t stop the scanf reading data from the buffer – after all there might be another format specifier. Many of the format specifiers skip input characters rather than give up trying to read data.
will work as expected if you type 123 return, say, but if you type something other than numbers, including a blank line, then the machine will generally just appear to hang. The reason is that %d will skip as many white space characters, including carriage return, until it finds some digits and a return.
There are many more “gotchas” in using scanf and it would take a chapter dedicated to the subject to list them all, but you can usually understand what is happening by finding out exactly what a format specifier is looking for and by remembering that you are working with a buffer.
In most cases it is better to avoid using scanf to get input from a user. You will often hear the advice – don’t use scanf. In fact this is too extreme. When it comes to reading in formatted data stored in a file or stream, scanf can be useful. The reason is that a file or stream generally has a clear fixed format and you can tailor the scanf format to suit. Also if anything goes wrong you can often back up and try again.
It is also worth commenting that, for low-level applications, input from the keyboard is generally not an issue because there is no keyboard. For higher-level applications there might well be a keyboard, but generally you need some more advanced form of UI and for this you need a library or a framework – ncurses for console and Qt say for a full GUI. These generally have their own I/O functions. However, for working with keyboard input, we need an alternative method of dealing with user input.
|Last Updated ( Monday, 27 June 2022 )|