How is it that a string, or specifically a part of a string, can be isolated and put into its own integer variable? For example, a user is asked to input a date, such as 12/31/2000, which is saved as a string. How can the "12" the "31" and the "2000" be isolated and saved as individual integer variables?

Recommended Answers

All 21 Replies

Look at the characters.
If there is a digit, subtract '0' to make it a number and accumulate it into a variable -- details for you to work out.
If you get a /, next digits go into another variable.

Look up the library function strtol, it will convert the digits ignoring leading blank spaces and pass a pointer back to where it finished, which will be the '/', you can then just hop over the '/' to convert the next piece of the number.

you can use strtol() which avoids at least one of the problems with strtok().

We can also use atoi() function for converting string to integer....

like
int_value = (unsigned int)atoi(string_val);
where

string_val is
char * string_val;

i don't recommend atoi() or atol(). this does not handle invalid strings (non-integer strings) very well at all. for instance, if you try

value = atoi("CowAndChicken");

the result will be zero (value = 0)

and if you try

value = atoi("0");

the result will also be zero (value = 0)

strtol() avoids this confusion by allowing you to tell the difference between an actual zero, and an invalid string. it also will convert number bases other than base 10. look up the strtol() function here: http://www.cplusplus.com/reference/clibrary/cstdlib/strtol/

And I would use both "strtok" to parse the strings between the separator characters (which could be "/" or "-" or ".") in conjunction with "strtol", to properly convert each numeric string.

this is the best method, IMO, because it will allow you to handle conditions where you have extra spaces or invalid characters, or differently formatted month/date numbers.

for instance, consider all the differences between:

"01/01/10"

"1/1/10"

"1/01/2010"

"01 - 01 - 2010"

"1-1-10"

"01.01.2010"

etc.

What jephthah says is correct, but by not passing "cowandchicken" into atoi() you won't have a problem.


You need to look at the characters anyway. This is the verification phase of any conversion. Make sure you pass digits at the front of the string and you're fine. Anyone that would blindly pass a non-verified string into a conversion function gets what he deserves.

nearly bulletproof

"nearly" is the key word. Murphy's Law always prevails.

but thanks for pointing this out. I realized that it would allow non-numerics after a valid number, but at some point i just got tired of "bulletproofing"

The rest is left as an exercise for the reader.

:P

Cowandchicken??

If you mean was that string tailored to the code after I had examined it then yes.

However there is a serious but generalised point here, if the validation does not validate the exact format, with allowable variations, then you let in the possibility that the user manages to type in something that was actually meant to go in a different field but somehow manages to conform loose verification of the field they have typed into the program has unwittingly let in incorrect input.

If the software is in everyday use then the chances of this happening go up and if for some strange reason the cancel input function of the software doesn't work and the software acts on the input even if cancelled they it could be a disaster (don't laugh I've seen it happen).

Not checking that there are no invalid characters between the end of the parsed input and the next separator is sloppy.

ato?() which is crap.

well, i'm not saying it's crap, per se, it is good for a quick prototyping that doesnt require validation.

but atol/atoi is terribly weak and unable to distinguish between non-numerics and a legitimate zero value.

now if you need to preface your calls to ato? with some routine that identifies whether or not it's a number in the first place, you've kind of defeated the purpose of having an ascii/string-to-numeric converter, yes?

You have brown eyes, don't you? ... get off your high horse and ... Become a real programmer

really? is this where we're headed?

.

The rest is left as an exercise for the reader.

lol, thanks but no thanks, my own approach is as far as possible to only work on code that has no direct connections with any people. Their nice and all that but they do tend to muddy the waters :D

Okay, Okay, Okay.

Banfa, you are right. good job on calling me out on being sloppy. i should have followed through. the change is actually easy: all i needed to do was change 3 lines in the ConvertDateStringToVals from

if (ptr == mmStr)

to

if (ptr == mmStr || ptr != &mmStr[strlen(mmStr)])

here is the NOW BULLETPROOF(*) version that i should have posted in the first place

(* Nearly)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define MAX_DATESTR_LEN                16
#define DATESTR_DIVIDER_CHARACTERS     "/\\-_.,"  // allowable delimiters for month date year

