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)