Input buffer to get a an input, C programming - c

I'm in my first steps in C programming, and I came across a task I can not find a solution to.
The task is simple: taking a character from the user.
After that, you receiving a string from the user until the user types the * character.
Then print the number of times the user typed the first character.
I was able to solve the problem using char [SIZE]ת when I placed a maximum input size of 255 bytes (#define SIZE 255).
Nevertheless, my teacher tells me that although the solution is working well, this was not the purpose of the exercise, also, I can not assume a maximum string size.
He asks us to use the input buffer.
No dynamic memory allocation is used in the exercise, and only the stdio.h library is allowed.
I read a lot about the input buffer, but I still have not found the possibility to solve the exercise - how can I absorb value from the user without knowing its size?
I would be happy to receive assistance and tips on how to use the input buffer correctly.
Or more focused, how to input values (string of characters) into the input buffer, and then go over each character separately in this string and process it.
Thank You

There is no need to store all characters. Once you have read a character you can throw it away and just increase a counter. Something like this:
#include <stdio.h>
int main() {
char c, first;
int counter=0;
printf("Enter first character: ");
scanf("%c", &first);
do {
scanf("%c", &c);
if(c == first)
counter++;
} while (c != '*');
printf("You entered '%c' %d times\n", first, counter);
}
Output:
Enter first character: a
aaaaa*
5
or
Enter first character: a
aabbaa*
You entered 'a' 4 times
Note:
As been pointed out in the comments, scanf is not a good tool for this kind of stuff. I would advice against the usage of it, unless you know it is the right tool. But that's beside the point. The point here was to show you that you don't need to store the whole input buffer. If you want to look at alternate input methods (as William Pursell suggested in the comments) you could have a look at fgetc, getc, or getchar for reading single characters. fread is also a tool you should get familiar with.

Related

Reason for use of a buffer instead of directly using the scanf function for the integer

So I have this piece of code which is written for reading the user input which is supposed to be between the numbers 1-9. In the code there is and int "choice" declared. But instead of directly scanning the user input using scanf("%d", choice); the programmer has used a char buffer and scanned the buffer instead and then used the atoi function to convert the char input to an integer. I'm confused why has it been done like that instead of directly doing it the easy way. My assumption is that the programmer has done this so that if the user enters a character instead of a number, the code doesn't malfunction. But if that's the case then how would the atoi convert an alphabet to an integer? Here's the code:
int readMenuChoice() {
while (1) {
char buffer[50];
size_t buffLen = 10;
int choice;
showMenu(); //another function that displays all options from 1 to 9
printf("Choose a menu option: ");
scanf("%[^\n]", buffer);
getchar();
choice = atoi(buffer);
if (choice > 0 && choice < 9) {
return choice;
}
printf("Invalid input\n\n");
}
}
We can only guess intention from the coder.
But a pretty likely reason is to make sure that the input stream is empty between each input. I personally do things like that too. But I would have done like this instead:
while (1) {
char buffer[50];
int choice;
showMenu();
printf("Choose a menu option: ");
if(!fgets(buffer, sizeof buffer, stdin)) {
/* Handle error */
}
if(sscanf(buffer, "%d", &choice) != 1) {
/* Handle error */
}
if (choice > 0 && choice < 9) {
return choice;
}
printf("Invalid input\n\n");
}
atoi is an unsafe function. If the argument cannot be parsed to a number, it invokes undefined behavior. And since x = atoi(s) is completely equivalent to sscanf(s, "%d", &x), there's no reason to use the unsafe function. sscanf returns the number of successful assignments, so it CAN be error checked.
The problem of reading user input safely, limiting the input to a certain set of "allowed" inputs, while cleanly disregarding "disallowed" inputs, can be a surprisingly tricky one.
Also surprising, perhaps, is how poor a function scanf is for performing this task, and how difficult it is to solve the problem completely using any algorithm built around scanf.
You asked why this code didn't "directly do it the easy way". By "the easy way" I assume you mean something like
scanf("%d", &choice);
The problem here is that, yes, it can be remarkably difficult to proceed correctly if the user types some non-numeric input.
There are two general avenues to take when trying to handle the possibility that the user types something wrong:
Continue to call scanf("%d") to read the input, but then, try to patch things up if scanf fails. (Obviously the first step here is to check scanf's return value.)
Read a line of input, as text, using something other than scanf. Then attempt to validate that line, and convert it to the desired form.
In my opinion, there is only one choice here, and it is #2. This answer will become far too long if I discuss all the reasons, but the bottom line is that approach #1 is futile. The scanf function has one virtue and one virtue only, and that is that a call like scanf("%d", &choice) is indeed very simple. But the error handling is almost useless. By the time you've built up a reasonable amount of error handling around it, the amount of work you'll have had to do is about three times as much as for approach #2, and you still won't have fully satisfactory results.
So most experienced C programmers will agree that #2 is the only viable approach in the long run. There's a central question advising on good ways of doing input using something other than scanf.
The problem with the code you've posted, IMO, is that it manages to combine the worst of both worlds. It does try to read a line of input as text, then process it later, but the way it reads that line of input is with... the dreaded scanf! And despite trying to be careful in several other ways, this code doesn't even check scanf's return value, so there are some classic problems (like premature EOF) that this code is still vulnerable to.
This code also contains a mysterious extra call to getchar, which is typical of scanf-using code, since stray newlines are almost always a problem.
This code also uses %[...], which is my least favorite scanf format. As I said, scanf's only virtue is simplicity, but a locution like "%[^\n]" is anything but simple. Yes, I know what it does, but IMO it completely defeats the purpose of using scanf for dirt-simple (if less than robust) user input.
But, yes, the primary intent of writing the code this way is probably "so that if the user enters a character instead of a number, the code doesn't malfunction". The code reads a line of text, as text, then attempts to convert the text to a number. You asked what the atoi function does with alphabetic input, and the answer is that (most of the time, anyway) it quietly returns 0. Since 0 isn't a valid input, this code will reject it, so in that sense it works.
To improve this function, the first thing to do would be to replace the calls to scanf and getchar with fgets. The next thing to do would be to replace atoi with strtol. And then it wouldn't be too bad.

Checking if input is a ENTER without losing the first character in C

I have a program with alot of data stored in a file and gets loaded into structs.
I have an option so the user can change some information but since I don't know what he wants to change I need to printf and scanf all the information of the item he wants to change.
This is a part of the program:
char check;
if(p->vetor.id == jogo){
printf("Reference: %d\n", jogo);
fflush(stdin);
printf("\nTeam 1: ");
if(getchar() != '\n'){ // METHOD 1
gets(p->vetor.eqTeam1);
}
fflush(stdin);
printf("\nTeam 2: ");
if(scanf("%c", &check) && check != '\n'){ //METHOD 2
gets(p->vetor.eqTeam2);
}
fflush(stdin);
}
It checks if the input is a ENTER (and it works) but when I write something there it "eats" the first letter because it needs to check before if is a ENTER or not, is there a way to give the lost letter back to the gets() ?
Thanks for your help.
It checks if the input is a ENTER (and it works) but when I write something there it "eats" the first letter because it needs to check before if is a ENTER or not, is there a way to give the lost letter back to the gets() ?
The function ungetc() is probably what you're looking for.
However, cleaning input buffers is a recurrent topic in C. Be aware that fflush(stdin) is a Undefined Behavor, because it actually makes no sense : flushing a buffer doesn't drop its content, it actually triggers its immediate shipping toward its final destination, which is, in case of an input buffer… yourself !
Some systems take advantage of this non-defined behavour situation to actually drop it as expected (which is an undefined behavour just like anything else), but this is a trap because the programmer get used of doing something that is not supposed to work. To my eyes, the most consistent behavor here is to do nothing, since the buffer's content is already available to the reader.
Don't use scanf and never again use gets.
Your problem can be solved by just using fgets
printf("\nTeam 2: ");
fflush(stdout);
char input[256]; // same size of eqTeam
fgets(input, sizeof(input), stdin);
if (input[0] != '\n') {
strcpy(p->vetor.eqTeam2);
}
This will always read in a full line, but if the first character of the line is a newline, the user just pressed enter. If the first char is something else, the input is copied to the correct location. Note that the input buffer must be of a suitable size, here I just guessed one that is for sure not correct (but I lack the necessary info)
And one more thing, never flush stdin, you have to fflush(stdout) as fflush is an output operation.

Replacing gets with scanf in simple equation crashes the program

I'm working through C for Dummies. It has an example code for converting inches to cm (p.135, if you have the text) using gets and atoi.
Now, I wanted to try using scanf rather than the dreaded gets, and this is the best I could come up with (based on the code the author provided).
#include <stdio.h>
#include <stdlib.h>
int main()
{
float height_in_cm;
char height_in_inches;
printf("Enter your height in inches: ");
scanf("%c"),&height_in_inches;
height_in_cm = atoi(height_in_inches)*2.54;
printf("You are %.2f centimetres tall.\n",height_in_cm);
return(0);
}
The program starts, but after input just crashes. Where am I going wrong?
Why spend time converting the answer when scanf() can do it for you?
#include <stdio.h>
int main(void)
{
float height_in_inches;
printf("Enter your height in inches: ");
if (scanf("%f", &height_in_inches) == 1)
{
float height_in_cm = height_in_inches * 2.54;
printf("You are %.2f inches or %.2f centimetres tall.\n",
height_in_inches, height_in_cm);
}
else
printf("I didn't understand what you said\n");
return(0);
}
If you must read a string, then use fgets():
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char line[4096];
printf("Enter your height in inches: ");
if (fgets(line, sizeof(line), stdin) != 0)
{
double height_in = strtod(line, 0);
double height_cm = height_in * 2.54;
printf("You are %.2f inches or %.2f centimetres tall.\n",
height_in, height_cm);
}
return(0);
}
Note that both programs check that input occurred before using the results of the input. You can argue that the error checking for the call to strtod() is woefully lackadaisical; I'd agree. Note that I switched between float in the first fragment and double in the second; either can be made to work. I see no particular reason to limit the input to an integer value when the result will be a fraction. It is also often beneficial to echo the input as well as the output; if what you get echoed isn't what you think you entered, it is a good hint that something is horribly wrong and sends you searching in the right area of the code.
Note: there are a number of minor details brushed under the carpet, especially in the first example regarding float and double with scanf() and printf(). Given the comment below, they are not relevant to the OP at the moment.
Minimal fixes to original code
Since the code above is more complex than the OP recognizes yet, here is a simpler set of fixes to the original code. The string input into an array (string) is the key point; that necessitated changes in the scanf() call too.
By using a big buffer, we can assume that the user won't be able to overflow the input by typing at the terminal. It would not be OK for machine-driven inputs, though.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float height_in_cm;
char height_in_inches[4096]; // Array, big enough to avoid most overflows
printf("Enter your height in inches: ");
// Missing error check on scanf() — too advanced as yet
scanf("%s", height_in_inches); // Format specifier, parentheses, ampersand
height_in_cm = atoi(height_in_inches) * 2.54;
printf("You are %s inches or %.2f centimetres tall.\n",
height_in_inches, height_in_cm);
return(0);
}
How long is a line of input?
user3629249 commented:
a LOT of stack space can be saved by:
noticing that an 'int' is only a max of 12 characters so the max length on the input buffer is 13 characters (to allow for the NUL string termination byte)
limit the scanf() to 12 characters. I.E. 'scanf( "%12s", myCharArray );
in C, the name of an array degrades to the address of the array, so not leading '&' needed on 'myCharArray'.
Point 3 is correct; if you use char myCharArray[13];, you do not use &myCharArray when calling scanf() et al; you use just myCharArray. A good compiler will point out the error of your ways if you misuse the &.
I have problems with points 1 and 2, though. A lot of trouble can be avoided by noting that if the user types 9876432109876543210 on the line, then using scanf() with %12s is not going to help very much in eliminating invalid inputs. It is going to leave 8 unread digits on the line, and what is read will still overflow a 32-bit integer. If you use the strtoX() family of functions on longer strings instead of atoi(), then they detect problems such as overflow, which neither scanf() with %d nor atoi() do. (This is one of the many points glossed over in the main answer.)
Also, on systems with megabytes, and usually gigabytes of main memory, 4 KiB on a stack is not a major problem. That said, I use 4 KiB in part for its shock value; but POSIX requires a minimum value of [LINE_MAX] of 2048.
If you are reading line-based inputs, which is usually a good way of doing input in command-line applications, then you want to make sure you read the whole line because futzing around with part lines is messy and makes error reporting hard. One major advantage of fgets() plus sscanf() processing is that you have a complete line which you can use in the error report, rather than what scanf() left after processing part of the line. You can also try scanning the string a different way if the first attempt fails; you can't do that with the direct file I/O functions in the scanf() family.
If you naïvely do not recognize that people type long lines when you intended them to type short lines, then you can get leftovers served as a new line — without further user interaction — when it is really the dregs of the previous line of input. For example, if you scan 12 digits out of 20, then the next input will get the remaining 8 digits without waiting for the user to type anything new, even though you prompted them for more input. (Also, beware of using fflush(stdin); it is at best system-specific whether it does anything useful.)
I used fgets() with a 4 KiB buffer. If you want to be safe against programs sending megabytes of JSON-encoded data on a single line, you need to use POSIX's getline() function to read the line. It allocates enough space for the whole line, unless it runs out of memory. For most student practice work, a 4 KiB buffer and fgets() is a reasonable surrogate. I'm willing to negotiate on the power of 2 used as long as the exponent is at least 8 — the value is at least 256. Limiting the line buffer to 80 characters, for instance, doesn't stop the user from entering more than 80 characters on a line. It just means that the extra characters are unlikely to be processed appropriately. Limiting the buffer to 13 characters doesn't buy you anything worthwhile, IMO, and 'saving stack space' is a premature optimization.
You are having troubles with a cast.
atoi accepts a const char* as input.
You are passing a char so it is implicitly casting the char to a point, bad bad thing.
As suggested by user3121023 change height_in_inches into a string.
char height_in_inches[20];
and read using %s
scanf("%s", height_in_inches);

