hey guys heres a portion of my code, im trying to validate a users input of price and then convert it to cents before doing some other calculations.
Im having problems with my validation still somehow allows letters if they are not the first digit entered.
For example, a2 is invalid, whereas 2a is valid.
I've tried using atoi and isdigit as well as I have searched it up on google, but those dont work either, they dont return me a zero as I am expecting when a letter is entered.
Any help is much appreciated...

/*Price Validation*/
		if(sPrice[strlen(sPrice)-1] != '\n')
		{   readRestOfLine();
			printf("Invalid price, maximum is RM 9999.99.");
			break;
		}
		if(sPrice[0] == '\n')
		{   break;
		}
		if(sPrice[0] == '0' && sPrice[1] == '\n')
		{	price = 0;
		}
		else if((sPrice[0] == '0' && sPrice[1] != '\n') ||	/*can't start with a zero*/
				(atof(sPrice) == 0.0) ||	/*no letters*/
				(sPrice[0] == '.')) 		/*can't start with a point*/
		{	printf("Invalid price.");
			break;
		}
		else if(strlen(sPrice) != strcspn(sPrice, point) &&	(strlen(sPrice) - strcspn(sPrice, point)) != 4)		/*must have 2 decimal digits or none at all*/
		{	printf("Invalid price.");
			break;
		}
		else
		{	dPrice = atof(sPrice);
			if(dPrice == 0.0)
			{	printf("Invalid price.");
			}
			else
			{	dPrice = (dPrice*100)+0.05;		/*convert to cents before storing*/
				price = (int)dPrice;
			}	
		}
		/*end of price validation*/

Dani AI

Generated

Short answer: stop using atof() for validation — it silently stops at the first non‑numeric character, so "2a" becomes 2.0. As pointed out, you must verify that the entire trimmed input is a valid numeric string. 's digit-scan idea is sound; a robust solution combines careful scanning with integer arithmetic so you get exact cents and predictable validation rules.

This example validates these rules: only digits with an optional single .; at most two fractional digits; no stray characters; optional policy to reject leading-zero forms like 01.00; and enforces the RM 9999.99 maximum. It returns cents exactly (integer arithmetic), so no floating rounding tricks.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int parse_price_to_cents(const char *input, int *cents_out) {
    char buf[64];
    const char *s, *dot;
    char whole[32], frac[4];
    size_t whole_len, frac_len;
    long whole_val;
    int frac_val = 0;

    if (!input || !cents_out) return 0;
    strncpy(buf, input, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0';

    // trim trailing whitespace
    size_t len = strlen(buf);
    while (len > 0 && isspace((unsigned char)buf[len-1])) buf[--len] = '\0';
    s = buf; while (*s && isspace((unsigned char)*s)) s++;
    if (*s == '\0') return 0;

    dot = strchr(s, '.');
    if (dot) {
        whole_len = dot - s;
        if (whole_len == 0 || whole_len >= sizeof(whole)) return 0;
        memcpy(whole, s, whole_len); whole[whole_len] = '\0';
        if (whole_len > 1 && whole[0] == '0') return 0; // optional: ban leading zeros
        for (size_t i=0; i<whole_len; ++i) if (!isdigit((unsigned char)whole[i])) return 0;

        const char *f = dot + 1;
        frac_len = strlen(f);
        if (frac_len == 0 || frac_len > 2 || frac_len >= sizeof(frac)) return 0;
        strcpy(frac, f);
        for (size_t i=0; i<frac_len; ++i) if (!isdigit((unsigned char)frac[i])) return 0;

        whole_val = strtol(whole, NULL, 10);
        if (frac_len == 1) frac_val = (frac[0]-'0') * 10;
        else frac_val = (frac[0]-'0')*10 + (frac[1]-'0');
    } else {
        whole_len = strlen(s);
        if (whole_len == 0 || whole_len >= sizeof(whole)) return 0;
        strcpy(whole, s);
        for (size_t i=0; i<whole_len; ++i) if (!isdigit((unsigned char)whole[i])) return 0;
        if (whole_len > 1 && whole[0] == '0') return 0; // optional: ban leading zeros
        whole_val = strtol(whole, NULL, 10);
    }

    if (whole_val < 0 || whole_val > 9999) return 0;
    *cents_out = (int)(whole_val * 100 + frac_val);
    return 1;
}

Notes and tests: try inputs 2a, a2, 2, 2.0, 2.00, 2.000, 0.99, 01.00, 9999.99, 10000.00. If you prefer strtod(), use its endptr to ensure the whole string was consumed and then check the fractional length; the manual parse above avoids floating rounding issues. Also be aware of locale decimal separators (, vs .) if your environment changes strtod behavior.

Recommended Answers

All 7 Replies

Did you find any error?

no errors... it simply allows the value to go thru, and takes 2a for example, as a 2.00

that's true -- atof("2a") is 2.00. I have no idea what the 'a' is for, but atof() stops converting at the first character that is not a digit or '.' or '-'.

The 2a is just an example of my input that is not supposed to be allowed by the program... but is...
if atof stops converting at the first non digit, dot or dash, then how do i go about validating the price?
thanks for the reply...

use instead of atof(). Read the description of that function carefully and you will see how you can use it to verify that the string contains only numeric digits plus dot and dash. Otherwise you can just parse the string yourself to validate it.

Read a string fgets()
set flag to TRUE
For i=0 to string length
    if string(i) != digit nor dot set flag to FALSE
end for
if flag = FALSE number was not entered
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.