How do i check each line of file in C? - c

I'm new to C
i'm asked to check if the format of the text file input is right or not!
the file should have lines like this :
1-float
2-('+'/'*'/'-')
3-flaot
4-'='
5-the result of the above operation
6-';'
I read the file and place each char in an array but have no idea what to do next
here is my code
#include <stdio.h>
#include <conio.h>
/*Max number of characters to be read/write from file*/
#define MAX_CHAR_FOR_FILE_OPERATION 1000000
int main()
{
char *filename = "D:\input.txt";
FILE *fp;
char text[MAX_CHAR_FOR_FILE_OPERATION];
int i;
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("File Pointer is invalid\n");
return -1;
}
//Ensure array write starts from beginning
i = 0;
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while( (fgets(&text[i++],sizeof(char)+1,fp) != NULL) && (i<MAX_CHAR_FOR_FILE_OPERATION) ) ;
//Ensure array read starts from beginning
fclose(fp);
getche();
return 0;
}

The easiest solution I can think of is to create an automata. That could be an enum with steps, for exemple:
enum AUTOMATE
{
FirstFloat = 0,
FirstSign,
SecondFloat,
EqualSign,
Answer
};
More info on how to use enum here : http://msdn.microsoft.com/en-us/library/whbyts4t.aspx
If you already have all each char in an array, iterate over the entire array using whichever loop you want, and check the integer value of each char. Use this table http://www.asciitable.com/ to check weather the integer value represents a number or a sign (-, +, =, etc). When each step is passed, tell your automate to go further (+=1). If you reach the end, you verified it. If not, then format is wrong.

It is not 100% clear what you want to do here.
If all you want to do is check that the expression is syntactically correct, that's one thing. If you want to check that it is also arithmetically correct (i.e. that the result on the RHS of the = is actually the result of the arithmetic expression on the LHS), that's another.
In either case, you must parse the input lines. There are several ways of doing this. The canonical, general, and robust way is to tokenize the lines with a lexer and pass the tokens from the lexer to a parser, which is a kind of finite state machine that “knows” the grammar of the language you are trying to parse (in this case infix arithmetic expressions). Given that you asked this question, it's reasonable to assume that you haven't got to this kind of material yet.
In your case, you are only dealing with simple infix arithmetic expressions of the form:
NUMBER OPERATOR NUMBER = NUMBER ;
You can get away with checking for lines that “look” exactly like this with one of the scanf() family of functions, but this is a fragile solution: if you add another term to the expression on the left, it will break; it takes considerable care to craft the correct format string; and it does not check for arithmetic correctness.
If all you need is something this simple, you can do it like this (I have omitted the file I/O):
#include <stdio.h>
#include <stdbool.h>
#define OPERATOR_CLASS "[-+/*]"
bool is_a_binary_infix_expression(const char *expr)
{
int count; // Count returned by sscanf()
float left_opd; // Left operand
char operator[2] = {'\0'}; // Operator
float right_opd; // Right operand
float result; // Result
char junk; // Trailing junk
// Format specifier for sscanf():
const char *format = "%f %1" OPERATOR_CLASS "%f =%f ; %c";
// Attempt conversion:
count = sscanf(expr, format, &left_opd, operator, &right_opd, &result, &junk);
// If exactly 4 conversions succeeded, the expression was good. If fewer,
// the conversion failed prematurely. If 5, there was trailing junk:
return count==4;
}
int main(void) {
int i;
int n_lines;
char *lines[]={
"1.5+2.2=3.7;",
"1.5 + 2.2 = 3.7 ; ",
"a+2.2=3.7;",
"1.5+2.2=3.7;x",
};
n_lines = (int)sizeof(lines)/sizeof(char *);
for(i=0; i<n_lines; i++) {
printf("'%s' is %s\n", lines[i], is_a_binary_infix_expression(lines[i]) ? "OK" : "NOT OK");
}
return 0;
}
This only checks for syntactic correctness. If you want to check for arithmetic correctness, you can switch on the operand to compute the correct result and compare that with the result extracted from the input line, but be careful not to fall into the trap of doing a direct comparison with ==.

Related

How to convert a string value to numerical value?

I have tried this code to separate my Str[] string into 2 string, but my problem is "I want to separate John(name) as string and 100(marks) as integer",How can I do it, any suggestion?
#include <stdio.h>
#include <string.h>
void main()
{
char Str[] = "John,100";
int i, j, xchange;
char name[50];
char marks[10];
j = 0; xchange = 0;
for(i=0; Str[i]!='\0'; i++){
if(Str[i]!=',' && xchange!=-1){
name[i] = Str[i];
}else{
xchange = -1;
}
if(xchange==-1){
marks[j++] = Str[i+1];
}
}
printf("Student name is %s\n", name);
printf("Student marks is %s", marks);
}
How to separate "John,100" into 2 strings?
There are three common approaches:
Use strtok() to split the string into individual tokens. This will modify the original string, but is quite simple to implement:
int main(void)
{
char line[] = "John,100;passed";
char *name, *score, *status;
/* Detach the initial part of the line,
up to the first comma, and set name
to point to that part. */
name = strtok(line, ",");
/* Detach the next part of the line,
up to the next comma or semicolon,
setting score to point to that part. */
score = strtok(NULL, ",;");
/* Detach the final part of the line,
setting status to point to it. */
status = strtok(NULL, "");
Note that if you change char line[] = "John,100"; then status will be NULL, but the code is otherwise safe to run.
So, in practice, if you required all three fields to exist in line, it would be sufficient to ensure the last one was not NULL:
if (!status) {
fprintf(stderr, "line[] did not have three fields!\n");
return EXIT_FAILURE;
}
Use sscanf() to convert the string. For example,
char line[] = "John,100";
char name[20];
int score;
if (sscanf(line, "%19[^,],%d", name, &score) != 2) {
fprintf(stderr, "Cannot parse line[] correctly.\n");
return EXIT_FAILURE;
}
Here, the 19 refers to the number of chars in name (one is always reserved for the end-of-string nul char, '\0'), and [^,] is a string conversion, consuming everything except a comma. %d converts an int. The return value is the number of successful conversions.
This approach does not modify the original string, and it allows you to try a number of different parsing patterns; as long as you try them the most complex one first, you can allow multiple input formats with very little added code. I do this regularly when taking 2D or 3D vectors as inputs.
The downside is that sscanf() (all functions in the scanf family) ignores overflow. For example, on 32-bit architectures, the largest int is 2147483647, but scanf functions will happily convert e.g. 9999999999 to 1410065407 (or some other value!) without returning an error. You can only assume the numerical inputs are sane and within the limits; you cannot verify.
Use helper functions to tokenise and/or parse the string.
Typically, the helper functions are something like
char *parse_string(char *source, char **to);
char *parse_long(char *source, long *to);
where source is a pointer to the next character in the string to be parsed, and to is a pointer to where the parsed value will be stored; or
char *next_string(char **source);
long next_long(char **source);
where source is a pointer to a pointer to the next character in the string to be parsed, and the return value is the value of the extracted token.
These tend to be longer than above, and if written by me, then quite paranoid about the inputs they accept. (I want my programs to complain if their input cannot be reliably parsed, rather than silently produce garbage.)
If the data is some variant of CSV (comma-separated values) read from a file, then the proper approach is a different one: instead of reading the file line by line, you read the file token by token.
The only "trick" is to remember the separator character that ended the token (you can use ungetc() for this), and use a different function to (read and ignore the rest of the tokens in the current record, and) consume the newline separator.

Using fgets for file read

I'm new to using strings in C and am needing to read from a file lines of data that contain strings and numbers, parsing them as I go along. I've done similar programs reading in just numbers, such as a list of ordered pairs, using a for loop so this is the strategy I am leaning towards.
Example of data line in the file: PART,2.000,-1,0.050,V
When I compile I get an error in the for loop declaration of "expected expression before 'char'". What is missing or needs reviewing in this code?
#define flush fflush(stdin)
#define N 50
int main()
{
flush;
const char part[] = "PART"; // String for PART variable
char descriptor[N]; // Starting string of data set
double p_dim[N]; // Array for part dimensions
int t_sens[N]; // Array for sensitivity values: -1 or +1
double t[N]; // Array for part tolerance, bilateral
char t_status[N]; // Array for tolerance status, F(ixed) or V(ariable)
double key_max; // Maximum value of key characteristic
double key_min; // Minimum value of key characteristic
FILE* fpin;
if((fpin = fopen("input.txt","r"))==(FILE*)NULL)
{
printf("File input does not exist\n"); exit(-1);
}
// For loop to parse data lines from file
for(N; char* fgets(descriptor, int N, FILE* fpin); N-1);
{
compare(descriptor, part);
if (descriptor == part)
{
fscanf(fpin, "%lf,%d,%lf,%s", p_dim[N], t_sens[N], t[N], t_status[N]);
}
else if (descriptor != part)
{
fscanf(fpin, "%lf, %lf", &key_min, &key_max);
}
}
1.) #define flush fflush(stdin)
Flushing stdin invokes undefined behaviour.
2.) if((fpin = fopen("input.txt","r"))==(FILE*)NULL)
The cast to (FILE*) is superfluous.
3.) for(N; ... ; N-1);
You defined N as a constant (#define N 50) so this loop won't ever exit.
4.) for(... ; char* fgets(descriptor, int N, FILE* fpin); ...);
This is just plain wrong ...
I'd lean more toward breaking the string apart
See question 3501338 for reading a file line by line
See question 15472299 using strtok to break apart the string
If you need to cast the strings as numbers use sscanf

