Yes! It’s a String – or Number!

The standard library functions atoi() and atof() work well to translate text (ASCII) input into values, an int or float, respectively. When your code must know whether a string is really a value, more processing is required.

The first method I’ve used to confirm values is a simple comparison: The original string is compared with the translated value. If they match, then the translation is successful and the proper value was obtained. This method uses the atoi() and atof() functions as well as sprintf() and strcmp() to compare the results. Here’s sample code based on last week’s Lesson‘s example:

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

int main()
{
    char *strings[4] = {
        "123",
        "0.33",
        "7lucky",
        "string"
    };
    int asint;
    float asfloat;
    char buffer[16];

    for(int x=0;x<4;x++)
    {
        printf("String \"%s\"\n",strings[x]);
        /* test int comparison */
        asint = atoi(strings[x]);
        sprintf(buffer,"%d",asint);
        if(strcmp(buffer,strings[x])==0)
            printf("\tString matches as int: \"%s\" == \"%s\"\n",
                    strings[x],
                    buffer
                  );
        else
            printf("\tString doesn't match as int: \"%s\" != \"%s\"\n",
                    strings[x],
                    buffer
                  );
       /* test float comparison */
        asfloat = atof(strings[x]);
        sprintf(buffer,"%f",asfloat);
        if(strcmp(buffer,strings[x])==0)
            printf("\tString matches as float: \"%s\" == \"%s\"\n",
                    strings[x],
                    buffer
                  );
        else
            printf("\tString doesn't match as float: \"%s\" != \"%s\"\n",
                    strings[x],
                    buffer
                  );
    }

    return(0);
}

For each string in the strings[] array, atio() and atof() translate. The sprintf() function takes the resulting value and converts it back into a string. Then that converted string, buffer, is compared with the original string.

Here’s a sample run:

String "123"
	String matches as int: "123" == "123"
	String doesn't match as float: "123" != "123.000000"
String "0.33"
	String doesn't match as int: "0.33" != "0"
	String doesn't match as float: "0.33" != "0.330000"
String "7lucky"
	String doesn't match as int: "7lucky" != "7"
	String doesn't match as float: "7lucky" != "7.000000"
String "string"
	String doesn't match as int: "string" != "0"
	String doesn't match as float: "string" != "0.000000"

As you can see, this method works best on int values. The problem with float comparisons is that the decimal positions are wrong: values 0.33 and 0.330000 are identical, but not as strings.

Another way to process text input as a value is to crunch through the string and determine its value based on individual characters. The following code uses the value_type() function to guess a string’s numeric type:

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

int value_type(char *s)
{
    enum { FALSE, TRUE };
    int f_flag = FALSE;

    while(*s)
    {
        if(*s == '.')
        {
            f_flag = TRUE;
            s++;
        }
        else if(!isdigit(*s))
        {
            return(0);  /* text */
        }
        else
        {
            s++;
        }
    }

    if(f_flag)
        return(1);  /* float */

    return(2);  /* int */
}

int main()
{
    char *strings[4] = {
        "123",
        "0.33",
        "7lucky",
        "string"
    };
    int t;

    for(int x=0;x<4;x++)
    {
        printf("String \"%s\" is probably a",strings[x]);
        t = value_type(strings[x]);
        switch(t)
        {
            case 2:
                printf("n integer\n");
                break;
            case 1:
                printf(" float\n");
                break;
            case 0:
                printf(" string\n");
                break;
            default:
                printf("Undefined\n");
        }
    }

    return(0);
}

The value_type() function reads the input string one character at a time. If a '.' is found, the f_flag variable is set to TRUE. That character is found in a float. After that character is eliminated, the isdigit() function is used to reject any string that doesn’t contain a digit.

After the string is processed, an if statement tests the f_flag variable. If TRUE, that means the string is all numbers with a period, so the value 1 is returned to represent a float. Otherwise, the value 2 is returned for an int.

In the main() function, a switch-case structure evaluates the return value t from function value_type(). Here’s sample output:

String "123" is probably an integer
String "0.33" is probably a float
String "7lucky" is probably a string
String "string" is probably a string

One thing I didn’t do in this code was to test for the presence of more than one period in a number. While it would be rare to have input such as "1.234.56" the code should anticipate such a thing. You can modify the value_type() function to test for multiple '.' characters in a string and then evaluate such input as a string as opposed to a float.

Further, the code could also test for and eliminate commas ',' in a string, just in case the user is dorky enough to specify them as a thousands separator.

Leave a Reply