String converter 
Author Message
 String converter

I like to write the function that get the string from the standard input the
check whether the string is integer and accept it, also accept the space
between the integer.
For example :
input: 123    432     422
How can i convert the string to integer.
I am using atoi however it only convert the first 123 and leave the rest.
When i test the function it show an error
"assignment make pointers from integer without a cast"
Can someone help me fix this problem.
int read(char *p)
{
 char message[90];
 int check;
 p=fgets(message,90,stdin);

 if (isdigit(*p)||isspace(*p))
 {
      check= atoi(p);
    return check;
  }

Quote:
}



Wed, 09 Feb 2005 15:03:59 GMT  
 String converter

Quote:

> I like to write the function that get the string from the standard input
the
> check whether the string is integer and accept it, also accept the space
> between the integer.
> For example :
> input: 123    432     422
> How can i convert the string to integer.
> I am using atoi however it only convert the first 123 and leave the rest.
> When i test the function it show an error
> "assignment make pointers from integer without a cast"
> Can someone help me fix this problem.
> int read(char *p)
> {
>  char message[90];
>  int check;
>  p=fgets(message,90,stdin);

>  if (isdigit(*p)||isspace(*p))
>  {
>       check= atoi(p);
>     return check;
>   }

> }

char *skipdecimal(const char *str)
{
   while(isspace(*str))
      str++;
   while(isdigit(*str))
      str++;
   return str;

- Show quoted text -

Quote:
}



Wed, 09 Feb 2005 17:44:15 GMT  
 String converter

Quote:

> I like to write the function that get the string from the standard input the
> check whether the string is integer and accept it, also accept the space
> between the integer.
> For example :
> input: 123    432     422
> How can i convert the string to integer.
> I am using atoi however it only convert the first 123 and leave the rest.
> When i test the function it show an error
> "assignment make pointers from integer without a cast"
> Can someone help me fix this problem.
> int read(char *p)
> {
>  char message[90];
>  int check;
>  p=fgets(message,90,stdin);

What is using 'p' good for? A simple local char pointer is all you need
(and the pointer you pass to the function will, luckily for you, not be
changed, anyway).

Quote:
>  if (isdigit(*p)||isspace(*p))
>  {
>       check= atoi(p);
>     return check;
>   }

Missing return value if the first character is neither a digit nor a
white space.

Quote:
> }

There are basically two strategies, both involving that you loop over
the string yourself. If you insist on using atoi() you will have to
check the contents of message one by one and for characters not being
digits (or a leading minus sign) you have to copy the later contents
of the array over the none-digit character(s), so that you end up with
a string only consisting of digits (except leading white space and a
minus sign).

Probably simpler is just looping over the string, skipping white space
and calculating the result manually, perhaps like this (take care,
code is untested):

int read( void )
{
    char message[ 90 ];
    char *cur;
    sign = 1;
    int val = 0;

    fgets( message, 90, stdin );

    /* Skip leading white space part of string and catch minus sign */

    for ( cur = message; *cur != '\0' && ! isdigit( *cur ) ; cur++ )
    {
        if ( *cur == '-' )
        {
            sign = -1;
            break;
        }

        if ( ! isspace( *cur ) )              /* invalid characer ? */
            exit( EXIT_FAILURE );
    }

    /* Loop over rest of string, calculating the resulting number and
       skipping white space */

    for ( ; *cur != '\0'; cur++ )
        if ( isdigit( *cur ) )
        {
            val = val * 10 + ( *cur - '0' );
            if ( val < 0 )                     /* integer overflow ? */
                exit( EXIT_FAILURE );
        }
        else if ( ! isspace( *cur ) )          /* invalid characer ? */
            exit( EXIT_FAILURE );

    return sign * val;

Quote:
}

As you see, you also have to think about what to do in cases where the
string either contains non-white-space character that aren't digits
or where the number is too large to be represented by an integer. What's
also not checked here is if there were any digits at all in the string,
in this case 0 is returned. I don't know if this is what you want, other-
wise you need an additional flag that gets set when an digit is found.
At the end you check if the flag is set, if not take the appropriate
action.
                                           Regards, Jens
--
      _  _____  _____

  _  | |  | |    | |
 | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
  \___/ens|_|homs|_|oerring


Wed, 09 Feb 2005 18:15:21 GMT  
 String converter

Quote:

> I like to write the function that get the string from the standard input the
> check whether the string is integer and accept it, also accept the space
> between the integer.

Already I'm confused by your requirements.  Perhaps you want more than one
function, the first of which just verifies the input contains only digits
and space characters?

Quote:
> For example :
> input: 123    432     422
> How can i convert the string to integer.
> I am using atoi however it only convert the first 123 and leave the rest.
> When i test the function it show an error
> "assignment make pointers from integer without a cast"

This error isn't from the function below, but you'll want to figure out
where exactly this is occurring, since it is a bug.

Quote:
> Can someone help me fix this problem.
> int read(char *p)

