0

I am making a program that asks users to enter their date of birth, then outputs it. It uses exception classes. However, the issue I seem to be having is that the input is somehow being lost or translated into undesired numbers. Code:

dob::dob() {
cout << "Enter your date of birth in format MM-DD-YYYY" << endl;
//cin.getline(monthChar, 10);
cin.get(monthChar, 10, '-');
cin.ignore();
cin.get(dayChar, 03, '-');
cin.ignore();
cin.get(yearChar, 04);
cout << dayChar[0];
cout << dayChar[1];
cout << monthChar[0];
cout << monthChar[1];
cout << " " << endl;
day = dayChar[0] * 10 + dayChar[1];
month = monthChar[0] * 10 + monthChar[1];
year = yearChar[0] * 1000 + yearChar[1] * 100 + yearChar[2] * 10 + yearChar[3];
cout << month << day << year;}    

when entering 12-12-1996 for input, I get 12 2 5054055270 for output. I read this link for get and seems like I followed all the steps correctly so I miss what my mistake is. Actually, midway through writing this post, I realize why I'm getting the weird numbers at the end, it's because I'm multiplying a char value by 10, but how do I cast to int? is it just static_cast for the char? I still need to answer why my monthChar char at monthChar[0] is replaced by a space. Thanks.

EDIT: New Code:

dob::dob() {
    cout << "Enter your date of birth in format MM-DD-YYYY" << endl;
    //cin.getline(monthChar, 3);
    cin.get(monthChar, 3, '-');
    cin.ignore();
    cin.get(dayChar, 3, '-');
    cin.ignore();
    cin.get(yearChar, 5);
    cout << dayChar[0];
    cout << dayChar[1];
    cout << monthChar[0];
    cout << monthChar[1];
    cout << " " << endl;
    day = (dayChar[0]-'0') * 10 + dayChar[1]-'0';
    month = (monthChar[0] - '0') * 10 + monthChar[1] - '0';
    year = (yearChar[0] - '0') * 1000 + (yearChar[1] - '0') * 100 + (yearChar[2] - '0') * 10 + yearChar[3] - '0';
    cout << month << day << year;
}

When I update the code with suggestions from the answers/comments, I get the correct day and year but not month. For input 05-27-1996 I get output

27 5

-45271996

What's going on with the month?

Community
  • 1
  • 1
Nicholas A. Randall
  • 421
  • 1
  • 5
  • 13
  • Why is your streamsize 10 and 3 for month and date in the `cin.get()` call? – Abhishek Agarwal Jul 19 '17 at 03:53
  • Can you provide new code (updated on the basis of examples from the answers)? Just add new code as a snippet in the end of your question. I suppose problem is related to `0` that is before `5` in the input, so I insist on using standard function – VolAnd Jul 20 '17 at 16:04
  • Added new code. No matter what number I type in, monthChar[0] gets outputted as a space. – Nicholas A. Randall Jul 20 '17 at 17:16
  • The most likely cause of problems is incorrect use of memory allocated to strings. You must remember, that you read 2 characters, you have to use `cin.get(monthChar, 3, '-');` (with value 3), and before that `monthChar` should be declared as `char monthChar[3];` or with value gretater than `3`. The third character is required for `\0` (nul-terminator). Otherwise, writing data to array of smaller size will cause violation of array boundaries, and this in turn will lead to errors in operation (read more about undefined behavior and related run-time errors) – VolAnd Jul 21 '17 at 05:01

3 Answers3

0

You use very strange approach for conversion digits (type char) to numbers (type int).

As I understand your idea

 day = dayChar[0] * 10 + dayChar[1];

make value for int day from two characters dayChar[0] and dayChar[1].

That is wrong, and must be like

 day = (dayChar[0] - '0') * 10 + (dayChar[1] - '0');

Let's look in the details. String "12" has two characters with codes 49 and 50, just check:

cout << (int)dayChar[0] << endl;
cout << (int)dayChar[1] << endl;

So expression

dayChar[0] * 10 + dayChar[1]

gives

49 * 10 + 50 = 540

so correction must be with code of character '0' (it is 48), and expression

(dayChar[0] - '0') * 10 + (dayChar[1] - '0')

will give

(49 - 48) * 10 + (50 - 48) = 1 * 10 + 2 = 12

as is expected.

UPDATE:

Some other points for improvement:

  1. Consider using atoi or other standard conversion function to get numbers from string, e.g. day = atoi(dayChar);
  2. Be careful with expressions like cin.get(yearChar, 04); - 04 is number in octal system (it does not matter for numbers lees than 8, but 011 is equal to 9 in decimal)
  3. Also about cin.get(yearChar, 4); - value 4 means the "size of character string" and as we know string of type char * require one extra position for nul-terminator (\0) so to get "1996" we need size 4+1, i.e. it must be

    cin.get(yearChar, 5);
    

    And it is also important, that array yearChar must have size equal or greater than 5.

