2009-12-07 2 views
0

Я пишу программу, которая получает от пользователя month и year, а затем распечатывает календарь. Но календарь правильный только в январе (каждые два года).Проблема с домашним заданием календаря в C

Как сделать другие месяцы правильными? Что я делаю не так?

#include "stdafx.h" 

void printMonth (int* startDay, int* days); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 

    int startDay, days, year, month, a; 

    printf("enter year: "); 
    scanf("%d", &year); 
    printf("enter month: "); 
    scanf("%d", &month); 

    a = year - 1; 
    startDay = ((a * 365) + (a/4) - (a/100) + (a/400) + 1) % 7; 

    switch (month) 
    { 
    case 1: days = 31; 
     break; 
    case 2: days = 28; 
     break; 
    case 3: days = 31; 
     break; 
    case 4: days = 30; 
     break; 
    case 5: days = 31; 
     break; 
    case 6: days = 30; 
     break; 
    case 7: days = 31; 
     break; 
    case 8: days = 31; 
     break; 
    case 9: days = 30; 
     break; 
    case 10: days = 31; 
     break; 
    case 11: days = 30; 
     break; 
    case 12: days = 31; 
     break; 
    } 

    printMonth (&startDay, &days); 

    printf("\nstart day: %d\n", startDay); 
    printf("\na: %d\n", a); 

    return 0; 
} 

void printMonth (int* startDay, int* days) 
{ 
    int weekDay; 

    printf("Sun Mon Tue Wed Thu Fri Sat\n"); 
    printf("--- --- --- --- --- --- ---\n"); 

    for (weekDay = 0; weekDay < *startDay; weekDay++) 
     printf(" "); 

    for (int dayCount = 1; dayCount <= *days; dayCount++) 
    { 
     if (weekDay > 6) 
     { 
      printf("\n"); 
      weekDay = 1; 
     } 
     else 
      weekDay++; 
     printf("%3d ", dayCount); 
    } 

printf("\n--- --- --- --- --- --- ---\n"); 

return; 
} 
+4

Это домашнее задание? Если да, добавьте тег «домашняя работа». –

+0

ok, добавлен тег «домашняя работа»;) –

+3

Почему вы передаете аргументы 'startDay' и' days' в качестве указателей? Они не изменяются функцией 'printMonth()', поэтому вы должны передать их по значению. –

ответ

2

Ваш призыв к printMonth явно проходит январский день начала, а не день начала этого месяца.

+0

O ... Как пройти день начала другого месяца ??? –

+0

Ваша строка «startday = ...» показывает, что у вас есть формула для расчета начального дня года (поэтому в январе). Чтобы пройти день начала другого месяца, вам нужно будет рассчитать, что это за день. Можете ли вы выяснить формулу для определения дня начала месяца? –

+0

Если, например, день начала года - воскресенье, какой день недели начнется в феврале? Когда у вас есть ответ, как вы его вычислили? –

1

startDay - день недели первого дня года. Вам нужно передать день недели первого дня месяца.

Рассмотрите возможность изменения инструкции switch в массив. Вычислить февраль на основе високосного года, остальные могут быть статически назначены. Затем вы можете выполнить цикл суммирования массива, чтобы выяснить, сколько дней в году вам нужно начать, и добавить это в расчет startDay перед модулем 7, и вы можете передать количество дней в году, указав в массив.

Имейте в виду, что массивы C основаны на 0. Вы также должны проверить правильность ввода пользователя.

Если вы не знакомы с этим, в системе * NIX есть команда cal, которая может помочь вам проверить правильность вашего вывода, но будьте предупреждены: есть некоторые странные вещи, которые происходят в the history of calendars.

+0

Спасибо, но как получить другой месяц в неделю? –

+1

Ответ обновлен. – retracile

1

Вы принимаете такое же значение для startDay как: printMonth() независимо от того, какой месяц введен. Подумайте, сколько дней прошло с начала года до начала данного месяца, и из этого вы можете выяснить, в какой день начинается данный месяц.

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

год является високосным, если он делится на 4 (2008, 2012 являются високосными) и не делится на 100 (1900 не високосный год) если не делится на 400 (2000 високосный год). Поэтому:

leap_year = (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)) 
+0

Буду считать год назад, спасибо за внимание. –

+0

На самом деле вам нужно сначала рассмотреть високосные годы, чтобы выяснить, какой день недели начинается месяц, потому что за все месяцы после февраля будет зависеть февраль, 28 или 29 дней. –

+0

Например, если февраль начинается в воскресенье и составляет 28 дней, март также начнется в воскресенье. Однако, если это 29 дней, март начнется в понедельник. Поэтому важно знать, как долго февраль до определения даты начала любого месяца. –

3

1) Инициализируйте все свои переменные.

int startDay, days, year, month, a; 
startDay = -1; 
days = -1; 

В этом случае «-1» или «0» выражают значение, которое до сих пор не имеет реального содержания, предоставленный пользователем. В других случаях вы можете выбрать для инициализации «правдоподобное» допустимое значение по умолчанию. Это помогает отлаживать. Очень некрасиво проверять значения отладки, которые были там, где была мусор, когда вы создали свою переменную.

Я не помню, если C позволяет делать это в одной строке, например C++. Так или иначе, сделать инициализировать их.

2) Проверьте и подтвердите ввод пользователя.

printf("enter year: "); 
scanf("%d", &year); 
// Check validity of year here. If year not valid, ask again, abort, or anything. 

3) Проверка логики кода с утверждениями (не делать этого, чтобы подтвердить ввод данных пользователя, конечно же, см 2).

assert(month >= 1); 
assert(month <= 12); 
switch (month) 
{ // ... 

void printMonth (int startDay, int days) 
{ 
    assert(startDay >= 1); 
    assert(startDay <= 31); 
    assert(days >= 0); 
    // ... 

Двойная проверка, что вы находитесь в режиме отладки и что неудачные утверждения вообще что-то делают. За одно исполнение просто напишите assert(0); (я не знаю, есть ли у вас логические значения в C). Это должно потерпеть неудачу.

4) Делайте разные вещи в разных функциях. Задавая пользователю месяц и делая что-то «сложное» с ним позже, это запах кода.

+0

Почему startDay и days = -1? –

+0

@Programme Newbie: вы можете использовать 0 или -5 или -1000, если хотите. В вашем исходном коде значение было любым значением. С моей предлагаемой модификацией вы сначала присвойте значение, которое, как вы знаете, недействительным (т. Е. Оно не является допустимым пользователем, если, конечно, ваши клиенты не являются древними греками). Позже вы назначаете значение, введенное пользователем, поэтому при отладке вы уверены, откуда все взялось. В вашем примере может произойти непредвиденное событие, но в более широком примере, как правило, очень хорошая идея инициализировать ваши целые значения по умолчанию. –

+1

Конкретный пример из приведенного кода: Если пользователь предоставляет 0 или 13 в качестве месяца, 'days' не будет инициализирован до его использования. – retracile

Смежные вопросы