This is perhaps a bad function name, as "read" is often a system function.

Quote:
> {
>  char message[90];
>  int check;
>  p=fgets(message,90,stdin);

   Perhaps you don't realize the caller's char * passed to the function
will never be updated (but you wouldn't want to return a pointer to
memory local to the function anyway).

Quote:
>  if (isdigit(*p)||isspace(*p))

You don't know that p != NULL, so *p could crash your program. Also, this
only checks the first character of the buffer, but you apparently want
to check them all.

Quote:
>  {
>       check= atoi(p);

atoi() is not a great function since you can't catch errors with it.
You're problem would be better addressed using strtol().

Quote:
>     return check;
>   }

> }

You're probably better off just trying to parse out the
string into a dynamic array of ints, and failing on error:

#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
/*
 * parse_ints: splits "line" into "nums", returning the count.
 * "nums" is a dynamically allocated int *, and must be freed
 * by the caller if parse_ints returns a number greater than
 * zero.
 * Returns -1 on error.
 */
int parse_ints (char *line, int **nums) {
    int count = 0;
    int errors = 0;
    long number;
    int *array = NULL, *iptr;
    char *cptr, *endptr;

    cptr = line;
    while (cptr != NULL && *cptr != '\0' && !errors) {
         errno = 0;
         number = strtol (cptr, &endptr, 10);
         if (cptr == endptr || errno == ERANGE) errors++;
         if (number < INT_MIN || number > INT_MAX) errors++;
         if (!errors) {
             iptr = realloc (array, sizeof *iptr * (count + 1));
             if (iptr != NULL) {
                 array = iptr;
                 array[count++] = (int) number;
             }
             else {
                errors++;
             }
         }
         cptr = endptr;
         while (isspace(*cptr))
             cptr++;
    }
    if (errors) {
        free (array);
        count = -1;
    }
    else {
        *nums = array;
    }
    return count;

Quote:
}



Wed, 09 Feb 2005 19:21:02 GMT  
 String converter
On Sat, 24 Aug 2002 17:03:59 +1000, in comp.lang.c , "tritran"

Quote:

>I like to write the function that get the string from the standard input the
>check whether the string is integer and accept it, also accept the space
>between the integer.
>For example :
>input: 123    432     422
>How can i convert the string to integer.

do you mean that you want to get the value 123432422? Or do you want
to get each integer in turn ie 3 values? If the latter, use fgets and
then strtok or something similar. If the former, copy each char into a
new string provided its not blank. Be careful of overflowing your
chosen integer type.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>



Wed, 09 Feb 2005 23:30:30 GMT  
 String converter



Quote:

> > I like to write the function that get the string from the standard input
the
> > check whether the string is integer and accept it, also accept the space
> > between the integer.

> Already I'm confused by your requirements.  Perhaps you want more than one
> function, the first of which just verifies the input contains only digits
> and space characters?

> > For example :
> > input: 123    432     422
> > How can i convert the string to integer.
> > I am using atoi however it only convert the first 123 and leave the
rest.
> > When i test the function it show an error
> > "assignment make pointers from integer without a cast"

> This error isn't from the function below, but you'll want to figure out
> where exactly this is occurring, since it is a bug.

> > Can someone help me fix this problem.
> > int read(char *p)

> This is perhaps a bad function name, as "read" is often a system function.

> > {
> >  char message[90];
> >  int check;
> >  p=fgets(message,90,stdin);

>    Perhaps you don't realize the caller's char * passed to the function
> will never be updated (but you wouldn't want to return a pointer to
> memory local to the function anyway).

> >  if (isdigit(*p)||isspace(*p))

> You don't know that p != NULL, so *p could crash your program. Also, this
> only checks the first character of the buffer, but you apparently want
> to check them all.

> >  {
> >       check= atoi(p);

> atoi() is not a great function since you can't catch errors with it.
> You're problem would be better addressed using strtol().

> >     return check;
> >   }

> > }

> You're probably better off just trying to parse out the
> string into a dynamic array of ints, and failing on error:

Thank you very much for answer me this problem however i am a newbie and i
haven't study much about pointers and your way seem difficult for me to
catch up. Could you please provide the simple one or explain to me step by
step.

Quote:
> #include <stdlib.h>
> #include <limits.h>
> #include <errno.h>
> #include <ctype.h>
> /*
>  * parse_ints: splits "line" into "nums", returning the count.
>  * "nums" is a dynamically allocated int *, and must be freed
>  * by the caller if parse_ints returns a number greater than
>  * zero.
>  * Returns -1 on error.
>  */
> int parse_ints (char *line, int **nums) {

What's "**" use for? Why we need this one?

Quote:
>     int count = 0;
>     int errors = 0;
>     long number;
>     int *array = NULL, *iptr;
>     char *cptr, *endptr;

>     cptr = line;
>     while (cptr != NULL && *cptr != '\0' && !errors) {
>          errno = 0;
>          number = strtol (cptr, &endptr, 10);
>          if (cptr == endptr || errno == ERANGE) errors++;
>          if (number < INT_MIN || number > INT_MAX) errors++;

you haven't declare the varibale for INT_MIN and INT_MAX are they from
limits.h
         if (!errors) {

Quote:
>              iptr = realloc (array, sizeof *iptr * (count + 1));

I haven't study up to realloc so that any other way to do without having a
problem with memory allocation

Quote:
>              if (iptr != NULL) {
>                  array = iptr;
>                  array[count++] = (int) number;
>              }
>              else {
>                 errors++;
>              }
>          }
>          cptr = endptr;
>          while (isspace(*cptr))
>              cptr++;
>     }
>     if (errors) {
>         free (array);

Is free() function is use to free the memory when you using realloc, could
you explain why we need to free the memory after using the calloc or realloc
I read from "the book on C " but hardly to understand why and sometime we
have to use sizeof(something) but above you are using sizeof *iptr is it the
right syntax

- Show quoted text -

Quote:
>         count = -1;
>     }
>     else {
>         *nums = array;
>     }
>     return count;
> }



Thu, 10 Feb 2005 12:25:58 GMT  
 String converter
Thank you so much but i would like to know that how we use flag to detect
the errors in this program and if the input like 123    456 it will return
the error because it's not an integer how can i do that and why you need to
catch the '-' sign caused also want to input the negative number .

Quote:

> > I like to write the function that get the string from the standard input
the
> > check whether the string is integer and accept it, also accept the space
> > between the integer.
> > For example :
> > input: 123    432     422
> > How can i convert the string to integer.
> > I am using atoi however it only convert the first 123 and leave the
rest.
> > When i test the function it show an error
> > "assignment make pointers from integer without a cast"
> > Can someone help me fix this problem.
> > int read(char *p)
> > {
> >  char message[90];
> >  int check;
> >  p=fgets(message,90,stdin);

> What is using 'p' good for? A simple local char pointer is all you need
> (and the pointer you pass to the function will, luckily for you, not be
> changed, anyway).

> >  if (isdigit(*p)||isspace(*p))
> >  {
> >       check= atoi(p);
> >     return check;
> >   }

> Missing return value if the first character is neither a digit nor a
> white space.

> > }

> There are basically two strategies, both involving that you loop over
> the string yourself. If you insist on using atoi() you will have to
> check the contents of message one by one and for characters not being
> digits (or a leading minus sign) you have to copy the later contents
> of the array over the none-digit character(s), so that you end up with
> a string only consisting of digits (except leading white space and a
> minus sign).

> Probably simpler is just looping over the string, skipping white space
> and calculating the result manually, perhaps like this (take care,
> code is untested):

> int read( void )
> {
>     char message[ 90 ];
>     char *cur;
>     sign = 1;
>     int val = 0;

>     fgets( message, 90, stdin );

>     /* Skip leading white space part of string and catch minus sign */

>     for ( cur = message; *cur != '\0' && ! isdigit( *cur ) ; cur++ )
>     {
>         if ( *cur == '-' )
>         {
>             sign = -1;
>             break;
>         }

>         if ( ! isspace( *cur ) )              /* invalid characer ? */
>             exit( EXIT_FAILURE );
>     }

>     /* Loop over rest of string, calculating the resulting number and
>        skipping white space */

>     for ( ; *cur != '\0'; cur++ )
>         if ( isdigit( *cur ) )
>         {
>             val = val * 10 + ( *cur - '0' );
>             if ( val < 0 )                     /* integer overflow ? */
>                 exit( EXIT_FAILURE );
>         }
>         else if ( ! isspace( *cur ) )          /* invalid characer ? */
>             exit( EXIT_FAILURE );

>     return sign * val;
> }

> As you see, you also have to think about what to do in cases where the
> string either contains non-white-space character that aren't digits
> or where the number is too large to be represented by an integer. What's
> also not checked here is if there were any digits at all in the string,
> in this case 0 is returned. I don't know if this is what you want, other-
> wise you need an additional flag that gets set when an digit is found.
> At the end you check if the flag is set, if not take the appropriate
> action.
>                                            Regards, Jens
> --
>       _  _____  _____

>   _  | |  | |    | |
>  | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
>   \___/ens|_|homs|_|oerring



Thu, 10 Feb 2005 21:46:30 GMT  
 String converter
I look at your program and found that there is the problem when i enter more
than 10 integer number for example
input: 1234567891
output: 1234567891
however
input: 12345678912
output: 1494771484
if more than 12 character it will not tested or appear the output. Could you
please explain to me how come the output like that i tried to debug several
time but it's not correct, may be i am not clearly understand your program
.Correct me if i am wrong:
/* You trying to read the string from the first character
to the '\0' and check each of them is number or not */
 for ( ; *cur != '\0'; cur++ )
        if ( isdigit( *cur ) )
        {
            /*i am not clearly understand why we have to multiply by 10
here, is it the way we check the number */
            val = val * 10 + ( *cur - '0' );
           if ( val < 0 )                     /* integer overflow ? */
                exit( EXIT_FAILURE );
        }
        else if ( ! isspace( *cur ) )          /* invalid characer ? */
            exit( EXIT_FAILURE );.
