2

Need to convert string into unsigned int in C. I've tried using sscanf() and strtoul(), but both of them on inputting negative digits like -123 inverts them and do not signals about error.

I mean, that strtoul(-1) will return UNSIGNED_INT_MAX - 1 and not an error.

I need something that will do so:

"123" - fine

"-123" - wrong

"wewe" - wrong

"123wew" - wrong

8
  • The endptr parameter of strtoul will point to the first character in the string that isn't part of a valid unsigned integer constant; if it's not whitespace or 0, then the input is invalid. Commented Dec 10, 2015 at 16:07
  • 4
    This is not a good duplicate. The OP wants a conversion to unsigned. This is not as simple as it looks. I think you can use strtoul and check if the result (an unsigned long) can fit into an unsigned. Commented Dec 10, 2015 at 16:07
  • Just to add, if you want something very specific to your needs, you better roll out your own function. Most of the library functions are targeted to be generic, you know. :) Commented Dec 10, 2015 at 16:22
  • 2
    I don't understand why this question was downvoted. Converting into an unsigned int and throwing an error if a '-' is present is not trivial and I don't see an obvious duplicate. The OP has clearly stated his question and clarified with examples and what he's tried to do. This is a valid question that can help future users. Commented Dec 10, 2015 at 16:25
  • 1
    @chux Spaces before first digits should be OK, because in this case the number still can be allocated definitely. Commented Dec 11, 2015 at 17:39

4 Answers 4

6

You could try checking all the individual characters of the string to assure that they are digits (isdigit() is your friend) - and then if this passes, calling strtoul. Some may argue that you could do a regexp call or something instead - but at the end of the day something is going to have to do this check.

unsigned int convert(char *st) {
  char *x;
  for (x = st ; *x ; x++) {
    if (!isdigit(*x))
      return 0L;
  }
  return (strtoul(st, 0L, 10));
}

(I "return zero" if the string is invalid - you'll have to change the behavior to your liking")

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks! That a way of solving this
This is a good case where continue could improve code readability.
Better to use NULL than 0L in strtol(const char *nptr, char ** endptr, int base);
@iharob Unclear how continue would help.
if (isdigit(*x)) continue; return 0L;.
|
2

In order to get an error return value from a function aswell as an unsigned int, you can do something like the following. The code is self explanatory.

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

int atoui(char *in,unsigned int *out);

int main() 
{
    char str[4][7] = {{"123"},
                  {"-123"},
                  {"wewe"},
                  {"123wew"}};
    unsigned int ui,
             uc;

    for(uc = 0; uc < 4; uc++)
        if(atoui(str[uc],&ui))  printf("ERROR: %s\n",str[uc]);
        else printf("OK: %u\n",ui);

return 0; 
}

int atoui(char *in,unsigned int *out) 
{
    char *p;

    for(p = in; *p; p++) 
        if (*p > '9' || *p < '0') 
            return 1;

    *out = strtoul(in, NULL, 10);
return 0;
}

Comments

1

strtoul will set endptr to point to the first non-digit character in the input string; however, it doesn't catch the sign (because, after all, you are allowed to write unsigned int x = -1;).

So you'll have to do this in two stages; first, you'll have to look for the leading -; if you don't find it, use strtoul to do the conversion and check endptr:

char input[N];
char *p;

while ( fgets( input, sizeof input, input_stream ) )
{
  p = input;
  while ( isspace( *p ) ) // skip over any leading whitespace
    p++;

  if ( !isdigit( *p ) )
  {
    printf( "\"%s\" is not a valid unsigned integer string\n" );
  }
  else
  {
    char *endptr;
    unsigned int val = (unsigned int ) strtoul( p, &endptr, 0 );
    if ( isspace( *endptr) || *endptr == 0 )
      printf( "\"%s\" is a valid unsigned integer string: %u\n", val );
    else
      printf( "\"%s\" is *not* a valid integer string\n" );
  }
}      

Comments

1

Simply look for a '-', then call strtoul().

unsigned long PN_strtoul(const char *s, int *fail) {
  *fail = strchr(s, '-') != NULL;
  char *endptr;
  errno = 0;
  unsigned long ul = strtoul(s, &endptr, 10);
  // overflow? no conversion? trailing junk?
  if (errno || endptr == s || *endptr) *fail = 1;
  return ul;
}

This way, leading spaces and '+' are still allowed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.