Уже пятница?

Это первая программа, которую я написал в своей саге C ++, которую я действительно считаю полезной. Описание для этого назначения очень длинное и обыденное:

  

Напишите программу, которая вводит дату (например: 4 июля 2008 г.) и   выводит день недели, соответствующий этой дате.   следующий алгоритм из Wikipedia . Реализация   требуют нескольких функций.

     
  • bool isLeapYear(int year);

         

    Эта функция должна возвращать true, если year является високосным годом и false, если это не так. Вот псевдокод для определения високосного года:

    leap_year = (year divisible by 400) or (year divisible by 4 and not divisible by 100)
    
  •   
  • int getCenturyValue(int year);

         

    Эта функция должна принимать первые две цифры года (то есть век), делить на \ $ 4 \ $ и сохранять остаток. Вычтите остаток из \ $ 3 \ $ и верните это значение, умноженное на \ $ 2 \ $. Например, год \ $ 2008 \ $ становится \ $ \ dfrac {20} {4} = 5 \ $ с остатком \ $ 0 \ $. \ $ 3 - 0 = 3 \ $. Возврат \ $ 3 \ cdot 2 = 6 \ $.

  •   
  • int getYearValue(int year);

         

    Эти функции вычисляют значение, основанное на годах с начала века. Сначала извлеките последние две цифры года. Например, \ $ 08 \ $ извлекается для \ $ 2008 \ $. Далее, коэффициент в високосные годы. Разделите значение с предыдущего шага на \ $ 4 \ $ и отбросьте остаток. Добавьте два результата вместе и верните это значение. Например, из \ $ 2008 \ $ мы извлекаем \ $ 08 \ $. Тогда \ $ \ dfrac {8} {4} = 2 \ $ с остатком \ $ 0 \ $. Возврат \ $ 2 + 8 = 10 \ $.

  •   
  • int getMonthValue(int month, int year);

         

    Эта функция должна возвращать значение, основанное на приведенной ниже таблице, и требует вызова функции isLeapYear().

         

    $$      \ Newcommand \ T {\ Правило {0pt} {1em} {. 5em}}      \ BEGIN {массив} {| с | с |}      \ hline \ textbf {Month} & \ textbf {Возвращаемое значение} \\\ hline        \ text {январь} \ T & 0 \ left (6 \ text {если год - високосный год} \ справа) \\\ hline        \ text {February} \ T & 3 \ left (2 \ text {если год - високосный год} \ справа) \\\ hline        \ text {March} \ T & 3 \\\ hline        \ text {April} \ T & 6 \\\ hline        \ text {May} \ T & 1 \\\ hline        \ text {June} \ T & 4 \\\ hline        \ text {July} \ T & 6 \\\ hline        \ text {August} \ T & 2 \\\ hline        \ text {September} \ T & 5 \\\ hline        \ text {October} \ T & 0 \\\ hline        \ text {November} \ T & 3 \\\ hline        \ text {декабрь} \ T & 5 \\\ hline      \ {Конец массива}      $$

  •   
  • Наконец, чтобы вычислить день недели, вычислите сумму дня дня плюс значения, возвращаемые getMonthValue, getYearValue и getCenturyValue. Разделите сумму на \ $ 7 \ $ и вычислите остаток. Остаток от \ $ 0 \ $ соответствует Sunday, \ $ 1 \ $ соответствует понедельнику и т. Д., До \ $ 6 \ $, что соответствует субботе. Например, дата 4 июля 2008 года должна быть рассчитана как (день месяца) + (getMonthValue) + (getYearValue) + (getCenturyValue) = \ $ 4 + 6 + 10 + 6 = 26 \ $. \ $ \ dfrac {26} {7} = 3 \ $ с остатком \ $ 5 \ $. Пятый день недели соответствует пятнице.

  •   

Ваша программа должна позволять пользователю вводить любую дату и выводить   соответствующий день недели на английском языке.

     

Эта программа должна включать функцию void с именем getInput, которая   запрашивает у пользователя дату и возвращает месяц, день и год   используя параметры сквозной ссылки. Вы можете выбрать пользователя   введите месяц даты как число (1-12) или месяцимя.

dayOfWeek.cpp

/**
 * @file dayOfWeek.cpp
 * @brief Computes the day of the week given a certain date
 * @author syb0rg
 * @date 10/23/14
 */

#include <cctype>
#include <iostream>
#include <limits>