Another problem is that the result will not treat the input string as an
integer caused when i tested
with only 1 number such as choice the option from menu and found that it's
return the value as the string or
different value for example enter an integer 5 it's print out the different
number but not 5. Also can i use atoi
to convert the string into the integer, how can i implement your program
with atoi.


Quote:

> > I like to write the function that get the string from the standard input
the
> > check whether the string is integer and accept it, also accept the space
> > between the integer.
> > For example :
> > input: 123    432     422
> > How can i convert the string to integer.
> > I am using atoi however it only convert the first 123 and leave the
rest.
> > When i test the function it show an error
> > "assignment make pointers from integer without a cast"
> > Can someone help me fix this problem.
> > int read(char *p)
> > {
> >  char message[90];
> >  int check;
> >  p=fgets(message,90,stdin);

> What is using 'p' good for? A simple local char pointer is all you need
> (and the pointer you pass to the function will, luckily for you, not be
> changed, anyway).

> >  if (isdigit(*p)||isspace(*p))
> >  {
> >       check= atoi(p);
> >     return check;
> >   }

> Missing return value if the first character is neither a digit nor a
> white space.

> > }

> There are basically two strategies, both involving that you loop over
> the string yourself. If you insist on using atoi() you will have to
> check the contents of message one by one and for characters not being
> digits (or a leading minus sign) you have to copy the later contents
> of the array over the none-digit character(s), so that you end up with
> a string only consisting of digits (except leading white space and a
> minus sign).

> Probably simpler is just looping over the string, skipping white space
> and calculating the result manually, perhaps like this (take care,
> code is untested):

> int read( void )
> {
>     char message[ 90 ];
>     char *cur;
>     sign = 1;
>     int val = 0;

>     fgets( message, 90, stdin );

>     /* Skip leading white space part of string and catch minus sign */

>     for ( cur = message; *cur != '\0' && ! isdigit( *cur ) ; cur++ )
>     {
>         if ( *cur == '-' )
>         {
>             sign = -1;
>             break;
>         }

>         if ( ! isspace( *cur ) )              /* invalid characer ? */
>             exit( EXIT_FAILURE );
>     }

>     /* Loop over rest of string, calculating the resulting number and
>        skipping white space */

>     for ( ; *cur != '\0'; cur++ )
>         if ( isdigit( *cur ) )
>         {
>             val = val * 10 + ( *cur - '0' );
>             if ( val < 0 )                     /* integer overflow ? */
>                 exit( EXIT_FAILURE );
>         }
>         else if ( ! isspace( *cur ) )          /* invalid characer ? */
>             exit( EXIT_FAILURE );

>     return sign * val;
> }

> As you see, you also have to think about what to do in cases where the
> string either contains non-white-space character that aren't digits
> or where the number is too large to be represented by an integer. What's
> also not checked here is if there were any digits at all in the string,
> in this case 0 is returned. I don't know if this is what you want, other-
> wise you need an additional flag that gets set when an digit is found.
> At the end you check if the flag is set, if not take the appropriate
> action.
>                                            Regards, Jens
> --
>       _  _____  _____

>   _  | |  | |    | |
>  | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
>   \___/ens|_|homs|_|oerring



Thu, 10 Feb 2005 23:12:42 GMT  
 String converter

Quote:

> Thank you so much but i would like to know that how we use flag to detect
> the errors in this program and if the input like 123    456 it will return
> the error because it's not an integer how can i do that and why you need to
> catch the '-' sign caused also want to input the negative number .

As far as I understood you you want to get the number 12345 from an
input string like "  12  3   45  ", if this isn't the case you can
forget about all of the rest.

I now included the flag ('found_digit') to figure out if there were any
digits at all in the input, see below. And, since you were writing about
integers you obviously have to take into account negative numbers and
thus minus signs. And, finally, since you were only testing for white-
space characters I assume that other non-digits are to be treated as an
error in the input.

Quote:
> I look at your program and found that there is the problem when i enter more
> than 10 integer number for example
> input: 1234567891
> output: 1234567891
> however
> input: 12345678912
> output: 1494771484
> if more than 12 character it will not tested or appear the output. Could you
> please explain to me how come the output like that i tried to debug several

Integers can only represent numbers up to certain limits. The standard only
requires that integers in the range between -32767 and 32767 must be
representable. Your implementation seems to allow larger value, from the
look of it you have 4 byte integers, resulting into a representable range
between 2147483647 and -2147483647 (or similar, to find out look up the
INT_MAX and INT_MIN values in linits.h). Thus you simply can't store
numbers like 12345678912, they are too large. It's possible (but not
required) that long integers can store larger numbers, too find out check
the LONG_MAX and LONG_MIN values in limits.h.