int convertDateStringToVals (char*, const char*, int*, int*, int*);
int getUserInput(char*, int);

int main(void)
{
   char  dateStr[MAX_DATESTR_LEN];
   int   inputLen = 0,
         month,
         date,
         year,
         isInvalid;

   while (1)
   {
      do {
         printf("\nEnter Date String : ");
         fflush(stdout);
         inputLen = getUserInput(dateStr,MAX_DATESTR_LEN);
         if (inputLen > MAX_DATESTR_LEN)
            printf("string length %d, max length is %d, try again.\n\n",inputLen, MAX_DATESTR_LEN);
      }
      while (inputLen > MAX_DATESTR_LEN);

      if (inputLen == 0)
         break;

      isInvalid = convertDateStringToVals(dateStr, DATESTR_DIVIDER_CHARACTERS, &month, &date, &year);
      printf("   month : %02d\n   date  : %02d\n   year  : %d\n", month, date, year);

      if (isInvalid)
         printf("WARNING:  one or more fields are invalid.\n");
   }

   printf("exiting.\n");
   return 0;
}


//*****************************************************************************************//
// convertDateStringToVals()
//
// (c) 2010 by Jephthah and distributed for general use under the WTFPL licence
//
// purpose: converts each field of the datestring (month, day, year) into integer values.
//          fields may be separated by one or more possible token separator characters
//          invalid non-numeric fields will be converted to -1, and return an error flag
//          out-of-range values will be left intact but will still return an error flag
//
// input:   dateString, the character string containing a valid date in mm/dd/yyyy or similar format
//          tokenSeparators, pointer to list of one or more possible field separator characters
//
// output:  month, date, year:  integer values representing each field.  the year, if less than 100,
//          will be converted to corresponding year 2000-2099, otherwise will be left intact.
//
// return:  0 if all fields were valid, -1 if one or more fields are invalid
//
//*****************************************************************************************//
int convertDateStringToVals (char * dateString, const char * tokenSeparators, int * month, int * date, int * year)
{
   char *tempDate, *mmStr, *ddStr, *yyStr, *ptr;
   int  error = 0;

   tempDate = malloc(strlen(dateString) * sizeof(char));
   strcpy(tempDate,dateString);   // copy dateStr into temp location that can be abused by strtok

   *month = *date = *year = -1;   // assume error unless found valid values
   
   mmStr = strtok(tempDate, tokenSeparators);
   ddStr = strtok(NULL,    tokenSeparators);
   yyStr = strtok(NULL,    tokenSeparators);

   if (mmStr != NULL)   // found token
   {
      *month = strtol(mmStr,&ptr,10);
      if (ptr == mmStr || ptr != &mmStr[strlen(mmStr)])
         *month = -1;   // token was not fully valid numeric
      else if (*month < 1 || *month > 12)
         error = -1;    // value numeric, but out of range
   }

   if (ddStr != NULL)  // found token
   {
      *date = strtol(ddStr,&ptr,10);
      if (ptr == ddStr || ptr != &ddStr[strlen(ddStr)])
         *date = -1;      // token was not fully valid numeric
      else if (*date < 1 || *date > 31)
         error = -1;      // value numeric, but out of range
   }

   if (yyStr != NULL)  // found token
   {
      *year = strtol(yyStr,&ptr,10);
      if (ptr == yyStr || ptr != &yyStr[strlen(yyStr)])
         *year = -1;       // token was not fully valid numeric
      else if (*year < 0)
         error = -1;       // value numeric, but out of range
      else if (*year < 100)
         *year += 2000;    // assume 2-digit year is 21st Century
   }

   if (*month < 0 || *date < 0 || *year < 0)
      error = -1;

   free(tempDate);

   return error;   // will be zero (0) if all fields are valid, -1 if not.

}

