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?
WaltP 2,905 Posting Sage w/ dash of thyme Team Colleague
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.
Banfa 597 Posting Pro Featured Poster
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.
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
you can use strtol() which avoids at least one of the problems with strtok().
sree_ec 10 Junior Poster
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;
jephthah 1,888 Posting Maven
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.
Edited by jephthah because: n/a
WaltP 2,905 Posting Sage w/ dash of thyme Team Colleague
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.
jephthah 1,888 Posting Maven
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
Banfa 597 Posting Pro Featured Poster
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.
Edited by Banfa because: n/a
jephthah 1,888 Posting Maven
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?
.
Edited by jephthah because: n/a
Banfa 597 Posting Pro Featured Poster
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
jephthah 1,888 Posting Maven
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
}
.
Edited by jephthah because: n/a
TimCereja 0 Newbie Poster
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;
}
Edited by peter_budo because: Keep It Organized - For easy readability, always wrap programming code within posts in [code] (code blocks)
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
TimCereja 0 Newbie Poster
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 ...
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
Edited by Ancient Dragon because: n/a
TimCereja 0 Newbie Poster
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?
WaltP 2,905 Posting Sage w/ dash of thyme Team Colleague
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?
TimCereja 0 Newbie Poster
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?
WaltP 2,905 Posting Sage w/ dash of thyme Team Colleague
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?
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
Edited by Ancient Dragon because: n/a
TimCereja 0 Newbie Poster
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;
}
Edited by mike_2000_17 because: Fixed formatting
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.