By the way, if you are planning to restore cin.getline(monthChar, 10); from comments, also consider the following snippet (where 11 is used instead of 10 and sscanf is used for string parsing (this is C style, just to show possible option)):

char dataChar[11]; // at least 11 chars are required to store MM-DD-YYYY
int day, month, year;
int rescnt = 0; // will show how many numbers are extracted from text line
while(1){
    cout << "Enter your date of birth in format MM-DD-YYYY" << endl;
    cin.getline(dataChar, 11);
    int rescnt = sscanf(dataChar, "%d-%d-%d", &month, &day, &year);
    if (rescnt != 3)
    {
        cout << "Imput was wrong!" << endl;
        cin.clear(); // reset state of cin
        cin.ignore(INT_MAX, '\n'); //  clean the input buffer
    }
    else
    {
        break;
    }
} 
// data is ready
cout << month << " " << day << " " << year << endl;

Also for splitting line (type string) with '-' delimiter you can use std::string::substr() and std::string::find() as suggested here or stringstream with copy algorithm like here

VolAnd
  • 6,367
  • 3
  • 25
  • 43
  • I used your suggestion and now the day and year are correctly outputted but not the month. I have the output in my edited post. – Nicholas A. Randall Jul 19 '17 at 20:19
  • added new code to edited post. No matter what input I give, monthChar[0] still outputs as a space. – Nicholas A. Randall Jul 20 '17 at 17:17
  • @NicholasA.Randall The declaration of char arrays you use in the program not shown, please check the sizes - they must be at least 3 for month and day (`char monthChar[3];` `char dayChar[3];`) and 5 for year (`char yearChar[5]`;`) – VolAnd Jul 20 '17 at 17:26
  • Changing the declaration of char arrays to sizes 3 works. But why? And why did it work for days with size 2 and year with size 4 but not month with size 2? – Nicholas A. Randall Jul 20 '17 at 23:54
  • This is an example on undefined behavior - "sometimes this works, but sometimes fails". You can test the same, after changing the order of arrays declaration, perhaps behavior will change (but maybe not - undefined behavior). In any case, now you remember this case, and, I hope, you will never make similar mistakes in the future. – VolAnd Jul 21 '17 at 01:49
  • Thanks VolAnd, you're the hero – Nicholas A. Randall Jul 21 '17 at 18:25
0

I have made some changes to your code and this works fine:

    cout << "Enter your date of birth in format MM-DD-YYYY" << endl;
    //cin.getline(monthChar, 10);
    cin.get(monthChar, 03, '-');
    cin.ignore();
    cin.get(dayChar, 03, '-');
    cin.ignore();
    cin.get(yearChar, 05);
    cout << dayChar[0];
    cout << dayChar[1];
    cout << monthChar[0];
    cout << monthChar[1];
    cout << " " << endl;
    int day, month,year;
    day =(dayChar[0] - 48 )* 10 +(dayChar[1] -48);
    month =( monthChar[0]-48) * 10 + (monthChar[1]-48);
    year =( yearChar[0] -48)* 1000 + (yearChar[1]-48) * 100 + (yearChar[2]-48) * 10 + (yearChar[3]-48);
    cout << month << day << year;

For getting the year you need to give streamsize 1 more than the size of year i.e. 5. Also to convert integer to character you need to subtract the ASCII value of '0' which is 48 from each character.

Abhishek Agarwal
  • 1,190
  • 2
  • 19
  • 38
0

According to the docs, cin.get(char* s, streamsize n, char delim) will extract characters from the stream, until either (n-1) characters have been extracted or the delimiting character is encountered. Thus assuming the input string is in the correct format "MM-DD-YYYY", i.e. with no error checking, you can update your code to

std::cin.get(monthChar, 3, '-');
std::cin.ignore();
std::cin.get(dayChar, 3, '-');
std::cin.ignore();
std::cin.get(yearChar, 5);
std::cout << dayChar[0];
std::cout << dayChar[1];
std::cout << monthChar[0];
std::cout << monthChar[1];
std::cout << " " << std::endl;
auto day = (dayChar[0] - '0') * 10 + dayChar[1] - '0';
auto month = (monthChar[0] - '0') * 10 + monthChar[1] - '0';
auto year = (yearChar[0] - '0') * 1000 + (yearChar[1] - '0') * 100 + (yearChar[2] - '0') * 10 + yearChar[3] - '0';
std::cout << month << day << year;

Subtracting '0' from a char converts the ascii value to a number, see Convert char to int in C and C++

StaticBeagle
  • 5,070
  • 2
  • 23
  • 34
  • You miss an important fact: `cin.get(char * s, streamsize n, char delim)` will read n-1 chars unless `delim` is found first. – user4581301 Jul 19 '17 at 04:29