Converting input numerical strings to integers in C - c

I am trying to convert numerical strings inputs to integer. When I type 2 my output is 0
scanf( "%d", betNumber );
printf("What number do you want to bet? \n");
printf("Here is your number: %d\n" ,atoi(betNumber));
User input = 2 or 3 or 5
Output = always 0

You should never use the *scanf family, nor atoi and friends. The correct way to write this code is
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
char inbuf[80], *endp;
unsigned long bet; /* negative bets don't make sense */
puts("What number do you want to bet?");
if (!fgets(inbuf, sizeof inbuf, stdin))
return 1; /* EOF - just quit */
errno = 0;
bet = strtoul(inbuf, &endp, 10);
if (endp == inbuf || *endp != '\n' || errno) {
fputs("invalid number entered, or junk after number\n", stderr);
return 1;
}
printf("Here is your number: %lu\n", bet);
return 0;
}
Some exposition, perhaps:
The only sane way to read input from the user in C is an entire line at a time. If you don't, you are very likely to get in trouble when, not if, the user types more input than you expected. The ideal way to do this is with getline, but many C libraries do not have it, and it does make you remember to free the line-buffer. Failing that, fgets is good enough for many purposes, as shown here.
The only correct way to convert text to machine numbers in C is with the strto* family of functions. I use the word correct very deliberately. All the alternatives either silently ignore numeric overflow (ato*) or, worse, trigger undefined behavior on numeric overflow (*scanf). The usage pattern for strto* is a little tricky, but once you get used to it, it is just boilerplate to be memorized and typed. I'll take it apart for you:
errno = 0;
It is necessary to clear errno manually before calling strto*, because a syntactically valid number that overflows the range of the return value is reported only by setting errno, but success does not clear errno. (The manpage says that a particular numeric value is returned, but that value could have resulted from correct input, so that's no help.)
bet = strtoul(inbuf, &endp, 10);
When this function call returns, bet will be the number you wanted, and endp will be set to the first character in inbuf that is not a digit.
if (endp == inbuf || *endp != '\n' || errno) { /* error */ }
If endp equals inbuf, that means there were no digits, which is usually not considered a valid number.
If *endp is not equal to '\n', that means either there was something else on the line after the number, or fgets did not read the whole line; in either case, again, the input is not as expected. (All 64-bit unsigned numbers fit in fewer than 80 characters.)
And if errno is nonzero, numeric overflow occurred.

I suggest you not use scanf, nor any of it's disreputable coterie of insidious companions. Use strtol. Easier to get your head around and less error prone. atoi is a less-safe equivalent of strtol.
But... atoi takes a pointer to char. So if this compiles...
printf("Here is your number: %d\n" ,atoi(betNumber));
...then betNumber must be:
char betNumber[100];
...or something like that. Which explains what's wrong with the call to scanf.
scanf("%d", p) expects that you'll be passing it a pointer to int, not a pointer to char. It reads text from standard input, converts it to an integer, and assigns it to the int variable -- or what it assumes must be an int variable -- that the pointer is pointing to. There is no type checking there, there can't be. The compiler can't tell that you passed the wrong thing (a C compiler could be written to validate scanf's arguments against the format string, but the general tendency with C compilers has always been to politely let you shoot yourself in the foot (modulo gcc -Wall, thanks #Zack), and rightly so).

If you use scanf() properly, such as
int betNumber;
scanf("%d", &betNumber);
then after scanf() returns successfully, the value of betNumber already is an integer, you do not need to convert it anymore.

scanf and atoi both take a pointer to some previously allocated storage. Here's a working example:
int betNumber;
printf("What number do you want to bet?\n");
scanf("%d", &betNumber);
printf("Here is your number: %d\n", betNumber);

Related

if my scanf variable is a float and a user inputs a character how can i prompt them to input a number? assuming the scanf is inside a do while loop

i have tried to use k = getchar() but it doesn't work too;
here is my code
#include<stdio.h>
int main()
{
float height;
float k=0;
do
{
printf("please type a value..\n");
scanf("%f",&height);
k=height;
}while(k<0);// i assume letters and non positive numbers are below zero.
//so i want the loop to continue until one types a +ve float.
printf("%f",k);
return 0;
}
i want a if a user types letters or negative numbers or characters he/she should be prompted to type the value again until he types a positive number
Like Govind Parmar already suggested, it is better/easier to use fgets() to read a full line of input, rather than use scanf() et al. for human-interactive input.
The underlying reason is that the interactive standard input is line-buffered by default (and changing that is nontrivial). So, when the user starts typing their input, it is not immediately provided to your program; only when the user presses Enter.
If we do read each line of input using fgets(), we can then scan and convert it using sscanf(), which works much like scanf()/fscanf() do, except that sscanf() works on string input, rather than an input stream.
Here is a practical example:
#include <stdlib.h>
#include <stdio.h>
#define MAX_LINE_LEN 100
int main(void)
{
char buffer[MAX_LINE_LEN + 1];
char *line, dummy;
double value;
while (1) {
printf("Please type a number, or Q to exit:\n");
fflush(stdout);
line = fgets(buffer, sizeof buffer, stdin);
if (!line) {
printf("No more input; exiting.\n");
break;
}
if (sscanf(line, " %lf %c", &value, &dummy) == 1) {
printf("You typed %.6f\n", value);
continue;
}
if (line[0] == 'q' || line[0] == 'Q') {
printf("Thank you; now quitting.\n");
break;
}
printf("Sorry, I couldn't parse that.\n");
}
return EXIT_SUCCESS;
}
The fflush(stdout); is not necessary, but it does no harm either. It basically ensures that everything we have printf()'d or written to stdout, will be flushed to the file or device; in this case, that it will be displayed in the terminal. (It is not necessary here, because standard output is also line buffered by default, so the \n in the printf pattern, printing a newline, also causes the flush.
I do like to sprinkle those fflush() calls, wherever I need to remember that at this point, it is important for all output to be actually flushed to output, and not cached by the C library. In this case, we definitely want the prompt to be visible to the user before we start waiting for their input!
(But, again, because that printf("...\n"); before it ends with a newline, \n, and we haven't changed the standard output buffering, the fflush(stdout); is not needed there.)
The line = fgets(buffer, sizeof buffer, stdin); line contains several important details:
We defined the macro MAX_LINE_LEN earlier on, because fgets() can only read a line as long as the buffer it is given, and will return the rest of that line in following calls.
(You can check if the line read ended with a newline: if it does not, then either it was the final line in an input file that does not have a newline at the end of the last line, or the line was longer than the buffer you have, so you only received the initial part, with the rest of the line still waiting for you in the buffer.)
The +1 in char buffer[MAX_LINE_LEN + 1]; is because strings in C are terminated by a nul char, '\0', at end. So, if we have a buffer of 19 characters, it can hold a string with at most 18 characters.
Note that NUL, or nul with one ell, is the name of the ASCII character with code 0, '\0', and is the end-of-string marker character.
NULL (or sometimes nil), however, is a pointer to the zero address, and in C99 and later is the same as (void *)0. It is the sentinel and error value we use, when we want to set a pointer to a recognizable error/unused/nothing value, instead of pointing to actual data.
sizeof buffer is the number of chars, total (including the end-of-string nul char), used by the variable buffer.
In this case, we could have used MAX_LINE_LEN + 1 instead (the second parameter to fgets() being the number of characters in the buffer given to it, including the reservation for the end-of-string char).
The reason I used sizeof buffer here, is because it is so useful. (Do remember that if buffer was a pointer and not an array, it would evaluate to the size of a pointer; not the amount of data available where that pointer points to. If you use pointers, you will need to track the amount of memory available there yourself, usually in a separate variable. That is just how C works.)
And also because it is important that sizeof is not a function, but an operator: it does not evaluate its argument, it only considers the size (of the type) of the argument. This means that if you do something silly like sizeof (i++), you'll find that i is not incremented, and that it yields the exact same value as sizeof i. Again, this is because sizeof is an operator, not a function, and it just returns the size of its argument.
fgets() returns a pointer to the line it stored in the buffer, or NULL if an error occurred.
This is also why I named the pointer line, and the storage array buffer. They describe my intent as a programmer. (That is very important when writing comments, by the way: do not describe what the code does, because we can read the code; but do describe your intent as to what the code should do, because only the programmer knows that, but it is important to know that intent if one tries to understand, modify, or fix the code.)
The scanf() family of functions returns the number of successful conversions. To detect input where the proper numeric value was followed by garbage, say 1.0 x, I asked sscanf() to ignore any whitespace after the number (whitespace means tabs, spaces, and newlines; '\t', '\n', '\v', '\f', '\r', and ' ' for the default C locale using ASCII character set), and try to convert a single additional character, dummy.
Now, if the line does contain anything besides whitespace after the number, sscanf() will store the first character of that anything in dummy, and return 2. However, because I only want lines that only contain the number and no dummy characters, I expect a return value of 1.
To detect the q or Q (but only as the first character on the line), we simply examine the first character in line, line[0].
If we included <string.h>, we could use e.g. if (strchr(line, 'q') || strchr(line, 'Q')) to see if there is a q or Q anywhere in the line supplied. The strchr(string, char) returns a pointer to the first occurrence of char in string, or NULL if none; and all pointers but NULL are considered logically true. (That is, we could equivalently write if (strchr(line, 'q') != NULL || strchr(line, 'Q') != NULL).)
Another function we could use declared in <string.h> is strstr(). It works like strchr(), but the second parameter is a string. For example, (strstr(line, "exit")) is only true if line has exit in it somewhere. (It could be brexit or exitology, though; it is just a simple substring search.)
In a loop, continue skips the rest of the loop body, and starts the next iteration of the loop body from the beginning.
In a loop, break skips the rest of the loop body, and continues execution after the loop.
EXIT_SUCCESS and EXIT_FAILURE are the standard exit status codes <stdlib.h> defines. Most prefer using 0 for EXIT_SUCCESS (because that is what it is in most operating systems), but I think spelling the success/failure out like that makes it easier to read the code.
I wouldn't use scanf-family functions for reading from stdin in general.
fgets is better since it takes input as a string whose length you specify, avoiding buffer overflows, which you can later parse into the desired type (if any). For the case of float values, strtof works.
However, if the specification for your deliverable or homework assignment requires the use of scanf with %f as the format specifier, what you can do is check its return value, which will contain a count of the number of format specifiers in the format string that were successfully scanned:
§ 7.21.6.2:
The [scanf] function returns the value of the macro EOF if an input failure occurs
before the first conversion (if any) has completed. Otherwise, the function returns the
number of input items assigned, which can be fewer than provided for, or even zero, in
the event of an early matching failure.
From there, you can diagnose whether the input is valid or not. Also, when scanf fails, stdin is not cleared and subsequent calls to scanf (i.e. in a loop) will continue to see whatever is in there. This question has some information about dealing with that.

Why does comparing the result of scanf() with NULL generate a compiler warning?

I'm writing in C and I need to read everything that arrives in input but I don't know how many characters I will receive. I wrote
while (scanf("%c", &read) != NULL)
but the compiler tells me: [Warning] comparison between pointer and integer, so what should I write instead?
Instead, of scanf("%c", &read) you may consider read = getc(stdin).
Please, be aware that getc()/fgetc() return int.
This allows to store any character as number in range [0, 255] as well as to return EOF (usually -1) in case of failure.
So, with getc() it would look like:
int read;
while ((read = getc(stdin)) != EOF)
Note:
You may assign read to a variable of type char – it will be implicitly converted. In case of getc() succeeded, there shouldn't be any data loss in this implicit conversion.
A little sample to show this at work:
#include <stdio.h>
int main(void)
{
enum { N = 10 };
char buffer[N];
/* read characters and print if buffer ful */
int read, n = 0;
while ((read = getc(stdin)) != EOF) {
if (n == N) {
printf("%.*s", N, buffer); n = 0;
}
buffer[n++] = read;
}
/* print rest if buffer not empty */
if (n > 0) printf("%.*s", n, buffer);
/* done */
return 0;
}
Note:
The read characters are stored in buffer without a termination '\0'. This is handled in printf() respectively by the formatter %.*s meaning string with max. width * where width and string are read as consecutive arguments.
Live Demo on ideone
Your
scanf("%c", &read) != NULL
is a typing mistake : the types of left and right operands to != don't match. Read about type systems.
Read the documentation of scanf. It says that scanf returns some int value.
But NULL is a pointer value (it is (void*)0).
How can a pointer be meaningfully compared to an int? On my Debian/x86-64, they don't even have the same size (as returned by sizeof): a pointer takes 8 bytes but an int takes 4 bytes.
So the compiler is right in warning you.
You probably want to code instead something like while (scanf("%c", &read) >0) or even while (scanf("%c", &read) == 1) since for a successful scan of "%c" the scanf function is documented to give 1.
Of course, in that particular case, using fgetc is better (more readable, and probably slightly faster). Read documentation of fgetc and follow the advice given by Sheff's answer.
Next time:
be sure to read the documentation of every function that you are using. Never use a function whose documentation you have not read and understood.
ask the compiler to give all warnings and debug info, so with GCC compile with gcc -Wall -Wextra -g. Trust your compiler, and improve your code to get no warnings at all.
read How To Debug Small Programs.
read the documentation of gdb (and perhaps of valgrind).
study, for inspiration, the source code of some small free software similar to yours (perhaps on github).
PS. Naming your variable read is poor taste. For most people it conflicts with the POSIX read function.

Error: expected declaration specifiers or '...' before string constant [puts() and gets() statement errors

After compiling my program of Dice Roll, I got this error. What is wrong with the code?
Also before I was using gets() instead of scanf() command, but because of that I got this error - passing argument 1 of 'gets' makes pointer from integer without a cast
So I removed the gets() command and used scanf and then there was no error regarding scanf().
What is the reason for getting these two errors?
Ok, so as per the answer I got to know how I should have used the gets() command and why I shouldn't use it instead should use scanf(). So, I made the changes.
Though I have encountered two new errors, this time it's related to the delay() command that I used.
Errors: undefined reference to delay
|error: ld returned 1 exit status|
OK so I solved my last errors by using Sleep() command from windows.h library instead of Delay() command. The programs was compiled.
But still there is a runtime error in the program, it works well till getting the roll1 but then it just print the next two statement and terminated the programs without taking a input for the guess.
It skips all the code after printf("Will it be Higher/Lower or the same? (press H/L/S)\n"); and directly terminates the program.
Ok So I solved above problem adding a whitespace before the "%c" in scanf(" %c", &nextGuess); statement. (Little things xD)
Now only problem is that my toupper() command is not working.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <windows.h>
int main()
{
int i, roll1=0, roll2=0, NumberOfRolls, RandomNUM1[50], RandomNUM2[50];
char nextGuess;
puts("Welcome to the Dice Roll Game");
puts("How many times do you want to roll a dice?");
scanf("%d", &NumberOfRolls);
for( i=1; i<=NumberOfRolls; i++ ) {
RandomNUM1[i] = ( rand()%6 ) + 1;
roll1 += RandomNUM1[i];
}
printf("\nYou Got %d in your first roll!\n", roll1);
Sleep(3000);
printf("\nLet's see if you can guess the value of next roll.\n");
printf("Will it be Higher/Lower or the same? (press H/L/S)\n");
scanf(" %c", &nextGuess);
toupper(nextGuess);
for( i=1; i<=NumberOfRolls; i++ ) {
RandomNUM2[i] = ( rand()%6 ) + 1;
roll2 += RandomNUM2[i];
}
if(nextGuess=='H'){
if(roll1<roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1>roll2){
printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
}
else if(roll1==roll2){
printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
}
}
if(nextGuess=='L'){
if(roll1>roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1<roll2){
printf("Uh-Oh! Bad Luck! First roll was lower, It's %d", roll2);
}
else if(roll1==roll2){
printf("Uh-Oh! Bad Luck! Both the rolls are same, It's %d", roll2);
}
}
if(nextGuess=='S'){
if(roll1==roll2){
printf("You are such a player, you guessed it right! It's %d", roll2);
}
else if(roll1>roll2){
printf("Uh-Oh! Bad Luck! First roll was higher, It's %d", roll2);
}
else if(roll1<roll2){
printf("Uh-Oh! Bad Luck! Second roll is higher, It's %d", roll2);
}
}
return 0;
}
You have a stray ,
At the 2nd line of your main, you declare char nextGuess, instead of char nextGuess;
The compiler tells you it expects specifiers or ... after , so either you add these, or you end the line properly with;.
And for the other problem you mention:
passing argument 1 of 'gets' makes pointer from integer without a cast
Since gets argument should be char *str and you didn't provide it.
You can fix that by, for example:
char tmp_NumberOfRolls[10];
gets(tmp_NumberOfRolls);
NumberOfRolls = atoi(tmp_NumberOfRolls);
but I prefer the scanf solution
PS: (in a now edited version of the code) ***//Error Line*** is not a comment (at least, not all of it) since the *** is still counted as part of the code and will cause an error. Either move the // a bit to the left or enclose that whole part with /* ... */
The gets function reads a string (till the next newline character) from stdin, therefore it asks for a char pointer (char*) to an area of memory where it can put all the characters read including string terminator. The mistake you made is to pass to that function a pointer to int, therefore not only you get a compiler error because you tried to pass an int pointer to gets (for which there are none implicit conversions), but even if it compiled, it would not have worked as you expected because it would put all the characters (which have a size of one byte - most of the times) in that area of memory encoded as chars. That means that when you try to dereference one using a pointer to int, the characters are "read like they were an int"!
There is an example (supposing 1-byte chars, 4-bytes int and a little endian machine and that there is an implicit cast from int* to char* which does not exist and hopefully will never exist):
int num
gets(&num);
if I input 123 in stdin, the memory area pointer by num is large enough to contain the string, but it would contain (exadecimal representation):
0x31|0x32|0x33|0x00
because the string is 3 characters long, ASCII code for '1' is 0x31, for '2' is 0x32, and for '3' is 0x33 and terminates with '\0'!!
Then, when you try to dereference it you get this int (binary representation - supposing a little endian machine):
00000000|00110001|00110010|00110011
which is not the int value 123 but instead ‭3224115‬. Which is not what you wanted to get.
When you use the scanf function, you pass to that function a format string which tells it how to interpret the next arguments passed to it and performs the appropriate conversions between the string read to the right type you specified. That means that you should still pay attention to what you tell to the scanf function while you write the format string (if you tell it to read a string and pass to it a pointer to int, the program will probably crash), but it performs the appropriate conversions for you, if you write the format string correctly.
That's why with scanf everything works perfectly (you're reading an int and you specified "%d" as format string), whereas with gets it does not compile to avoid serious mistakes.
I also would like to remark some points of this answer:
The example is just for didactic purposes and the code provided does not work indeeed. The fact that I supposed that it compiles is for didactic purposes; obviously, the code provided in that example does not compile
If, in that example, we input a string larger than 3 characters (which are four if we include the null terminator) or the int (char) type contains less (more) than 4 (1) byte, the program would have crashed because we corrupted other areas of memory
The reference is more expert than me in techincal stuff, so here are the links to the gets function and the scanf function: gets, scanf (and the ASCII Table is useful too)
You could use the gets function together with the atoi function to parse the string read from gets (using a char pointer to a free area of memory large enough to contain the string, which is pretty hard to allocate (*)) to an int, but scanf is the best approach.
(*) Remember: if you allocate an area of memory that contains 20 chars, the user will input 21 chars. The atoi function fails, but the worst thing is that you have a buffer overflow (and can be a high security issue if your program runs under root permissions).

Float Checking from Char Array for Limit, Character Checking Front and Back

I am creating a simple Console application where its char *argv[] are expected to be in the form of floating number (such as 5.234, 7.197, and so on)
To ensure that the program only receive user inputs which are truly valid float, I created a function which combines sscanf (ref: character array to floating point conversion) and valid range checks (ref: How can I check if a string can be converted to a float?) results.
//buffer comes from agrv[n]
char MyFloatCheck(char* buffer)
{
float f;
char result;
result = sscanf(buffer, "%f", &f);
result &= isRangeValid(buffer);
return result;
}
Then I tested the the function above with:
Valid input: 12.15
Very large input: 4 x 10^40
Invalid inputs: (a) ab19.114, (b) 19.114ab
The results for my test no 1, 2, and 3(a) are expected:
1
0 (because it is too large)
(a) 0 (because it contains the invalid characters in front of the number)
However the result for 3 (b) is unexepected:
(b) 1 (??)
My questions are:
1. Why is that so?
2. Is there any built-in way to check this kind of input error?
3. Is there any well established workaround?
I am thinking of making my own function which checks the character from the right end to see if it contains invalid characters, but if there is any available built-in way, I would rather use it.
As you noticed, sscanf consumes characters one by one and writes the number that has been read in %f regardless of whether the reading stopped because of the end of the input string, a space, a newline, or a letter.
You would get the same behavior from strtof, a simpler substitute for sscanf(buffer, "%f", &f);:
char *endptr;
f = strtof(buffer, &endptr);
The above two lines give you a simple way to check that the entire string has been consumed after the call to strtof:
if (endptr != buffer && *endptr == 0) …
The condition endptr != buffer means that a floating-point number has been read. Otherwise, f is zero but that doesn't mean anything since no character was consumed. *endptr == 0 means that the entire input buffer was consumed in reading the floating-point number, which appears to be what you are looking for.

How to tell "1.0" is a float but an integer in C language?

I have a program that accept orders by reading commands from a file.
In this file some commands are "float string", like "1.0","2.0", but they are invalid, what the program need is integer, like "1","2". So, how can I make the program understand the commands like "1.0" is invalid? Is there any neat way to do this?
char buf[CMDSIZE];
if(fgets(buf, CMDSIZE, stdin)) //buf likes this: "1.0 \n"
{
*prio = 1; *command = -1; *ratio =1.0;
// I need to make sure that command is not "1.0" or something like this
sscanf(buf, "%d", command);
switch(*command){....blahblah......}
}
Thank you.
It's easier to use strtol.
This will parse a base-10 integer. The pointer e will point to the first character after the integer. You can check to make sure it's a NUL byte and signal an error otherwise. (You also have to check that the input isn't empty.)
If you want to allow spaces / newlines after the number, you can do that too. Note that strtol eats leading whitespace -- but not trailing whitespace.
long v;
char *e;
v = strtol(buf, &e, 10);
if (!buf[0] || *e) {
error();
}
// v has number
Footnote: Checking for overflow and underflow with strtol is a little weird. You have to set errno to 0 first, call strtol, then check if the result is LONG_MIN or LONG_MAX and if errno is set to ERANGE.
Both scanf("%d"....) and scanf("%f"....) will succeed and return 1 when reading the input 1.0. (sscanf works the same way.) It's just that with "%d", it will stop reading before the decimal point.
You can use the format specifier %n with sscanf to see how many characters were read, and then look if the buffer contains more stuff afterwards.
Or, which might be easier, just look at the contents in the buffer with your own code, instead of sscanf, to see if there are only digits there.
in your special case, just to check difference between 1 and 1.0
use the code:
int ret = scanf("%d.%d",&i,&j);
if inputs is 1, the scanf only assign one value, the ret is 1
if inputs is 1.0, the scanf assign two value, the ret is 2.
if inputs is abcd, the scanf can't assign any value, the ret is 0
and regarding the return value of scanf, fscanf etc.
In C99 standard 7.19.6.4 The scanf function
The scanf function returns the value of the macro EOF if an input failure occurs before
any conversion. Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the event of an early
matching failure
You can use scanf with %f to store it as a floating point value
example or scan with %d to store it as an integer but it will not count the decimal
#include<stdio.h>
main()
{
float i;
int a;
printf("Enter a number which is a floating point value");
scanf("%f,%d",&i,&a);
}
here using scanf and %f we are storing it in a float variable i so 1.5,1.0
or any number with a decimal will be stored or if we only use the %d it will only store 1,2,3,4 any number without the decimal i.e if we give 2.5 it will only take 2

Resources