enum Months {None, January, February, March, April, May, June, July, August, September, October, November, December};
std::string *weekDays = new std::string[7] {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

/**
 * Makes sure data isn't malicious, and signals user to re-enter proper data if invalid
 */
size_t getSanitizedNum()
{
    size_t input = 0;
    while(!(std::cin >> input))
    {
        // clear the error flag that was set so that future I/O operations will work correctly
        std::cin.clear();
        // skips to the next newline
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "Invalid input.  Please enter a positive number: ";
    }
    return input;
}

/**
 * Safetly grabs and returns a lowercase version of the character (if the lowercase exists)
 */
char32_t getSanitizedChar()
{
    // absorb newline character (if existant) from previous input
    if('\n' == std::cin.peek()) std::cin.ignore();
    return std::tolower(std::cin.get());
}

bool isLeapYear(const int year)
{
    if (0 == (year % 400) || (0 == (year % 4) && (year % 100))) return true;
    else return false;
}

int getCenturyValue(const size_t year)
{
    return (2 * (3 - div(year / 100, 4).rem));
}

int getYearValue(const size_t year)
{
    int mod = year % 100;
    return (mod + div(mod, 4).quot);
}

int getMonthValue(const size_t month, const size_t year)
{
    switch (month) {
        case January:
            if (isLeapYear(year)) return 6;
        case October:
            return 0;
        case May:
            return 1;
        case August:
            return 2;
        case February:
            if (isLeapYear(year)) return 2;
        case March:
        case November:
            return 3;
        case June:
            return 4;
        case September:
        case December:
            return 5;
        case April:
        case July:
            return 6;
        default:
            return -1;
    }
}

int dayOfWeek(const size_t month, const size_t day, const size_t year)
{
    return div(day + getMonthValue(month, year) + getYearValue(year) + getCenturyValue(year), 7).rem;
}

void getInput(size_t &month, size_t &day, size_t &year)
{
    std::cout << "Enter the month (1-12): ";
    month = getSanitizedNum();

    std::cout << "Enter the day (1-31): ";
    day = getSanitizedNum();

    std::cout << "Enter the year: ";
    year = getSanitizedNum();
}

int main()
{
    size_t month = 0;
    size_t day = 0;
    size_t year = 0;
    do
    {
        getInput(month, day, year);
        std::cout << "The day of the week is " << weekDays[dayOfWeek(month, day, year)] << std::endl;

        std::cout << "Run the program again (y/N): ";  // signify n as default with capital letter
    } while ('y' == getSanitizedChar());
}
27 голосов | спросил syb0rg 23 +04002014-10-23T06:49:49+04:00312014bEurope/MoscowThu, 23 Oct 2014 06:49:49 +0400 2014, 06:49:49

4 ответа


31

Это неверно несколькими способами:

std::string *weekDays = new std::string[7] {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

Это не только глобальная переменная (no const), но она динамически распределяется без освобождения delete где-то. Кроме того, он может быть освобожден в любом месте и, возможно, более одного раза, если вы не будете осторожны. В любом случае, поскольку std::string уже выполняет собственное управление памятью, просто оставьте new.

Предполагая, что C ++ 11 (доступ к std::array ), вы должны в итоге:

const std::string weekDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

В C ++ также лучше оставить [] пустым при инициализации массива C. Компилятор сам определит правильный размер, поэтому вам не нужно беспокоиться о том, чтобы поддерживать его в актуальном состоянии.

ответил Jamal 23 +04002014-10-23T08:40:02+04:00312014bEurope/MoscowThu, 23 Oct 2014 08:40:02 +0400 2014, 08:40:02
21

Я просто сосредоточусь на getMonthValue():

int getMonthValue(const size_t month, const size_t year)
{
    switch (month) {
        case January:
            if (isLeapYear(year)) return 6;
        case October:
            return 0;
        case May:
            return 1;
        …

Параметры месяца и года не являются размерами. Не используйте size_t, когда вы просто означаете unsigned int. Однако у вас также есть bool isLeapYear(const int year) - почему непоследовательность в типе year? Кроме того, у вас есть отличный код Months. Почему бы не переименовать его с помощью единственного числа и использовать его? В любом случае вы неявно сравниваете size_t и Months в блоке коммутатора.

Вместо блока switch я бы использовал таблицу поиска. Фактически, две таблицы поиска: одна для високосных годов и одна для непиковых лет. Конструкция, управляемая данными, будет иметь меньше кода.

int getMonthValue(int month, int year) {
    const static int NON_LEAP_VALS[] = { 0xDEAD, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 },
                         LEAP_VALS[] = { 0xDEAD, 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
    return (isLeapYear(year)) ? LEAP_VALS[month] : NON_LEAP_VALS[month];
}
ответил 200_success 23 +04002014-10-23T07:33:46+04:00312014bEurope/MoscowThu, 23 Oct 2014 07:33:46 +0400 2014, 07:33:46
15
bool isLeapYear(const int year)
{
    if (0 == (year % 400) || (0 == (year % 4) && (year % 100))) return true;
    else return false;
}

Это ничтожно, но для меня это немного нечитаемо. Непоследовательное использование круглых скобок заставляет меня задуматься о порядке оценки.

Кроме того, вы используете 0 ==, чтобы выразить ложное значение, но вы не используете 0 !=, чтобы выразить истинное значение, которое также я считаю непоследовательным .

Кроме того, if/else немного избыточен.

Я бы переписал это как:

bool isLeapYear(const int year)
{
    return (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));
}

или если не используется == 0:

bool isLeapYear(const int year)
{
    return !(year % 400) || (!(year % 4) && (year % 100));
}
ответил Rotem 23 +04002014-10-23T15:24:18+04:00312014bEurope/MoscowThu, 23 Oct 2014 15:24:18 +0400 2014, 15:24:18
3

Я получил код и дал улучшение на основе комментариев здесь, и я изменил некоторые вещи, главным образом, функцию isLeapYear, потому что нет необходимости создавать функцию внутри iostream, уже имеет __isleap работает на 100%: https://pastebin.com/7xsM2CSF

#include <limits> //numeric_limits
#include <iostream>
//https://codereview.stackexchange.com/questions/67636/is-it-friday-yet
//dayOfWeek.cpp

enum Months { January=1, February, March, April, May, June, July, August, September, October, November, December};

const std::string weekDays[7]={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

/**
 * Makes sure data isn't malicious, and signals user to re-enter proper data if invalid
 * getSanitizedNum
 */
int getInt()
{
    int input = 0;
    while(!(std::cin>>input))
    {
        // clear the error flag that was set so that future I/O operations will work correctly
        std::cin.clear();
        // skips to the next newline
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "\n\tInvalid input.\n\tPlease enter a positive number: ";
    }
    return input;
}

/**
 * Safetly grabs and returns a lowercase version of the character (if the lowercase exists)
 * getSanitizedChar
 */
char32_t getChar()
{
    // absorb newline character (if existant) from previous input
    if('\n' == std::cin.peek()) std::cin.ignore();
    return std::tolower(std::cin.get());
}

int getCenturyValue(int year)
{
    return (2 * (3 - div(year / 100, 4).rem));
}

int getYearValue(int year)
{
    int mod = year % 100;
    return (mod + div(mod, 4).quot);
}

int getMonthValue(int month, int year) 
{
    const static int NON_LEAP_VALS[] = { 0xDEAD, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 },
                         LEAP_VALS[] = { 0xDEAD, 6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };

  return (__isleap(year) ? LEAP_VALS[month] : NON_LEAP_VALS[month]);
}
/*
int getMonthValue(int month, int year)
{
    switch (month) 
    {
        case January:
            if (__isleap(year)) return 6;
        case October:
            return 0;
        case May:
            return 1;
        case August:
            return 2;
        case February:
            if (__isleap(year)) return 2;
        case March:
        case November:
            return 3;
        case June:
            return 4;
        case September:
        case December:
            return 5;
        case April:
        case July:
            return 6;
        default:
            return -1;
    }
}
*/
int dayOfWeek(int day, int month, int year)
{
    return div(day + getMonthValue(month, year) + getYearValue(year) + getCenturyValue(year), 7).rem;
}

void getInput(int &day, int &month, int &year)
{
 int meses[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
 do{
    do{
       std::cout << "\n\tEnter the day (1-31): ";
       day = getInt();
      }while(day < 1 || day > 31);

    do{  
       std::cout << "\n\tEnter the month (1-12): ";
       month = getInt();
      }while(month < 1 || month > 12);

    do{  
       std::cout << "\n\tEnter the year: ";
       year = getInt();
      }while(year < 1100);

      if(__isleap(year))meses[1] = 29;

      if(day > meses[month-1])std::cout<<"\n\tO mes "<<month<<" do ano de "<<year<<" nao tem "<<day<<" dias!!!\n\n";

  }while(day > meses[month-1]);
}

int main()
{
 int day = 0;
 int month = 0;
 int year = 0;

 do{
    getInput(day, month, year);
    std::cout << "\n\tThe day of the week is " << weekDays[dayOfWeek(day, month, year)] << std::endl;

    std::cout << "\n\tRun the program again (y/N): ";  // signify n as default with capital letter

   }while('y' == getChar());

  return 0;
}
ответил dark777 23 SatEurope/Moscow2017-12-23T15:44:49+03:00Europe/Moscow12bEurope/MoscowSat, 23 Dec 2017 15:44:49 +0300 2017, 15:44:49

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132