Andy Link
Andy Link

Reputation: 139

How to get the actual Value at a specific index of a char array

I have a program I'm making for date validation. I am receiving the input from user in the form of MM/DD/YYYY and storing it as a character array.

First I tried to break it apart into int variables for month day and year with casting

 char UserDate[10];
 int month = 00, day = 00, year = 0000;
 cout << "Enter a date in the format of MM/DD/YYYY" << endl;
 cin >> UserDate;
 month = (int)UserDate[0] + (int)UserDate[1];
 day = (int)UserDate[3] + (int)UserDate[4];
 year = (int)UserDate[6] + (int)UserDate[7] + (int)UserDate[8] + (int)UserDate[9];

I then tried it without casting

 char UserDate[10];
 int month = 00, day = 00, year = 0000;
 cout << "Enter a date in the format of MM/DD/YYYY" << endl;
 cin >> UserDate;
 month = UserDate[0] + UserDate[1];
 day = UserDate[3] + UserDate[4];
 year = UserDate[6] + UserDate[7] + UserDate[8] + UserDate[9];

The problem is I cant get the actual value out of the index of the array. The results I get for the date entered 01/01/2014 are as follows:

month = 48'0' + 49'1'; //months value is 97
day = 48'0' + 49'1'; //days value is 97
year = 50'2' + 48'0' + 49'1' + 52'4'; //years value is 199

This happens for both methods above whether i cast the char as int or not. How do I get the value stored at the index that I want since there is no UserDate[1].Value??

Upvotes: 0

Views: 1893

Answers (3)

Camlorn
Camlorn

Reputation: 33

The problem you're running into here is that C does not convert characters to numbers in this manner. A char is a 1-byte number. Whether or not a char is signed or unsigned depends on your compiler unless you specifically specify in your code. If I do:

char x = '1';
int y = (int)x;

I actually have that y = 49 with my compiler and on my platform. This is the ASCII value of the character 1, and for the intent of this discussion it might be different for someone else (specifically, if I make x an unsigned char I'm probably okay, and the ASCII value for 1 is low enough that it might be anyway). Don't assume that chars are going to hold a specific value unless you know what you're doing. Some people use them as tiny integers and there are tricks that you can do if you understand ASCII. In my opinion, these are best hidden away in a library or used only in very special cases.

Secondly, you can't just add the casted values: even assuming the cast works, you're adding the digits-for the year 1999, your method would give 28. Because it doesn't, what you're getting is the sum of the ASCII values of that part of the string. If you want + to concatenate strings, you have to use std::string for everything. Otherwise, chars are basically 1-byte integers.

If you are absolutely, absolutely positive that the string is valid, you can do the following. If it is not valid, this will break, so you'll need to validate the string. Here's a program that demonstrates the technique. This is not the best coding practice: you should probably use std::string, make parseDate a constructor, and do a few other things. I've kept this intentionally simple at the cost of some good design practices. In reality, I suggest looking for a date handling library: boost.date_time is not something that I have used, but based off my experiences with other parts of boost would make it my first choice. You will eventually need more functionality unless this is a very small project, and why reinvent the wheel? Anyhow:

#include <stdio.h>

class date {
    public:
    int day, month, year;
};

date parseDate(const char* str) {
    date d;
    sscanf(str, "%i/%i/%i", &d.month, &d.day, &d.year);
    return d;
}

void main() {
    char test[255];
    scanf("%s", &test);
    date d = parseDate(test);
    printf("%i %i %i", d.day, d.month, d.year);
}

Note that, at least in my opinion, sscanf and scanf are actually more powerful than cin and cout in a lot of ways-for this kind of parsing specifically, and without bringing in external libraries, they're almost always my first choice. Since you're already using a char array (which is unsafe, you should probably use std::string), you need no extra conversion. If you need to pass an std::string into this, use std::string::c_str(), as in:

string dateString;
cin>>dateString;
date d = parseDate(dateString.c_str());

Hope this helps.

Upvotes: 0

mittelmania
mittelmania

Reputation: 3571

Your UserDate array is in fact an array of characters, each represented by a standard ASCII code (see the complete ASCII table here). Using explicit casting like you did results in converting the char (no matter whether a letter or a digit) to the integer ASCII code. For example - the character '0' has an ASCII value of 48, so writing (int)'0' equals 48.

Since digits 0-9 appear sequentially in the ASCII table, you can evaluate each char by writing:

int digit = (int)UserDate[...] - '0'

The mathematics here are pretty simple so I trust you to understand why that's true.

Please notice that if your character is not a digit, this conversion will result in a negative integer or a number greater than 9, so you should check that the value you've received is valid.

Upvotes: 1

ScottMcP-MVP
ScottMcP-MVP

Reputation: 10425

Casting does not convert a char into an int. Subtract '0' to get the int value.

month = 10 * (UserDate[0] - '0') + UserDate[1] - '0';

Upvotes: 3

Related Questions