Char value higher then 255?

Today I wrote simple program to encryption my .txt file. And I saw, I can set char value higher than 255.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
FILE* fp;
FILE* fp2;
char buffor = '\0';
int szyfr = 0;
if(argc < 4)
{
printf("Za malo argumentow (c/dc, sciezka, szyfr)!\n");
exit(0);
}
{
int i;
for(i = 0;i < strlen(argv[3]);++i)
{
szyfr *= 10;
szyfr += argv[3][i]-48;
}
}
if(!strncmp(argv[1], "c", 1))
{
fp = fopen(argv[2], "r");
fp2 = fopen("crypted.data", "w");
if(!fp)
{
printf("Cannot open file: %s!", argv[2]);
exit(0);
}
while(1)
{
buffor = fgetc(fp);
if(feof(fp) != 0) break;
fputc(buffor+szyfr, fp2);
}
fputc_unlocked(
fclose(fp);
fclose(fp2);
}
else if(!strncmp(argv[1], "dc", 2))
{
fp = fopen(argv[2], "r");
fp2 = fopen("uncrypted.txt", "w");
if(!fp)
{
printf("Cannot open file: %s!", argv[2]);
exit(0);
}
while(1)
{
buffor = fgetc(fp);
if(feof(fp) != 0) break;
fputc(buffor-szyfr, fp2);
}
fclose(fp);
fclose(fp2);
}
return 0;
}
Whatever you set in the szyfr value this will work, but chars in the .data file is very strange (for example for 666 szyfr it will be like " ×ýû¤")
Why this doesn't giving error about char memory or something like that?
PS: Sorry for some texts in code in Polish but I forgot about this
I saw, I can set char value higher than 255.
I guess you're talking about the first argument to fputc(), and maybe about the return value of fgetc(). These both have type int, but that doesn't mean what you seem to think it means. The behavior of both functions is defined in terms of type unsigned char:
fgetc():
the fgetc function obtains that character as an unsigned char converted to an int [...]
(C2011, 2.21.7.1/2; emphasis added)
fputc():
The fputc function writes the character specified by c (converted to an unsigned char) to the output stream pointed to by stream [...]
(C2011, 2.21.7.3/2; emphasis added)
So yes, inasmuch as the range of type int is, in practice, invariably larger than that of type unsigned char, you can pass a value larger than unsigned char can represent to fputc(). But no, that does not result in writing that value in a manner that can be read back. The conversion to unsigned char will result in the character actually written being in the range of unsigned char, which is almost certainly 0 - 255 for you.
Why this doesn't giving error about char memory or something like that?
There is no error in fputc() because the behavior is perfectly well defined for the arguments you are providing. Even if there were an error, however, your code would not tell you, because such an error would be communicated to your program via the return value of fputc(), which you do not check.
Regarding wide-character I/O
Note that wide-character I/O functions such as fgetwc() and fputwc() operate in larger units, but their underlying behavior is not fundamentally different. It involves casting analogous to that performed by fgetc() and fputc() -- thus affording the same possibility of data corruption -- and you might still see strange characters in your encrypted file, albeit probably different ones.
Regarding strange characters
As far as strange characters appearing in the encrypted file, this is pretty much to be expected, albeit somewhat dependent on what your editor or terminal (depending on how you display the file) supposes is the file's character encoding. Your encryption scheme effectively converts character data to binary data, so it's unreasonable to expect it to look like character data.
C is a low-level language that just does what you tell it, with no help or argument.
You declare a variable buffor to be a char, and then you call a function fgetc() that returns an int, and then you assign it. C says "Fine. You've asked me to put 16 gallons of water into an 8-gallon bucket, so I did." Now you've got a full 8 gallon bucket and a wet floor. C just chops off 8 bits and drops them, so for instance, you'll never be able to tell when fgetc() returns EOF, since that's a larger-than-8-bit value.
If you want to assure that 8-bit variables only get 8-bit values, you'll have to check them yourself before you assign them.

