1641 OOP in C (Date class)

Task

学习如何用C模仿C++的类:
How do you implement a class in C?
根据给出的文件实现C中的“Date class”。

Hints

先认真阅读上面的链接。
void DestroyDate(Date** p); 中,传入Date**的作用是避免“野指针”问题,细节请自己思考。

One more step

  • 试试在client代码中直接访问或修改Date的year等变量,跟C++版本有何不同?这会违背OOP吗?

  • 仔细辨别void SetDate(Date* date, int year, int month, int day)void Date::setDate(int year, int month, int day);两者的异同,
    包括参数数量,参数类型,命名大小写等(关于命名风格可参照前面提到的《Google C++ Style Guide》)。

  • 大胆猜想早期C++编译器是如何把C++程序转换为C程序的。另外,本题只是C中OOP的一种思路,有兴趣可以进一步了解

  • “OOP in C”有必要吗?请查阅资料了解其应用场景。

  • 如果void DestroyDate(Date** p); 传入Date*,可行吗?可能会导致什么问题?

  • 为什么要把free()封装到Destroy()里?直接让client代码调用free()合适吗?

  • 内存资源释放的责任在client身上,可能会有什么问题?有兴趣的同学可以了解C++的解决方案(需要超前学习,选做)。

  • 如果client写出date2 = date1这种代码,即两个指针指向同个“对象”,在内存资源释放上会有问题吗?有兴趣的同学可以了解C++的解决方案(需要超前学习,选做)。

Provided Codes

date_client.c

#include "date.h"
#include <stdio.h>
#include <assert.h>

void TestDate(Date* date, int after, int before) {
  printf("Year: %d\n", GetYear(date));
  printf("Month: %d\n", GetMonth(date));
  printf("Day: %d\n", GetDay(date));

  char* date_string = GetDateString(date);
  printf("Formatted: %s\n", date_string);

  DestroyDateString(&date_string);
  assert(date_string == NULL);
  DestroyDateString(&date_string);

  IncreaseDate(date);
  date_string = GetDateString(date);
  printf("1 day later: %s\n", date_string);
  DestroyDateString(&date_string);

  int i;
  for (i = 0; i < after; ++i) {
    IncreaseDate(date);
  }
  date_string = GetDateString(date);
  printf("Another %d day(s) later: %s\n", after, date_string);
  DestroyDateString(&date_string);

  for (i = 0; i < before; ++i) {
    DecreaseDate(date);
  }
  date_string = GetDateString(date);
  printf("Another %d day(s) earlier: %s\n", before, date_string);
  DestroyDateString(&date_string);  
}

int main() {
  int year, month, day;
  int after, before;
  scanf("%d%d%d%d%d", &year, &month, &day, &after, &before);

  Date* date1 = CreateDate(year, month, day);
  assert(sizeof(*date1) == sizeof(Date));

  Date* date2 = CopyDate(date1);
  assert(date1 != date2);
  assert(date1->month == date2->month);

  SetDate(date1, year + 1, month, day);
  SetYear(date1, year);
  SetMonth(date1, month);
  SetDay(date1, day);

  TestDate(date1, after, before);

  DestroyDate(&date1);
  DestroyDate(&date2);

  assert(date1 == NULL);
  DestroyDate(&date2);

  return 0;
}

/*
One probable test case:

1900 2 28 365 366
Year: 1900
Month: 2
Day: 28
Formatted: 1900-02-28
1 day later: 1900-03-01
Another 365 day(s) later: 1901-03-01
Another 366 day(s) earlier: 1900-02-28

*/

date.h

#ifndef DATE_H_
#define DATE_H_

typedef struct {
  int year, month, day;
} Date;

Date* CreateDate(int year, int month, int day);
void DestroyDate(Date** p);
Date* CopyDate(const Date* date);

int GetYear(const Date* date);
int GetMonth(const Date* date);
int GetDay(const Date* date);
void SetYear(Date* date, int year);
void SetMonth(Date* date, int month);
void SetDay(Date* date, int day);
void SetDate(Date* date, int year, int month, int day);

char* GetDateString(const Date* date);
void DestroyDateString(char** p);

void IncreaseDate(Date* date);
void DecreaseDate(Date* date);

#endif

Submission

date.c

#include<stdlib.h>
#include<stdio.h>
#include "date.h"