Quote:
> time but it's not correct, may be i am not clearly understand your program
> .Correct me if i am wrong:
> /* You trying to read the string from the first character
> to the '\0' and check each of them is number or not */
>     for ( ; *cur != '\0'; cur++ )
>            if ( isdigit( *cur ) )
>            {
>                /*i am not clearly understand why we have to multiply by 10
> here, is it the way we check the number */
>                val = val * 10 + ( *cur - '0' );
>               if ( val < 0 )                     /* integer overflow ? */
>                    exit( EXIT_FAILURE );
>            }

No, the multiplication by 10 is simply how you calculate the number. Let's
assume you have the string "123". 'val' is 0 at first, so multiplication
with 10 leaves it 0. Now you add the first number from the string, 1
(but since you only have the character representation of the number, the
character '1', you must subtract the char representation of '0' to get
the *number* 1). 'val' is now 1. The next time through the loop, 1 is
multiplicated by ten, giving you 10. Now 2 is added, so 'val' is now 12.
The next and last time through the loop, the multiplication gives 120,
then you add 3 and thus end up with val beeing 123, the number you were
looking for.

The check if 'val' is negative is there to find out if the number got
larger than the maximum value you can represent with an integer value.
In this case you get a wrap-around, i.e. too large a number gets truncated
and you end up with a *negative* number.

Quote:
>            else if ( ! isspace( *cur ) )          /* invalid characer ? */
>                exit( EXIT_FAILURE );.
> Another problem is that the result will not treat the input string as an
> integer caused when i tested
> with only 1 number such as choice the option from menu and found that it's
> return the value as the string or
> different value for example enter an integer 5 it's print out the different
> number but not 5. Also can i use atoi

Sorry, I don't understand what you mean here. Could you please try to
rephrase it a bit?

Quote:
> to convert the string into the integer, how can i implement your program
> with atoi.

I also added a version where you can use atoi(). Unfortunately, it's even
more complicated because of all the necessary copying within the string.
Also finding out if the number in the string isn't too large is a bit more
tricky. I hope the comments give you an idea how it works.

                                          Regards, Jens

PS: Please stop top-posting: put your comments etc. below what you
    quote of other peoples messages. This way it's much easier to
    follow what you refer to. And please also remove everything not
    strictly necessary from what you quote, no-one likes to have to
    browse through hundreds of lines of useless text just to find the
    one interesting point.

----------------------8<---------------------------------------------------
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

int read_int_v1( const char *message );
int read_int_v2( const char *message );

int main( void )
{
    char message[ 90 ];

    if ( fgets( message, 90, stdin ) == NULL )
    {
        fprintf( stderr, "No input found\n" );
        exit( EXIT_FAILURE );
    }

    printf( "Version 1: You entered %d\n", read_int_v1( message ) );
    printf( "Version 2: You entered %d\n", read_int_v2( message ) );
    return EXIT_SUCCESS;

Quote:
}

int read_int_v1( const char *message )
{
    const char *cur;
    int sign = 1;
    int val = 0;
    int found_digit = 0;

    /* Skip leading white space at start of string and catch minus sign */

    for ( cur = message; *cur != '\0' && ! isdigit( *cur ) ; cur++ )
    {
        if ( *cur == '-' )
        {
            sign = -1;
            cur++;
            break;
        }

        if ( ! isspace( *cur ) )              /* invalid characer ? */
        {
            fprintf( stderr, "Invalid character: '%c'\n", *cur );
            exit( EXIT_FAILURE );
        }
    }

    /* Loop over rest of string, calculating the resulting number and
       skipping white space */

    for ( ; *cur != '\0'; cur++ )
        if ( isdigit( *cur ) )
        {
            found_digit = 1;
            val = val * 10 + ( *cur - '0' );
            if ( val < 0 )                     /* integer overflow ? */
            {
                fprintf( stderr, "Integer overflow\n" );
                exit( EXIT_FAILURE );
            }
        }
        else if ( ! isspace( *cur ) )          /* invalid characer ? */
        {
            fprintf( stderr, "Invalid character: '%c'\n", *cur );
            exit( EXIT_FAILURE );
        }

    /* Check if there were any digits at all in the input */

    if ( ! found_digit )
    {
        fprintf( stderr, "No digits found in input\n" );
        exit( EXIT_FAILURE );
    }

    return sign * val;

Quote:
}