C language reading columnated text file

First of all let me ask for your forgiveness if this is too trivial, I am not a C developer, usually I program in Fortran.
I am in need to read some columnated text files. The problem I have is that some columns can have blank space (non filled value) or not fully filed field.
Let me use a short example of the problem. Lets say I have a generator program like:
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("xxxx%4d%4.2f\n",99,3.14);
}
When I execute this program I get:
$ ./t1
xxxx 993.14
If I get it into a text file and try to read using (e.g.) sscanf with the code:
#include <stdio.h>
#include <stdlib.h>
int main() {
char *fmt = "%*4c%4d%4f";
char *line = "xxxx 993.14";
int ival;
float fval;
sscanf(line,fmt,&ival,&fval);
printf(">>>>%d|%f\n",ival,fval);
}
The result is:
$ ./t2
>>>>993|0.140000
What is the problem here? The sscanf seems to think that all space is meaningless and should be discarded. So the "%4c" does what it is meant to be, it counts 4 characters without discarding any blank space and discards everything due to "". Next the %4d start skipping all blank spaces and start count the 4 characters of the field upon finding the first valid character for the conversion. So the value, meant to be 99 becomes 993, and the 3.14 becomes 0.14.
In Fortran the reading code would be:
program t3
implicit none
integer :: ival
real :: fval
character(len=30) :: fmt="(4x,i4,f4.0)"
character(len=30) :: line="xxxx 993.14"
read(line,fmt) ival, fval
write(*,"('>>>>',i4,'|',f4.2)") ival,fval
end program t3
and the result would be:
$ ./t3
>>>> 99|3.14
That is, the format specification states the field width and nothing is discarding in conversion, except if instructed to by the "nX" specification.
Some final remarks to help the helpers:
The format to be read is an international standard and there is no
way to change it.
The number of existing files is to big to think of intervention or
format change.
It is not a CSV or similar format.
The code has to be in C for integration in a free software package.
Sorry to be too long, trying to state the problem as completely as possible.
The question is: Is there a way to tell sscanf to not skip the blank spaces? If not, is there a simple way to do it in C or it will be necessary write an specialized parser for each record type?
Thank you in advance.
When reading fixed-length fields with sscanf, it is best to parse the values as character strings (which you could do a number of ways), and then perform independent conversion of each of the fields. This allows you to handle conversion/error detection on a per-field basis. For example, you could use a format string of:
char *fmt = "%*4s%2[^0-9]%s";
which would read/discard the 4 leading characters, then read 2-chars as your integer, followed by the remainder of line (or up until the next whitespace) as a string containing your float value.
To handle the storage and parsing of line as fixed length fields, you could use temporary character arrays to hold each of the strings and then use sscanf to fill them much as you have attempted to do with the integer and float directly. e.g.:
char istr[8] = {0};
char fstr[16] = {0};
...
sscanf (line,fmt,istr,fstr);
(note: you could use minimum storage of istr[3] and fstr[7] in this given case, adjust the storage length as required, but providing space for the nul-terminating character)
You can then use strtol and strtof to provide conversion with error checking on each value. For example:
errno = 0;
if ((ival = (int)strtol (istr, NULL, 10)) == 0 && errno)
fprintf (stderr, "error: integer conversion failed.\n");
/* underflow/overflow checks omitted */
and
errno = 0;
if ((fval = strtof (fstr, NULL)) == 0 && errno)
fprintf (stderr, "error: integer conversion failed.\n");
/* nan and inf checks omitted */
Putting all the pieces together in you example, you could use something like:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main() {
char *fmt = "%*4s%2[^0-9]%s";
char *line = "xxxx 993.14";
char istr[8] = {0};
char fstr[16] = {0};
int ival;
float fval;
sscanf (line,fmt,istr,fstr);
errno = 0;
if ((ival = (int)strtol (istr, NULL, 10)) == 0 && errno)
fprintf (stderr, "error: integer conversion failed.\n");
/* underflow/overflow checks omitted */
errno = 0;
if ((fval = strtof (fstr, NULL)) == 0 && errno)
fprintf (stderr, "error: integer conversion failed.\n");
/* nan and inf checks omitted */
printf(">>>>%d|%6.2f\n",ival,fval);
return 0;
}
Example/Output
$ >>>>0|993.14
*scanf() is not designed to handle fixed column width with non-intervening white-space.
With sscanf(), to not skip spaces, code must use "%c", "%n", "%[]" as all other specifiers skip leading white-space and those skipped characters do not contribute to a width limit.
To scan the printed line, which in now in buffer, take advantage that the only use of '\n' is at the end of the line.
char str_int[5];
char str_float[5];
int n = 0;
sscanf(buffer, "%*4c%4[^\n]%4[^\n]%n", str_int, str_float, &n);
if (n != 12 || buffer[n] != '\n') Fail();
// Now convert str_int, str_float as needed.
Another way to use sscanf() would be to parse buffer as
int ival;
float fval;
if (strlen(buffer) != 13) Fail();
if (sscanf(&buffer[8], "%f", &fval) != 1) Fail();
buffer[8] = '\0';
if (sscanf(&buffer[4], "%d", &ival) != 1) Fail();
Note: The 4s in the below do not specified the output width as 4 characters. 4 is the minimum width to print.
printf("xxxx%4d%4.2f\n",ival, fval);
Code could use the following to detect problems.
if (13 != printf("xxxx%4d%4.2f\n",ival, fval)) Fail();
Watch out for
printf("xxxx%4d%4.2f\n",123, 9.995000001f); // "xxxx 12310.00\n"
First off, I dunno. There might be some way to wrangle sscanf to recognize the whitespace towards your integer count. But I just don't think scanf was made for this sort of format in mind. The tool's trying to be smart of helpful and it's biting you in the ass.
But if it's columnated data and you know the position of the various fields, there's a really easy work around. Just extract the field you want.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
char line[] = "xxxx 893.14";
char tmp[100];
int thatDamnNumber;
float myfloatykins;
//Get that field
memcpy(tmp, line+4, 4);
sscanf(tmp, "%d", &thatDamnNumber);
//Kill that field so it doesn't goober-up the float
memset(line+4, ' ', 4);
sscanf(line, "%*4c%f", &myfloatykins);
printf("%d %f\n", thatDamnNumber, myfloatykins);
return 0;
}
If there is a lot of this, you could make some generalized functions: integerExtract(int positionStart, int sizeInCharacters), floatExtract(), etc.
If each element is of fixed width you don't really need scanf(), try this
char copy[5];
const char *line = "xxxx 993.14";
int ival;
float fval;
copy[0] = line[4];
copy[1] = line[5];
copy[2] = line[6];
copy[3] = line[7];
copy[4] = '\0'; // nul terminate for `atoi' to work
ival = atoi(copy);
fval = atof(&line[8]);
fprintf(stdout, "%d -- %f\n", ival, fval);
If you want (probably should) you can use strtol() instead of atoi() and strtof() instead of atof() to check for malformed data.
Both these functions take a parameter to store the unconverted/invalid characters, you can check the passed pointer in order to verify that there was a problem with conversion.
Or if you really want scanf() do the same, capture the integer + whitespaces to a char array and then convert it to int later, like this
char integer[5];
const char *line = "xxxx 993.14";
int ival;
float fval;
if (sscanf(line, "%*4c%4[0-9 ]%f", integer, &fval) != 2)
return -1;
ival = atoi(integer);
fprintf(stdout, "%d -- %f\n", ival, fval);
The format "%*4c%4[0-9 ]%f" will
Skip the first four characters including white spaces.
Scan the next four characters if they consist only of digits or white spaces.
Scan the rest of the input string searching for a matching float value.
I am posting what I think is a final conclusion from the answers I have got so far and from other sources.
What is a very trivial task in Fortran is not a so trivial task in other languages. I guess — not sure — that the same task could be as easy as in Fortran in other languages. I think that Cobol, Pascal, PL/I and others from the time of punched card probably could be trivial.
I think that most languages nowadays are more comfortable with different data structure and inherited its I/O structure from C. I think that Java, Python, Perl(?) and others could serve as examples.
From what I saw in this thread there are two main problems to read / convert fixed column length text data with C.
The first problem is that, as Philip said in his answer: “The tool’s trying to be smart of helpful and it’s biting you in the ass.” Quite right! The point is that it seems that C text I/O thinks that “white space” is something like a NULL character and should be thrown away, completely disregarding any information of the start of field. The only exception to that seems to be the %nc that get exactly n chars, even blanks.
The second problem is that the conversion “tag” (how is that called?) %nf will keep converting while it finds a valid character, even if you say stop at the 4th character.
If we join those two problems with a field completely filled with white space, depending on the conversion tool used, it throws an error or keeps going madly looking for something meaningful.
At the end of the day, it seems that the only way is to extract the field length to another memory area, dynamically allocated or not (we can have an area for each column length), and try to parse this separate area, taking into account the possibility of a full white space area to cache the error.