Date* CreateDate(int year, int month, int day) {
    Date* ppp = (Date*)malloc(sizeof(Date));
    ppp->year = year;
    ppp->month= month;
    ppp->day = day;
    return ppp;
}

void DestroyDate(Date** ppp) {
    free(*ppp);
    *ppp=NULL;
}

Date* CopyDate(const Date* date) {
    return CreateDate(date->year, date->month, date->day);
}

int GetYear(const Date* date) {
    return date->year;
}

int GetMonth(const Date* date) {
    return date->month;
}

int GetDay(const Date* date) {
    return date->day;
}

void SetYear(Date* date, int year) {
    date->year = year;
}

void SetMonth(Date* date, int month) {
    date->month = month;
}

void SetDay(Date* date, int day) {
    date->day = day;
}

void SetDate(Date* date, int year, int month, int day) {
    date->year = year;
    date->month = month;
    date->day = day;
}

char* GetDateString(const Date* date) {
    char* str = (char*)calloc(11, sizeof(char));
    sprintf(str, "%04d-%02d-%02d", date->year, date->month, date->day);
    return str;
}

void DestroyDateString(char** ppp) {
    free(*ppp);
    *ppp=NULL;
}

int Day(int month,int year){
if(month==2){
        if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0)
          return 29;
        return 28;
}
else if(month>0&&month<8){
        if(month%2==0)
            return 30;
            return 31;
    }
if(month%2==0)
            return 31;
            return 30;
}

void IncreaseDate(Date* date) {
    date->day++;
        if (date->day > Day(date->month,date->year)) {
            date->day = 1;
            date->month++;
        }
            if (date->month > 12) {
                date->month = 1;
                date->year++;
            }

}

void DecreaseDate(Date* date) {
    date->day--;
    if (date->day < 1&&date->month==1) {
        date->month=12;
        date->year--;
        date->day=31;
    }
    else if(date->day < 1){
        date->month--;
        date->day = Day(date->month,date->year);
    }   
}

Standard Answer

date.c

#include "date.h"
#include <stdlib.h>
#include <stdio.h>

Date* CreateDate(int year, int month, int day) {
  Date* date = (Date*)malloc(sizeof(Date));
  date->year = year;
  date->month = month;
  date->day = day;
  return date;
}

void DestroyDate(Date** p) {
  if (*p) {
    free(*p);
    *p = NULL;
  }
}

Date* CopyDate(const Date* date) {
  Date* new_date = (Date*)malloc(sizeof(Date));
  new_date->year = GetYear(date);
  new_date->month = GetMonth(date);
  new_date->day = GetDay(date);
  return new_date;
}

int GetYear(const Date* date) { return date->year; }
int GetMonth(const Date* date) { return date->month; }
int GetDay(const Date* date) { return date->day; }
void SetYear(Date* date, int year) { date->year = year; }
void SetMonth(Date* date, int month) { date->month = month; }
void SetDay(Date* date, int day) { date->day = day; }
void SetDate(Date* date, int year, int month, int day) {
  date->year = year;
  date->month = month;
  date->day = day;
}

char* GetDateString(const Date* date) {
  const int length_of_date_string = 10;
  char* date_string = (char*)malloc(sizeof(char)*(length_of_date_string + 1));
  snprintf(date_string,
          length_of_date_string + 1,
          "%04d-%02d-%02d",
          GetYear(date), GetMonth(date), GetDay(date));
  return date_string;
}

void DestroyDateString(char** p) {
  if (*p) {
    free(*p);
    *p = NULL;
  }
}

int GetDaysOfMonth(int year, int month) {
  if (month == 2) {
    return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ? 29 : 28;
  } else {
    int daysOfMonth[13] = { -1, 31, -1, 31, 30,
                                31, 30, 31, 31,
                                30, 31, 30, 31 };
    return daysOfMonth[month];
  }
}

void IncreaseDate(Date* date) {
  ++date->day;
  if (date->day > GetDaysOfMonth(date->year, date->month)) {
    date->day = 1;
    ++date->month;
    if (date->month > 12) {
      date->month = 1;
      ++date->year;
    }
  }
}

void DecreaseDate(Date* date) {
  --date->day;
  if (date->day < 1) {
    --date->month;
    if (date->month < 1) {
      date->month = 12;
      --date->year;
    }
    date->day = GetDaysOfMonth(date->year, date->month);
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值