Whats wrong with my SIMPLE C program?

I am writing a super simple command line based program in C. It's just a small test and the code is very simple. So what it is meant to do is to ask the user for their name, maths grade, english grade, computing grade. Then it figures out their average grade and also tells them the name they entered. Yes I know this is an extremely simple program, but I'm still doing something wrong.
The problem is, one part of my code will run first telling the user to enter their name and then once they do this and press enter the rest of my code will run all at once and then stop working. It's weird I just don't understand what is wrong.
#include <stdio.h>
int main(int argc, const char * argv[])
{
char chr;
char firstname;
int mathsmark, englishmark, computingmark, averagemark;
printf("What is your name?\n");
scanf("%c", &firstname);
printf("\n");
printf("What is your maths mark?\n");
scanf("%d", &mathsmark);
printf("\n");
printf("What is your english mark?\n");
scanf("%d", &englishmark);
printf("\n");
printf("What is your computing mark?\n");
scanf("%d", &computingmark);
printf("\n");
printf("Your name is: %c", firstname);
printf("\n");
averagemark = (mathsmark + englishmark + computingmark) / 3;
printf("%d", averagemark);
printf("\n");
chr = '\0';
while (chr != '\n') {
chr = getchar ();
}
return 0;
}
One major problem is that you've declared firstname to be a single character long, and when you try to read the name from the console, you're using the %c conversion specifier, which reads the next single character from the input stream and stores it to firstname. The remainder of the name is left in the input stream to foul up the remaining scanf calls.
For example, if you type "Jacob" as a first name, then the first scanf call assigns J to firstname, leaving "acob\n" in the input stream.
The next scanf call attempts to convert "acob\n" to an integer value and save it to mathsmark, which fails ("acob\n" is not a valid integer string). Same thing happens for the next two scanf calls.
The last loop
while (chr != '\n')
{
chr = getchar();
}
finally consumes the rest of "acob\n", which contains the newline character (because you hit Enter after typing the name), causing the loop and program to exit.
How do you fix this?
First, you need to declare firstname as an array of char:
char firstname[SOME_SIZE] = {0};
where SOME_SIZE is large enough to handle all your cases. The you need to change scanf call to
scanf("%s", firstname);
This tells scanf to read characters from the input stream up to the next whitespace character and store the results to the firstname array. Note that you don't need to use the & operator here; under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array.
Note that scanf is not very safe, and it's not very robust. If you enter more characters than your buffer is sized to hold, scanf will happily store those extra characters to memory following the array, potentially clobbering something important. You can guard against this by using an explicit field width in the conversion specifier, like
scanf(*%29s", firstname);
but in general it's a pain.
scanf is also not very good at detecting bad input. If you enter "12er" as one of your marks, scanf will convert and assign the "12", leaving the "er" in the stream to foul up the next read.
scanf returns the number of successful assignments, so one way to guard against bad input is to check the return value, like so:
if (scanf("%d", &mathmarks) != 1)
{
printf("Bad input detected for math marks\n");
}
Unfortunately, scanf won't remove bad characters from the stream; you'll have to do that yourself using getchar or similar.
This is a common mistake amongst newer C/C++ developers. The scanf function detects you hitting the ENTER/RETURN key to signal the end of input, but it also catches the \n character as well at the end of the input string, so you essentially get two RETURNS being detected.
Please read up on an example of using fgets and sscanf here:
http://www.linuxforums.org/forum/programming-scripting/67560-problem-scanf.html
It will resolve this issue very quickly for you. In the meantime, I strongly urge you to check out this book:
http://www.amazon.com/Primer-Plus-5th-Stephen-Prata/dp/0672326965
It is the most commonly used C programming book in high school and colleges in North America, and has TONS of examples for you to work through, including this specific program you demonstrated above. The print version has more examples than the e-book, so I would just cough up the $30.00 for the printed version.
Good luck!
You might want to look at a few tutorials. Maybe one on Format specifiers and one on strings in C
scanf() reads data from stdin and stores them as specified by the format specifiers. In this case:
char firstname;
scanf("%c", &firstname);
Read 1 character from stdin and store it to firstname:
>> What is your first name?
Mike
Now firstname == 'M' because scanf() read 1 character as we requested.
What you wanted to do was read a string (a bunch of characters):
char firstname[5]; // an array of characters
scanf("%s", firstname); // store as a string
firstname[4] = '\0'; // Truncate the result with a NULL to insure no overflow
>> What is your first name?
Mike
Now firstname is [M][i][k][e][\0] because scanf() read 1 string, as we requested.
Note the same holds true for printf(), a printf with a %c will give you one character where as a printf() with a %s will give you all the characters until the NULL terminator.
You have (at least) two choices.
char firstname[number_big_enough_to_hold_long_name];
/*or */
char *firstname = malloc(sizeof(char) * number_big_enough_to_hold_long_name);
/* ... code ... */
free(firstname);
Further it would be best to limit width of read. scanf() does not know the size (available space) of firstname.
scanf("%number_big_enough_to_hold_long_names", ...
/* i.e. */
char firstname[32];
if(scanf("%31s", firstname) == EOF) {
perror("bad");
return 1;
}
Further you should check if there is anything left before trying next read. I.e. If someone enters "My Name" then only "My" will end up in firstname and "Name" will be left in input stream.
And getchar() returns an int not a char.
getchar
scanf
And search "ansi c char arrays tutorial" or similar.

Why do I have to repeat an intro sentence?

I wan to read two char so I do the following code:
main() {
char a,b;
printf("\nEnter the first char.. ");
a=getchar();
printf("\nEnter the second char.. ");
b=getchar();
b=getchar(); //<--I've to add this sentence because the previously doesn't work
printf("\nFirst char --> %c",a);
printf("\nSecond char --> %c",b);
}
The code should not work but it does. The output is the correct:
First char --> z
Second char --> z ('z' or the char there I wan to)
If I remove the second getchar() then the output is:
First char --> z
Second char --> (Here there is no char)
How can I remove the second getchar() without get any error?
Because fflush(stdin) before getchar() doesn't work.
Try this: make a file data, two bytes in size containing precisely ab. Now say:
./myprogram < data
And voila.
The point is that when you operate your terminal and press a followed by the enter key, you are sending two characters to the process, first a and then \n, the newline. So the second getchar picks up the newline.
(And your terminal does not permit you to send individual characters without pressing Enter, since it has a line buffer that it fills up before sending anything.)
In short, getchar is a poor I/O primitive, and you should almost always prefer fgets to read entire lines and process those.
As indicated by the other answers, the problem was caused by the carriage return.
There are many ways solve this, some more complex than others. Therefore I will indicate the simplest method I've found:
As the GNU website indicate the most appropriate function for this is getc(stream) and I quote:
This is just like fgetc, except that it is permissible (and
typical) for it to be implemented as a macro that evaluates the stream
argument more than once. getc is often highly optimized, so it is
usually the best function to use to read a single character.
I put it into practice but it still have the CR problem, so I printed the result of this function and notice that it return 10 when CR.
After this I tried to get functionality and clarity for the code. Doing everything possible for this, now my code is the following:
main() {
char a,b;
printf("\nEnter the first char.. ");
if ((a=getc(stdin))==10) a=getc(stdin);
printf("\nEnter the second char.. ");
if ((b=getc(stdin))==10) b=getc(stdin);
printf("\nFirst char --> %c",a);
printf("\nSecond char --> %c",b);
}
And the nice output:
First char --> z
Second char --> z ('z' or the char there I wan to)
I've learned that all the programs need they own solution, different than the others, and that is the reason (I think) for that are so many functions. What I can say is "Always have to adapt the program. Maybe this sentence works for me but is not guaranteed that gonna work for other codes."
Thanks to all the guys that helped me!
It sounds like your getchar() function leaves the newline character in the keyboard buffer. This means the first b=getchar(); reads a newline character and the second one reads the actual input you expect. A more elegant approach would be to ignore the newline character if you have an ignore() function available.
getchar() only gets one char. newline takes one character, ergo you need the extra getchar() in your code to get the desired input/output.

Resources