C: Check if a string is an integer and save it

I've been searching the internet for some time, but didn't find a simple solution for a actually simple problem in my eyes. I guess it has been asked already:
I'm reading a value like 20.1 or XYZ via sscanf from a file and saving it in char *width_as_string.
All functions should be valid in -std=c99.
Now I want to check if the value in width_as_string is an integer. If true, it should be saved in int width. If false, width should remain with the value 0.
My approaches:
int width = 0;
if (isdigit(width_as_string)) {
width = atoi(width_as_string);
}
Alternatively, convert width_as_string to int width and convert it back to a string. Then compare if it is the same. But I'm not sure how to achieve that. I already tried itoa.
Functions like isdigit and itoa are not valid in std=c99, therefore I can't use them.
Thanks.
Read carefully some documentation of sscanf. It returns a count, and accepts the %n conversion specifier to give the number of character (bytes) scanned so far. Perhaps you want:
int endpos = 0;
int width = 0;
if (sscanf(width_as_string, "%d %n", &width, &endpos)>=1 && endpos>0) {
behappywith(width);
};
Perhaps you want also to add && width_as_string[endpos]==(char)0 (to check that the number is perhaps space suffixed, then reaching the end of string) after endpos>0
You could also consider the standard strtol which sets an end pointer:
char*endp = NULL;
width = (int) strtol(width_as_string, &endp, 0);
if (endp>width_as_string && *endp==(char)0 && width>=0) {
behappywith(width);
}
The *endp == (char)0 is testing that the end of number pointer -filled by strtol- is the end of string pointer (since a string is terminated with a zero byte). You could make that more fancy if you want to accept trailing spaces.
PS. Actually, you need to specify precisely what is an acceptable input (perhaps by some EBNF syntax). We don't know if "1 " or "2!" or "3+4" are (as C strings) acceptable to you.
How about strtol?
This gives a clear return value if something goes wrong, i think this is what you're looking for
http://www.cplusplus.com/reference/cstdlib/strtol/
Actually, you could use sscanf at the very beginning to check whether the number is integer or not. Something like this
#include <stdio.h>
#include <string.h>
int
main (int argc, char *argv[])
{
int wc; // width to check
int w; // width
char *string = "20.1";
printf("string = %s\n", string);
if (strchr(string, '.') != NULL)
{
wc = 0;
printf("wc = %d\n", wc);
}
else if ((sscanf(string, "%d", &w)) > 0)
{
wc = w;
printf("wc = %d\n", wc);
} else w = 0;
return 0;
}
This is a sample program of course, it first searches the string for a "." to verify if the number could be float and discards it in such a case, then tries to read an integer if no "." are found.
Changed thanks to ameyCU's suggestion
Reference page for sscanf

Resources