int read_int_v2( const char *message )
{
    char str[ 90 ];
    char buffer[ 90 ];
    char *p0, *p1, *p2, *p_end;
    int res;

    /* Make sure to only modify a copy of the input string, so the function
       can also be applied to strings we're not allowed to modify. */

    strcpy( str, message );

    /* Start off by looking for the first character that's either a digit
       or a minus sign (bail out when there's an error in the input). */

    for ( p0 = str; *p0 != '\0' && isspace( *p0 ) && *p0 != '-'; p0++ )
          /* empty */ ;

    if ( *p0 == '\0' )
    {
        fprintf( stderr, "No numbers found in input\n" );
        exit( EXIT_FAILURE );
    }

    if ( ! isdigit( *p0 ) && *p0 != '-' )
    {
        fprintf( stderr, "Invalid character: '%c'\n", *p0 );
        exit( EXIT_FAILURE );
    }

    /* Also calculate a pointer to the very end of the input string, i.e.
       the trailing '\0'. */

    for ( p_end = p0 + 1; *p_end != '\0'; p_end++ )
        /* empty */ ;

    /* p0 points now to the first digit or a minus sign. Now, in the remaining
       string, look for sets of white-space characters followed by a digit. In
       this case we simply copy everything following this region to the place
       where the first white-space character was found. */

    for ( p1 = p0 + 1; *p1 != '\0'; p1++ )
    {
        if ( isdigit( *p1 ) )
             continue;

        if ( ! isspace( *p1 ) )
        {
            fprintf( stderr, "Invalid character: '%c'\n", *p1 );
            exit( EXIT_FAILURE );
        }

        /* p1 now points to a white-space character. Loop over the following
           characters, using pointer p2, until a digit is found (or an error
           in the input is detected). */

        for ( p2 = p1 + 1; p2 != '\0' && isspace( *p2 ); p2++ )
            /* empty */ ;

        if ( *p2 == '\0' )       /* string ended with white-space ? */
        {
            *p1 = '\0';
            break;
        }

        if ( ! isdigit( *p2 ) )
        {
            fprintf( stderr, "Invalid character: '%c'\n", *p2 );
            exit( EXIT_FAILURE );
        }

        /* p2 now points to a digit and we move everything from p2 to the
           end of the string (including the trailing '\0') to where p1
           points. Since the string is now shorter we also have to correct
           the end pointer, p_end. */

        memmove( p1, p2, p_end - p2 + 1 );
        p_end -= p2 - p1;
    }

    /* Now check that we didn't got just a minus sign and nothing else. */

    if ( *p0 == '-' && *( p0 + 1 ) == '\0' )
    {
        fprintf( stderr, "Only found a minus sign\n" );
        exit( EXIT_FAILURE );
    }

    /* Before we can return the result of applying atoi() to p0 we must
       check that the number we got isn't too large for an integer. We
       do this by comparing the cleaned-up string with the one we get when
       we print the return value of atoi() into a string. If both are
       identical everything's ok, otherwise the original number was too
       large for an integer. */

    res = atoi( p0 );
    sprintf( buffer, "%d", res );
    if ( strcmp( p0, buffer ) )      /* strings differ ? */
...

read more »



Fri, 11 Feb 2005 21:44:43 GMT  
 String converter

Quote:


>> You're probably better off just trying to parse out the
>> string into a dynamic array of ints, and failing on error:

> Thank you very much for answer me this problem however i am a newbie and i
> haven't study much about pointers and your way seem difficult for me to
> catch up. Could you please provide the simple one or explain to me step by
> step.

Well, one solution is my limit ;-)  But, I'll try to explain...

