Is this a bad way to check if a string represents a floating point number?

Looking around the Internet, I did not find a solution that satisfied me, so I tried it myself. But now the lecture also said that calling functions and waiting for a return could lead to a stack overflow, so is this a bad idea? I use this function to check if argv [1] is a float or not. Will the loop be better? or is there something more intuitive? must there be exactly one dot, and should it be followed by at least one digit to the right?

#include <stdbool.h> #include <ctype.h> /** * checks if string is floating point number * please call function with pointCounter=0 and digitAfterPoint=false */ bool isFloatString(char *s, int pointCounter, bool digitAfterPoint) { if (isdigit(*s)) { if(pointCounter==1) { digitAfterPoint=true; } return isFloatString(s+1, pointCounter, digitAfterPoint); } else if (*s == '.' && pointCounter==0) { return isFloatString(s+1, pointCounter+1,digitAfterPoint); } else if (*s == '\0' && digitAfterPoint) { return true; } else { return false; } } 
+5
source share
2 answers

For 999 digits and one point, there are 1000 recursive calls with each return address and three parameters on the stack. I would understand that everything is in order. However, a non-recursive iterative solution eliminates state parameters and is easier to read (only in this case).

 bool isFloatString(char *s) { int pointCounter = 0; bool digitAfterPoint = false; while (*s != '\0') { if (isdigit(*s)) digitAfterPoint = pointCounter == 1; } else if (*s == '.' && pointCounter == 0) { ++pointCounter; } else { return false; } ++s; } return digitAfterPoint; } 

Mind: A recursive solution is prone to malicious stack overflow.


@MatteoItalia rightly pointed out that there is only tail recursion (nothing is done with the result), so any mature C / C ++ compiler will convert recursion to jumping (iteration). Here it is disassembled (see link in comments too).

 isFloatString(char*, int, bool): movsx ecx, BYTE PTR [rdi] mov r9d, edx mov r8d, ecx sub ecx, 48 cmp ecx, 9 jbe .L23 cmp r8b, 46 je .L24 test r8b, r8b sete al and eax, edx ret .L24: xor eax, eax test esi, esi je .L25 .L1: rep ret .L23: movsx eax, BYTE PTR [rdi+1] mov ecx, eax sub eax, 48 cmp esi, 1 je .L26 cmp eax, 9 movzx edx, dl jbe .L10 cmp cl, 46 je .L27 .L8: test cl, cl sete al and eax, r9d ret .L26: cmp eax, 9 jbe .L28 xor eax, eax cmp cl, 46 mov r9d, 1 jne .L8 jmp .L1 .L28: mov edx, 1 .L10: add rdi, 2 jmp isFloatString(char*, int, bool) .L25: movzx edx, dl add rdi, 1 mov esi, 1 jmp isFloatString(char*, int, bool) .L27: xor eax, eax test esi, esi jne .L1 add rdi, 2 mov esi, 1 jmp isFloatString(char*, int, bool) 
+4
source

check if a string represents a floating point number?

The C standard library provides a simple robust solution using strtof() , strtod() or strtold()

 // leading whitespace OK, trailing text OK, over/underflow OK bool isFloatString_Simple(const char *s) { char *endptr; strtof(s, &endptr); return endptr > s; } 

Are leading spaces OK?
Does garbage end after a numeric text OK?
Should overflow problems?
Should you underestimate anxiety?

Then more code is required. Adjust if necessary.

 bool isFloatString_Picky(const char *s) { char *endptr; errno = 0; float f = strtof(s, &endptr); if (s == endptr) return false; // no conversion if (isspace((unsigned char) *s)) return false; // reject leading white-space if (*endptr) return false; // reject junk after numeric text if (errno) { if (fabsf(f) > 1.0f) return false; // reject on overflow // yet pass on underflow. } return true; } 
0
source

Source: https://habr.com/ru/post/1274211/


All Articles