IP4 strings validator Trying to write fast non dependency IP4 string validator for embedded system, It should counts leading zeros, values over 255 and other corrupted strings. Not sure if I missed something. Сan you guys take a look:

// Return 0 on error, store result to segs, if segs != 0.
int is_valid_ip4(const char *str, unsigned char* segs)
{
    int dots = 0;   // Dot count.
    int chcnt = 0;  // Character count within segment.
    int accum = 0;  // Accumulator for segment.

    // Catch NULL pointer.
    if (str == 0)
        return 0;

    // Process every character in string.
    for (;;)
    {
        // Check numeric.
        if (*str &lt; '0' || *str &gt; '9')
            return 0;

        // Prevent leading zeros.
        if (chcnt &gt; 0 &amp;&amp; accum == 0)
            return 0;

        // Accumulate and check segment.
        accum = accum * 10 + *str - '0';
        if (accum &gt; 255)
            return 0;

        // Store result.
        if (segs)
            segs[dots] = (unsigned char)accum;

        // Advance other segment specific stuff.
        ++chcnt;
        ++str;

        // Finish at the end of the string when 3 points are found.
        if (*str == '\0' &amp;&amp; dots == 3)
            return 1;

        // Segment changeover.
        if (*str == '.')
        {
            // Limit number of segments.
            ++dots;
            if (dots == 4)
                return 0;

            // Reset segment values.
            chcnt = 0;
            accum = 0;
            ++str;
        }
    }
}
&lt;stdbool.h&gt;

Unless you need compatibility with C89 for some reason, I would use bool for the return type of the function and true and false as the possible values.

It helps readability.



sscanf()

This one depends on your performance needs.  A solution using sscanf() will be much easier to understand with a simple look and also shorter in code, but may also be much slower (a benchmark would be appropriate).

Update: I would discard sscanf() because it would accept spaces before the numbers; better use inet_pton() as @vnp suggested.



&lt;stdint.h&gt;

Same as with bool: segs seems at first glance to be some string, but after some time I realized it's just an array of 8-bit unsigned integers.  You should use uint8_t for that.

In case of &lt;stdint.h&gt; I would say that if you don't have it, you should do the typedefs yourself (enclosed in some #if) anyway.  Don't do that with bool, however, which is very dangerous.



Unneeded cast

unsigned char *p;
int i;

...
*p = (unsigned char)i;


This cast is not needed.

Usually casts are very dangerous: they can hide bugs that otherwise the compiler would catch easily.  Don't ever cast, unless you know a very good reason to.



BUG! (No, I was wrong)

// Check numeric.
if (*str &lt; '0' || *str &gt; '9')
        return 0;


This line returns 0 at the first dot it finds.  The function doesn't work!

This if that comes later is always false due to that:

// Segment changeover.
if (*str == '.') {
        /// Unreachable code!!!
}




&lt;ctype.h&gt;

There are some functions in &lt;ctype.h&gt; that you should use:

// Check numeric.
if (*str &lt; '0' || *str &gt; '9')
        return 0;


That code above can be simplified to this one (and the comment is now even more obvious and therefore removed ;-):

if (!isdigit((unsigned char)*str))
        return 0;



  NOTES: The standards require that the argument c for these functions is either EOF or a value that is representable in the type unsigned char.  If the argument c is of type char, it must be cast to unsigned char.
  
  This is necessary because char may be the equivalent of signed char, in which case a byte where the top bit is set would be sign extended when converting to int, yielding a value that is outside the range of unsigned char.


See man isdigit.

If you're going to use these functions, I would create an unsigned char pointer to alias the char * parameter, so that you don't need to cast all the time.