2016-05-13 3 views
2

Я запрограммировал очень простой календарь на C. Он принимает год в качестве входных данных и затем вычисляет даты и дни недели для этого года. Предполагается, что дата 0001-01-01 - понедельник. У меня получилось хорошо работать, кроме как в одном месте. Когда он собирается распечатать строку со всеми 31-ю датами. В основном, что происходит неправильно, когда он проверяет, есть ли что-нибудь для печати в 31-ом классе (чего там нет), он исключает переменную недели недели. Который делает следующие 31 даты неверными. Есть ли кто-нибудь, кто может увидеть, что я сделал что-то неправильно или могу помочь мне? :)Weird output Calendar in C

EDIT Забыл упомянуть, что это задача, которую нужно решить без каких-либо формул для расчета дневного кода и так далее. Единственной ссылкой, разрешенной для использования, является то, что дата 0001-01-01 является понедельником.

Heres my code. (Да, это немного грязный атм, но я все еще учусь.)

int isLeapYear(int year){ 
    if(((year%4==0) && (year%100!=0)) || (year%400==0)){ 
      return 1; 
     } 
    else 
     return 0; 
} 
int getYear(){ 
    int year = 0; 
    while(year==0 || year < 0){ 
     printf("Enter year: "); 
     scanf("%d", &year); 
     if(year > 0){ 
      break; 
     } 
     printf("Invalid input. Try again.\n\n"); 
    } 
    return year; 
} 
void printWeekday(int w){ 
    switch(w){ 
     case 0: 
      printf("Sun"); 
      break; 
     case 1: 
      printf("Mon"); 
      break; 
     case 2: 
      printf("Tue"); 
      break; 
     case 3: 
      printf("Wed"); 
      break; 
     case 4: 
      printf("Thu"); 
      break; 
     case 5: 
      printf("Fri"); 
      break; 
     case 6: 
      printf("Sat"); 
      break; 
    } 
} 
void printMonth(int m){ 
    switch(m){ 
     case 1: 
      printf("Jan"); 
      break; 
     case 2: 
      printf("  Feb"); 
      break; 
     case 3: 
      printf("  Mar"); 
      break; 
     case 4: 
      printf("  Apr"); 
      break; 
     case 5: 
      printf("  May"); 
      break; 
     case 6: 
      printf("  Jun"); 
      break; 
     case 7: 
      printf("  Jul"); 
      break; 
     case 8: 
      printf("  Aug"); 
      break; 
     case 9: 
      printf("  Sep"); 
      break; 
     case 10: 
      printf("  Oct"); 
      break; 
     case 11: 
      printf("  Nov"); 
      break; 
     case 12: 
      printf("  Dec\n"); 
      break; 
    } 
} 
void calendar(int year){ 
    int y = 1; 
    int m = 1; 
    int d = 1; 
    int loop = 1; 
    int day = 1; 
    int days_in_month[14] = {0,31,28,31,30,31,30,31,31,30,31,30,31,0}; 
    if(isLeapYear(year)){ 
     days_in_month[1] = 29; 
    } 
    for(m=1; m<=12; m++){ 
     printMonth(m); 
    } 
    while(loop){ 
     int weekday = 1; 
      for(y=1; y<=year; y++){ 
       for(m=1; m<=12; m++){ 
        for(d=1; d<=31; d++){ 

         if(weekday%7 == 0){ 
          // printf("h"); 
          weekday = 0; 
         } 
         if(y==year){ 
          if(day>days_in_month[m]){ 
           printf("   "); 
           printf("%d", weekday); 
           break; 
          }else if(d == day){ 
           //printf("%d", weekday); 
           if(m == 1){ 
            printf("%02d ", d); 
            printWeekday(weekday); 
           }else if(m == 12){ 
            printf(" %02d ", d); 
            printWeekday(weekday); 
            printf("\n"); 
           }else{ 
            printf(" %02d ", d); 
            printWeekday(weekday); 
           } 
          } 
         } 
         if(d<=days_in_month[m]){ 
          weekday = weekday + 1; 
         } 
        } 
       } 
      } 
      day++; 
      if(day == 32){ 
       break; 
      } 
     } 
} 
int main() 
{ 
    int end = 1; 
    while(end){ 
     int year = getYear(); 
     printf("               %d\n", year); 
     calendar(year); 
     printf("\nEnter 0 to quit: "); 
     scanf("%d", &end); 
     //system("cls"); 
    } 
    return 0; 
} 
+2

Days_in_Month [1] = 29; -> должно быть days_in_month [2] = 29; –

+0

Ой, я забыл изменить это, когда тестировал, хотя это относится только к високосным годам, это не проблема печально :) –

+0

Я полагаю, что ваш вопрос о 'void calendar (int year)' в вашем коде. Не могли бы вы объяснить, какой должна быть ожидаемая входная функция этой функции и ее соответствующая продукция? Примером может служить пример (возможно, один, показывающий ошибку). –

ответ

0