Quote:
>> #include <stdlib.h>
>> #include <limits.h>
>> #include <errno.h>
>> #include <ctype.h>
>> /*
>>  * parse_ints: splits "line" into "nums", returning the count.
>>  * "nums" is a dynamically allocated int *, and must be freed
>>  * by the caller if parse_ints returns a number greater than
>>  * zero.
>>  * Returns -1 on error.
>>  */
>> int parse_ints (char *line, int **nums) {
> What's "**" use for? Why we need this one?

This function "returns" two things.  Well, you can only return one thing
from a C function, but the caller will need not only the array of ints,
but also how many there are.  So the function returns the "count", the
normal way, and returns the dynamically allocated array via a pointer to
pointer supplied by the caller.  All C functions receive their arguments
by value.  So, in order to "return" the array, the caller sends a pointer
to the pointer that will hold the result.  Maybe, a demonstration:

Calling function:

    int *nums = NULL;
    int count = parse_ints (instr, &nums);
    ...

Taking the address of a variable yields a pointer to that variable. Now,
parse_ints can change its view of "nums" all it wants and the caller will
never see the changes.  However, if parse_ints changes "*nums", then
the caller will see the changes.

The caller originally has:

     nums -> NULL

The caller calls parse_ints with "&nums" and parse_ints sees:

     nums -> <some address> -> NULL (same NULL from caller).

Then parse_ints updates *nums:

     int * array = ... ;  /* create the array somehow ... */    
     *nums = array;       /* Sets the callers "nums" to array */

Well, that probably didn't make any sense... Sorry ;-(

Quote:
>>     int count = 0;
>>     int errors = 0;
>>     long number;
>>     int *array = NULL, *iptr;
>>     char *cptr, *endptr;

>>     cptr = line;
>>     while (cptr != NULL && *cptr != '\0' && !errors) {
>>          errno = 0;
>>          number = strtol (cptr, &endptr, 10);
>>          if (cptr == endptr || errno == ERANGE) errors++;
>>          if (number < INT_MIN || number > INT_MAX) errors++;
> you haven't declare the varibale for INT_MIN and INT_MAX are they from
> limits.h

limits.h is a standard header that includes many useful constants,
like INT_MIN, CHAR_BIT, etc...

Quote:
>          if (!errors) {
>>              iptr = realloc (array, sizeof *iptr * (count + 1));

> I haven't study up to realloc so that any other way to do without having a
> problem with memory allocation

An alternative way might be to set a limit on the number of ints in a "line"
of input, then you could use a static declaration.  Or possibly just use
a static quantity, but make it possible to process each input line partially.
I gave a general solution since I didn't have enough info to judge how the
function would be used.

Quote:

>>              if (iptr != NULL) {
>>                  array = iptr;
>>                  array[count++] = (int) number;
>>              }
>>              else {
>>                 errors++;
>>              }
>>          }
>>          cptr = endptr;
>>          while (isspace(*cptr))
>>              cptr++;
>>     }
>>     if (errors) {
>>         free (array);
> Is free() function is use to free the memory when you using realloc, could
> you explain why we need to free the memory after using the calloc or realloc
> I read from "the book on C " but hardly to understand why and sometime we
> have to use sizeof(something) but above you are using sizeof *iptr is it the
> right syntax

malloc, calloc and realloc allocate dynamic memory from "somewhere".  This
memory is not released back to the operating system unless it is explicitly
free'd or the program exits (on most hosted OS's).  So, every time you use
these functions, you grab more system memory for an indefinite period.  If
you don't free memory when you no longer are using it and lose all pointers
to the memory location, you create a memory leak (i.e. you have no way to
free or reuse the memory, but the OS still thinks you're using it).  Higher
level languages tend to provide methods to automatically free memory when
it is no longer used, but in C you must take care of memory management
yourself.

Note: The above free() call is only called if an error occurred.  Otherwise,
the function assumes that the caller will free the memory when they're done
with it.  For instance:

    char buff[80];
    int  *nums = NULL;
    int  count;
    while (NULL != fgets (buff, sizeof buff, stdin)) {
        count = parse_ints (buff, &nums);
        if (count > 0) {
            /* do something with "nums" */
            free (nums);
            nums = NULL;
        }
        else if (count < 0) {
            /* report the error */
        }
        else {
            /* report empty input? */
        }
     }



Sat, 12 Feb 2005 11:44:01 GMT  
 String converter

...

Quote:
> Probably simpler is just looping over the string, skipping white space
> and calculating the result manually, perhaps like this (take care,
> code is untested):
...
>             val = val * 10 + ( *cur - '0' );
>             if ( val < 0 )                     /* integer overflow ? */
>                 exit( EXIT_FAILURE );

This isn't safe.  First off, overflow is Undefined Behavior,
and can trap before ever getting to your test.  But even
on a machine that silently wraps, as many do nowadays,
this doesn't catch about half of all overflows.  Consider,
on a 16-bit system (for simplicity), 65540.  After four
digits val==6554 and *cur=='0'.  val*10 wraps to 4,
plus 0 is 4, is not < 0 but has overflowed.

--
- David.Thompson 1 now at worldnet.att.net



Mon, 14 Feb 2005 04:17:48 GMT  
 String converter

Quote:


> ...
>> Probably simpler is just looping over the string, skipping white space
>> and calculating the result manually, perhaps like this (take care,
>> code is untested):
> ...
>>             val = val * 10 + ( *cur - '0' );
>>             if ( val < 0 )                     /* integer overflow ? */
>>                 exit( EXIT_FAILURE );
> This isn't safe.  First off, overflow is Undefined Behavior,
> and can trap before ever getting to your test.  But even
> on a machine that silently wraps, as many do nowadays,
> this doesn't catch about half of all overflows.  Consider,
> on a 16-bit system (for simplicity), 65540.  After four
> digits val==6554 and *cur=='0'.  val*10 wraps to 4,
> plus 0 is 4, is not < 0 but has overflowed.

Unfortunately, you're completely right. At least I had the "untested
code" bit in there ;-) But seriously, the only working alternative I
came up with is

    if ( val > ( INT_MAX - ( *p - '0' ) ) / 10 )
        return EXIT_FAILURE;
    val = val * 10 + ( *p - '0' );

But this more or less requires to do the calculation twice. (And to make
it work cleanly for both positive and negative integers I would need two
different loops because INT_MAX isn't necessarily equal to -INT_MIN and
even writing -INT_MIN might lead to trouble if INT_MAX < -INT_MIN). Any-
one with an idea for a better and more elegant method?

                                           Regards, Jens
--
      _  _____  _____

  _  | |  | |    | |
 | |_| |  | |    | |          http://www.physik.fu-berlin.de/~toerring
  \___/ens|_|homs|_|oerring



Mon, 14 Feb 2005 05:35:54 GMT  
 String converter

Quote:

...
> > This isn't safe.  First off, overflow is Undefined Behavior,
> > and can trap before ever getting to your test.  But even
> > on a machine that silently wraps, as many do nowadays,
> > this doesn't catch about half of all overflows.  ...

> Unfortunately, you're completely right. At least I had the "untested
> code" bit in there ;-) But seriously, the only working alternative I
> came up with is

>     if ( val > ( INT_MAX - ( *p - '0' ) ) / 10 )
>         return EXIT_FAILURE;
>     val = val * 10 + ( *p - '0' );

> But this more or less requires to do the calculation twice. (And to make
> it work cleanly for both positive and negative integers I would need two
> different loops because INT_MAX isn't necessarily equal to -INT_MIN and
> even writing -INT_MIN might lead to trouble if INT_MAX < -INT_MIN). Any-
> one with an idea for a better and more elegant method?

Not really.  You can avoid the division most of the time,
which is usually the most costly operation (although on
machines with 1->2 multiplication can and might be
implemented as a scaled multiplication by the reciprocal,
or perhaps by floating-point multiplication by the reciprocal
if FP is available and the conversion isn't too costly),
by testing first for val <= (INT_MAX/10)-1, which should be
precomputed by the compiler, and handling the "teetering on
the edge" cases separately (on machines with silent wrap,
_these_ cases do produce a negative result).

Yes, INT_MIN == -INT_MAX-1 (in 2sC) is a problem.
I usually punt by converting to the string to _unsigned_ int
and then worrying about the sign (although it is also
theoretically possible that UINT_MAX == INT_MAX)
or actually to _unsigned long_ and then worry about
narrowing _or_ limiting to a range _and/or_ sign.

--
- David.Thompson 1 now at worldnet.att.net



Fri, 18 Feb 2005 12:56:16 GMT  
 String converter
[on avoiding overflow in a strtol()-equivalent function]

Quote:

>>>             val = val * 10 + ( *cur - '0' );
>>>             if ( val < 0 )                     /* integer overflow ? */

>> This isn't safe.  First off, overflow is Undefined Behavior,
>> and can trap before ever getting to your test.  But even
>> on a machine that silently wraps, as many do nowadays,
>> this doesn't catch about half of all overflows.  Consider,
>> on a 16-bit system (for simplicity), 65540.  After four
>> digits val==6554 and *cur=='0'.  val*10 wraps to 4,
>> plus 0 is 4, is not < 0 but has overflowed.


Quote:

>Unfortunately, you're completely right. At least I had the "untested
>code" bit in there ;-) But seriously, the only working alternative I
>came up with is

>    if ( val > ( INT_MAX - ( *p - '0' ) ) / 10 )
>        return EXIT_FAILURE;
>    val = val * 10 + ( *p - '0' );

>But this more or less requires to do the calculation twice. (And to make
>it work cleanly for both positive and negative integers I would need two
>different loops because INT_MAX isn't necessarily equal to -INT_MIN and
>even writing -INT_MIN might lead to trouble if INT_MAX < -INT_MIN). Any-
>one with an idea for a better and more elegant method?

What I used in my strtol() implementation goes something like this:

 - Calculate the number that, if there is another valid digit, results
   in potential overflow.  If the number is nonnegative and INT_MAX is
   32767 and we are working in base ten, this is 3276.  If the number
   is negative and INT_MIN is -32768 (and we are still working in base
   ten), the number is again 3276, although this time -3276.  Call
   this the "cutoff" number -- inputs that exceed the cutoff definitely
   overflow, while inputs that exactly equal the cutoff may be OK.

 - Next, calculate the digit beyond which overflow occurs.  For
   our two cases (nonnegative and negative), these are 7 and 8
   respectively.  Call this the limit for "cutoff numbers", i.e.,
   an input of 3276 with a following digit of 7 (for positive)
   or 8 (for negative) is OK, but one with anything greater than
   7 (respectively 8) is not.

Note that these numbers are simply INT_MAX / 10 and INT_MAX % 10
(and similar for INT_MIN, although in C89 the rounding direction
is not specified in advance).

Now we have an easy test for "will overflow" (but watch out for
sign inversion for negative numbers):

    if (there is another valid digit) {
        if (val > cutoff ||                     /* e.g., val > 3276 */
            (val == cutoff && digit > cutlim))  /* e.g., 3276 but digit is 9 */
            ... handle would-overflow error ...
        else
            val = val * 10 + digit;
    }

(In my code, I actually did all the work in "unsigned"s and negated
at the end, I think.  I would have to check.)
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)





Fri, 18 Feb 2005 18:00:42 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. newbie needs help to strings, strings, strings

2. how to register a file converter?

3. Bit Converter for Bitmap

4. C code to C# converter

5. VB.NET to C# Converter

6. Converter from Occam to C

7. C to Forth converter

8. C to Fortran-77 Converter?

9. AWK converters

10. Pascal to C converter

11. TAL to C converter

12. f2c converter/polisher

 

 
Powered by phpBB® Forum Software