Как получить фактическое значение по определенному индексу массива символов

0

У меня есть программа, которую я делаю для проверки даты. Я получаю вход от пользователя в виде MM/DD/YYYY и сохраняю его как массив символов.

Сначала я попытался разбить его на переменные int на месяц и год с литьем

 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];

Затем я попробовал его без кастинга

 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];

Проблема в том, что я не могу получить фактическое значение из индекса массива. Результаты, полученные мной за дату, 01/01/2014, следующие:

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

Это происходит для обоих вышеописанных методов, если я использую char как int или нет. Как получить значение, хранящееся в индексе, который я хочу, так как нет UserDate[1].Value??

  • 0
    Используйте scanf для чтения целочисленных значений.
  • 2
    @JoelCornett Зачем ему это делать?
Теги:
arrays

3 ответа

3

Кастинг не преобразует char в int. Вычитаем '0', чтобы получить значение int.

month = 10 * (UserDate[0] - '0') + UserDate[1] - '0';
  • 0
    красивый ... но почему 10 *? Можете ли вы объяснить, почему это работает?
  • 0
    @AndyLink Из-за десятичного разряда цифры чувак! Используйте дополнительные 100 * (UserDate[0] - '0') + ... для номеров, превышающих 99 !
Показать ещё 2 комментария
1

Ваш UserDate массив в действительности массив символов, каждый из которых представлен стандартного кода ASCII (см полной таблицы ASCII здесь). Использование явного каста, как и вы, приводит к преобразованию символа (независимо от того, является ли буква или цифра) целочисленным кодом ASCII. Например, символ "0" имеет значение ASCII 48, поэтому запись (int)'0' равна 48.

Поскольку цифры 0-9 появляются последовательно в таблице ASCII, вы можете оценить каждый символ, написав:

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

Математика здесь довольно проста, поэтому я надеюсь, что вы поймете, почему это правда.

Обратите внимание, что если ваш символ не является цифрой, это преобразование приведет к отрицательному целому числу или числу больше 9, поэтому вы должны проверить, что полученное вами значение действительно.

0

Проблема, с которой вы сталкиваетесь, заключается в том, что C не преобразует символы в числа таким образом. Символ 1-байтовый номер. Независимо от того, подписан символ или нет, зависит от вашего компилятора, если вы специально не укажете в своем коде. Если я сделаю:

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

На самом деле у меня есть y = 49 с моим компилятором и на моей платформе. Это значение ASCII символа 1, и для намерения этого обсуждения он может быть другим для другого (в частности, если я делаю x беззнаковым символом, я, вероятно, хорошо, а значение ASCII для 1 достаточно мало, это может быть так или иначе). Не предполагайте, что символы будут иметь определенную ценность, если вы не знаете, что делаете. Некоторые люди используют их как маленькие целые числа, и есть трюки, которые вы можете сделать, если понимаете ASCII. На мой взгляд, их лучше всего скрывать в библиотеке или использовать только в особых случаях.

Во-вторых, вы не можете просто добавить литые значения: даже если вы выполняете литье, вы добавляете цифры - за 1999 год ваш метод даст 28. Поскольку это не так, то, что вы получаете, является суммой значений ASCII этой части строки. Если вы хотите + конкатенировать строки, вы должны использовать std::string для всего. В противном случае символы в основном представляют собой 1-байтовые целые числа.

Если вы абсолютно, абсолютно уверены, что строка действительна, вы можете сделать следующее. Если это недействительно, это сломается, поэтому вам нужно будет проверить строку. Здесь программа, демонстрирующая технику. Это не лучшая практика кодирования: вы должны, вероятно, использовать std :: string, make parseDate конструктор и сделать несколько других вещей. Я сохранил это намеренно просто за счет некоторых хороших дизайнерских практик. На самом деле, я предлагаю искать библиотеку обработки дат: boost.date_time - это не то, что я использовал, но основанный на моем опыте с другими аспектами повышения, сделал бы это мой первый выбор. В конечном итоге вам понадобится больше функциональности, если это не очень маленький проект и зачем изобретать колесо? Так или иначе:

#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);
}

Обратите внимание, что, по крайней мере, по моему мнению, sscanf и scanf на самом деле более мощные, чем cin и cout во многом - для такого рода парсинга, и без привлечения внешних библиотек, они почти всегда являются моим первым выбором. Поскольку вы уже используете массив символов (который небезопасен, вы, вероятно, должны использовать std :: string), вам не требуется дополнительное преобразование. Если вам нужно передать std :: string в это, используйте std :: string :: c_str(), как в:

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

Надеюсь это поможет.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню