Strtok and Strtol
/**************************************************************************/
/*                                                                        */
/*   Demonstration of user input parsing and conversion of user input     */
/*   to a decimal integer.                                                */
/**************************************************************************/

#include <stdlib.h>   /* Library where strtol is located. */
#include <string.h>   /* Library where strtok is located. */
#include <stdio.h>    /* Library for gets, printf, etc.   */

main()
{
   int tokennum, num;
   char line[256], *linep, *tokenptr, *endp;

   /*********************************************************/
   /*                                                       */
   /*  Assume user is entering an arbitrary number of       */
   /*  space and/or tab delimited integers per line.        */
   /*  Report all strings which are not correct integers.   */
   /*********************************************************/

   while (printf("\nEnter some integers: "),gets(line),strcmp(line, "quit"))
   {
   /********  For token 1, first arg. of strtok must be non-NULL.   *******/
   /********  For tokens 2 thru N, first argument of strtok is NULL *******/
   /********  When strtok encounters no non-delim chars before '\0' *******/
   /********  it returns NULL.                                      *******/

      for (tokennum = 1, linep = line;
          (tokenptr = strtok(linep, "\040\t")) != NULL;
           tokennum++, linep = NULL)
      {
            num = (int) strtol(tokenptr, &endp, 10);
            if (*endp != '\0')
            {
               printf("Token number %d is not a valid integer!\n", tokennum);
            }            
            else
            {
               printf("Token number %d is = %d\n", tokennum, num);
            }
      }
   }
}

/*****************  SAMPLE EXECUTION OF CODE ON PAGE 1  *********************/

Enter some integers: 

Enter some integers: 4 5 x
Token number 1 is = 4
Token number 2 is = 5
Token number 3 is not a valid integer!

Enter some integers: 3 x4 5
Token number 1 is = 3
Token number 2 is not a valid integer!
Token number 3 is = 5

Enter some integers: x
Token number 1 is not a valid integer!

Enter some integers:      10            12x5   3

Token number 1 is = 10
Token number 2 is not a valid integer!
Token number 3 is = 3

Enter some integers: x23
The first token is not a valid integer!

Enter some integers: 23
Token number 1 is = 23

Enter some integers: 10   20                            66
Token number 1 is = 10
Token number 2 is = 20
Token number 3 is = 66

Enter some integers: quit
$ 


/**************  KEY POINTS TO BE REMEMBERED ABOUT strtok/strtol  ************/

1. Strtok needs the name of the string variable on the first call to parse a
   string.  After that, if given NULL as a first argument, it assumes it is
   still parsing THE SAME STRING!!!

2. Strtok returns NULL if it cannot find any more tokens in the string starting
   from the current point out to the terminating '\0'.

3. Strtok places '\0' characters between tokens while it parses a string.  This
   means that it MANGLES THE STRING!!  If you need to use the original string
   later -- do a strcpy of it to ANOTHER string variable.

4. The string pointer returned by strtok points to a string that has NO 
   DELIMITER CHARACTERS (i.e. characters passed as the second argument.).

5. Strtol returns a long int if it can find one.  Thus, 56X will cause a 56
   to be returned but the endp will point to the "X".  Thus, strtol's second
   argument (endp) will point to the first character in the token that is
   not part of a valid integer.  If it is a good token, that character should
   be '\0'.  If strtol runs into an invalid char before finding any long int
   (e.g. X56), then it returns zero and endp will point at the "X".

6. If strtol is given a number which is a legal number but cannot fit into
   into a long int, strtol will return HUGE_VAL and errno will be set to
   ERANGE (if you remember to include errno.h!!).  Remember to set errno
   to zero before each call to strtol, if you use errno.  ERANGE may not
   be relevant if you are interested only in a limited range of values.
   For example, if you are having a user select a numbered item from a
   menu with 10 choices, you are interested only in whether the number the
   user entered is between 1 and 10.  You don't care how MUCH more than 10
   it is!!