Здесь, внутри calendar() функция добавить этот код:

if(day>days_in_month[m] /*Add this code: */ && d>days_in_month[m]){ 
     printf("   "); 
     printf("%d", weekday); 
     break; 
}else if(d == day){... 

Где проблема? Ну, ты видел 31-й день марша? В субботу: enter image description here

В конце итерации дней (я имею в виду for(d=1; d<=31; d++){ цикл) вы повторяете будний день. Итак, первый апрель должен быть в воскресенье. Это действительно, если вы проверяете результаты.

Но вы рассчитываете будний день на день месяца. Поэтому, когда мы печатаем 31 марта, наша переменная day равна 31.

Теперь марш закончился (мы печатаем 31 марта), наш будний день начинается в воскресенье. И мы собираемся рассчитать дни апреля. Но посмотрите на свой код, внутри цикла for(d=1; d<=31; d++), у вас есть if(day>days_in_month[m]) {break;}. И когда наша программа проверяет первый день апреля, а day равна 31, тогда ее стоп-расчетные дни на апрель с инструкцией break. Мы собираемся рассчитать дни мая. Но наш будний день по-прежнему остается в воскресенье. Если вы видите действительный код, сначала может быть вторник. Но когда day переменная равна 31, сначала может начинаться как воскресенье. И начиная с 1-го мая все дни вычислялись неправильно.

ПРОБЛЕМА LEAPS ЛЕТ: Поскольку вы используете это:

if(isLeapYear(year)){ 
    days_in_month[2] = 29; 
} 

Он добавляет 29 дней в течение каждого года (Так вы добавить три 29-дней в первые три года, и вы увидите результат в 1-го января 4-й год :)).

Чтобы решить эту проблему, удалите эти фрагменты кода. И внутри цикла в течение нескольких месяцев, добавить переменную, которая будет представлять количество дней:

for(m=1; m<=12; m++){     
int monthDays = days_in_month[m]; /*Add this variable*/ 
if (m==2 && isLeapYear(y)) 
    monthDays++; // Add 29th day to feb. of leap year  
for(d=1; d<=31; d++){... 

И внутри функции, заменить все days_in_month[m] на monthDays

+0

Этот способ, похоже, устранил проблему, я так благодарю вас многое для подробного ответа. Хотя сейчас, похоже, проблемы возникают в течение високосных лет. При тестировании я узнал, что за год 1,2 и 3 цифры совпадают. И к концу 3-го дня рабочий день - это среда. Но когда я смотрю на 4-й год, он начинается в субботу, что совершенно неправильно, это должно начаться в четверг. Любые мысли по этому поводу? :) –

+1

Посмотрите на ответ. Я отредактировал его. –

+0

Большое спасибо, это исправлено. И большое спасибо за подробный ответ :) –

0

Вместо проведения переменного буднего дня вы можете вызвать функцию, которая будет вычислять день недели заданной даты. Для этого вы можете использовать алгоритм «День недели» Томохико Сакамото.

int dayofweek(int d, int m , int y){ 
    static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 }; 
    y -= m < 3; 
    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; 
} 
// 0 - Sunday 
// 1 - Monday and so on 

Если вы хотите, чтобы понять этот алгоритм вы можете увидеть подробное объяснение здесь: https://www.quora.com/How-does-Tomohiko-Sakamotos-Algorithm-work

Но так как вы новичок, я Wouldnt действительно recoment это :) Его немного сбивает с толку.

После реализации этого вы можете упростить функцию календаря быть

void calendar(int year) { 

    int days_in_month[14] = { 0,31,28,31,30,31,30,31,31,30,31,30,31,0 }; 

    if (isLeapYear(year)) { 
     days_in_month[2] = 29; 
    } 
    for (int m = 1; m<=12; m++) { 
     printMonth(m); 
    } 

    for (int d = 1; d<=31; d++) { 
     for (int m = 1; m<=12; m++) { 
      if (d <= days_in_month[m]) { 
       int weekday = dayofweek(d, m, year); 
       printf("%02d ", d); 
       printWeekday(weekday); 
       printf(" "); 
      } 
      else { 
       printf("   "); 
      } 
     } 
     printf("\n"); 
    }    

} 

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

+0

Я вижу, я могу понять, почему это намного эффективнее моего пути. Но в моей задаче мне не разрешено использовать какие-либо формулы или алгоритмы, найденные в сети. Единственное, на что мне позволено ссылаться, это то, что дата 0001-01-01 - понедельник. (Я знаю, это делает задачу более сложной ха-ха) –

+1

@HampusSiversson: это довольно плохая отправная точка. Предполагаете ли вы адаптироваться к канонической реформе 1582 года, или ваш учитель ретроактивно отрегулировал ее (так на самом деле дни для дат, прежде чем они ошибаются)? – usr2564301

+0

@ HampusSiversson Ну, тогда вы можете переписать функцию 'dayofweek' таким образом, чтобы она повторялась с 01-01-0001 и находила день недели данного дня. –