//*****************************************************************************************//
// GetUserInput()
//
// (c) 2010 by Jephthah and distributed for general use under the WTFPL licence
//
// purpose:gets user input, removes the newline, passes back results up to maximum
//         number of characters, flushes remaining characters from input buffer,
//         returns the number of total characters entered by user
//
// input:  maxStringLength is the maximum allowble characters to input by user
//
// output: returnStr, contains up to the maximum length of characters allowed that were
//         input by the user, any additional characters entered are lost
//
// return: total characters entered by user; caller should check that this value is equal
//         to or less than the maximum allowed to indicate valid string was input.  larger
//         value returned than was allowed by the input indicates characters were lost
//
//
// TYPICAL USE EXAMPLE:
//
//    do {
//       printf("\nEnter String : ");
//       fflush(stdout);
//       inputLen = getUserInput(inputStr, MAX_STR_LEN);
//       if (inputLen > MAX_STR_LEN)
//           printf("string length %d, max length is %d, try again.\n\n",inputLen, MAX_STR_LEN);
//    }
//    while (inputLen > MAX_STR_LEN);
//
//*****************************************************************************************//
int getUserInput (char * returnStr, int maxStringLength)
{
   char    *tempStr;
   int     maxLen, totalCount = 0;
   size_t  len;

   maxLen = maxStringLength + 2;     //account for NULL and /newline
   tempStr = malloc(maxLen * sizeof(char));  //temporary holder

   do {
      fgets(tempStr, maxLen, stdin);  // get chars from input buffer
      len = strlen(tempStr);

      if (tempStr[len-1] == '\n') // newline indicates end of string
      {
         tempStr[len-1] = '\0';   // delete it
         len = strlen(tempStr);   // and recalc length
      }
      totalCount += (int)len;
   }
   while ((int)len > maxStringLength);  // continue to flush extras if too long

   strcpy(returnStr,tempStr);  // copy temp string into output
   free(tempStr);              // and release memory

   return totalCount;   // may be more than the number allowed
}

.

I've got the month working well with atoi. Can anyone see what is wrong with the day and year variables in this code? They return only zero:

#include <stdio.h>

int main(void)
{
int day, month, year = 0;
char *s[10];
char list[12][12] = { "January", "February", "March", "April", "May", "June", "July", 
                      "August", "September", "October", "November", "December" };

printf("Please Enter the Check Date: ");
scanf("%s", s);

int month = atoi (s);
int day = atoi (s+3);
int year = atoi (s+6);

printf(list[month - 1]);
printf(" %d, %d", day, year);

return 0;

}

what are the value of those two variables ? what was your input string? use strtol() and you will get better results

char *ptr = 0;
month = strtol(s, &ptr, 10);
day = strtol(++ptr, &ptr, 10);
year = strtol(++ptr, &ptr, 10);

Note that with strtol() the input string may or may not contain leading 0s, such as it will recognize "2/3/10", or "02/03/2010", or any other combination as long as there is one character separating month, day and year.

Thanks a lot for the strtol suggestion. It works very well. I'm learning C and still fairly new, so could you please explain the logic behind the strtol(s, &ptr, 10) and strtol(++ptr, &ptr, 10) statements? Thank you very much ...

strtol() sets the pointer (second parameter) to the first character which it could not convert to int -- e.g. it's the '/' character in the string you enter. The ++ptr just advances that pointer past the '/' character so that is is not set to the first digit of the next part of the string.

The last parameter to strtol() tells it how to interpret the string (base). Base 10 is decimal, base 16 is Hex, base 8 is Octal. I have not tried it but you base 2 will mean the string is in binary 0 and 1s.

Another question about strtol. If I have an double that has two decimal numbers, such as 941.59, and I want to set the .59 to an integer with the value 59, can strtol be used? If not, how could that be done?

Another question about strtol. If I have an double that has two decimal numbers, such as 941.59, and I want to set the .59 to an integer with the value 59, can strtol be used? If not, how could that be done?

If you are asked to do it on paper mathematically, how would you do it?

If you are asked to do it on paper mathematically, how would you do it?

For that example, you'd subtract 941 and multiply by 100. But if it is an input from the user which you do not know, would you change the double to a string and then use something like strtol to find it?

For that example, you'd subtract 941 and multiply by 100. But if it is an input from the user which you do not know, would you change the double to a string and then use something like strtol to find it?

How do you know it's 941?
How can you get the integer 941 (or whatever it is) from your double?

call modf() to split the double into integer and fractional parts. Microsoft (as well as others) compilers have a lot of floating point functions that come in handy from time-to-time.

Thanks for all the help. I put work into the coding, but I sometimes get hung up on functions that I'm not familiar with. Here's one of the projects I've gotten done with the assistance. It prompts the user for a number between 1.00 and 999999.99 and outputs the number in word form (ie: ONE HUNDRED ONE THOUSAND TWO HUNDRED NINE and 50/100). I think I've worked all the bugs out and it's working great. These endless 'IF' statements is the only way to do it, isn't it?

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

int main(void)
{
  char ones[9][6] = {"ONE","TWO","THREE","FOUR","FIVE",
                       "SIX","SEVEN","EIGHT","NINE"};
  char teens[9][10] = {"ELEVEN","TWELVE","THIRTEEN","FOURTEEN",
                       "FIFTEEN","SIXTEEN","SEVENTEEN","EIGHTEEN","NINETEEN"};
  char tens[9][10] = {"TEN","TWENTY","THIRTY","FORTY","FIFTY","SIXTY",
                      "SEVENTY","EIGHTY","NINETY"};
  char thou[9] = {"THOUSAND"};
  char hun[8] = {"HUNDRED"};
  double num, x, y = 0;
  int temp = 0;
  int a,b,c,d,e,f = 0;

  while(temp <= 0 || num > 999999.99)
  {
    printf("Please Enter a number between 1.00 and 999999.99: ");
    scanf("%lf",&num);
    temp = num;
  }

  temp = num;
  x = modf(num, &y);
  x = (x*100);

  if(temp%10 > 0)
  {a = temp%10;}
  else
  {a = 0;}

  temp = temp/10;

  if(temp%10 > 0)
  {b = temp%10;}
  else
  {b = 0;}

  temp = temp/10;

  if(temp%10 > 0)
  {c = temp%10;}
  else
  {c = 0;}

  temp = temp/10;

  if(temp%10 > 0)
  {d = temp%10;}
  else
  {d = 0;}

  temp = temp/10;

  if(temp%10 > 0)
  {e = temp%10;}
  else
  {e = 0;}

  temp = temp/10;

  if(temp%10 > 0)
  {f = temp%10;}
  else
  {f = 0;}


  if(f > 0 && e > 0)
  {printf(ones[f - 1]);
   printf(" ");
   printf(hun);
   printf(" ");}

  if(f > 0 && e == 0 && d == 0)
  {printf(ones[f - 1]);
   printf(" ");
   printf(hun);
   printf(" ");
   printf(thou);
   printf(" ");}

  if(f > 0 && e == 0 && d > 0)
  {printf(ones[f - 1]);
   printf(" ");
   printf(hun);
   printf(" ");}

  if(e >= 2 && d > 0)
  {printf(tens[e - 1]);
   printf(" ");
   printf(ones[d - 1]);
   printf(" ");
   printf(thou);
   printf(" ");}

  if(e >= 2 && d == 0 || e == 1 && d == 0)
  {printf(tens[e - 1]);
   printf(" ");
   printf(thou);
   printf(" ");}

  if(e == 1 && d > 0)
  {printf(teens[d - 1]);
   printf(" ");
   printf(thou);
   printf(" ");}

  if(d > 0 && e == 0)
  {printf(ones[d - 1]);
   printf(" ");
   printf(thou);
   printf(" ");}

  if(c > 0)
  {printf(ones[c - 1]);
   printf(" ");
   printf(hun);
   printf(" ");}

  if(b >= 2 || b == 1 && a == 0)
  {printf(tens[b - 1]);
   printf(" ");}

  if(b == 1 && a > 0)
  {printf(teens[a - 1]);
   printf(" ");}

  if(b >= 2 && a > 0 || b == 0 && a > 0)
  {printf(ones[a - 1]);
   printf(" ");}

  if(num > 1)
  {printf("and ");}

  printf("%.0lf/100", x);
  return 0;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.