注册 登录
编程论坛 C++教室

华为又出变态面试题!大家请看以下代码 在看懂的同时 修改错误!

单调黑白 发布于 2007-12-11 14:45, 4409 次点击
#include<iostream>
using namespace std;
#include <ctime>

class CLF_DateTime
{
private:

    struct tm *local;

public:
    CLF_DateTime(int year, int month, int day,int hour, int min,int sec);

    CLF_DateTime(CLF_DateTime &x);
    
    CLF_DateTime()
    {
        
    }    
    ~CLF_DateTime(void);
    void display(char * strdisplay);
    void setdisplay(char * setstrdisplay);
    int compare(CLF_DateTime* pa, CLF_DateTime* pb);

};

CLF_DateTime::CLF_DateTime(CLF_DateTime &x)
    {
        local = new tm;
        local->tm_year =x.local->tm_year;//struct tm中定义的年成员tm_year是以1900为基数的,也就是说他显示2007时tm_year值并不是2007
        local->tm_mon = x.local->tm_mon;//月份可见definition里有说明是[0,11]所以比现实小了一个月
        local->tm_mday = x.local->tm_mday;
        local->tm_hour =x.local->tm_hour;
        local->tm_min =x.local->tm_min;
        local->tm_sec =x.local->tm_sec;
        
    }
CLF_DateTime::CLF_DateTime(int year, int month, int day,int hour, int min,int sec)
    {
        local = new tm;
        local->tm_year = year-1900;//struct tm中定义的年成员tm_year是以1900为基数的,也就是说他显示2007时tm_year值并不是2007
        local->tm_mon = month-1;//月份可见definition里有说明是[0,11]所以比现实小了一个月
        local->tm_mday = day;
        local->tm_hour =hour;
        local->tm_min =min;
        local->tm_sec =sec;
   
    }

CLF_DateTime::~CLF_DateTime(void)
    {
        delete(local);
        local = NULL;
    }

void CLF_DateTime::display(char * strdisplay)
    {
        
        strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",local);
        

    }
void CLF_DateTime::setdisplay(char * setstrdisplay)
    {
        if(local->tm_sec<30&&local->tm_sec>=0)
        {   
            local->tm_sec=0;
            strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
        }
   
        else if (local->tm_sec>=30&&local->tm_sec<=60)
        {
            local->tm_min+=1;
            local->tm_sec=0;
            strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
        }
        if (local->tm_min>=60)
        {
            local->tm_hour+=1;
            local->tm_min=0;
            strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
        }
        if (local->tm_hour>=24)
        {
            local->tm_mday+=1;
            local->tm_hour=0;
            strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
    
        }
        if (local->tm_mon==1||local->tm_mon==3||local->tm_mon==5||local->tm_mon==7||local->tm_mon==8||local->tm_mon==10||local->tm_mon==12)
        {
            if(local->tm_mday>=31)
            {
                local->tm_mon+=1;
                local->tm_mday=1;
                strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
            
            }
        }
        else if (local->tm_mon==4||local->tm_mon==6||local->tm_mon==9||local->tm_mon==11)
        {
            if(local->tm_mday>=30)
            {
                local->tm_mon+=1;
                local->tm_mday=1;
                strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
                
            }
        }
        else if (local->tm_mon==2&&(local->tm_year%400==0||(local->tm_year%4==0&&local->tm_year%100!==0)))
        {
            if(local->tm_mday>=29)
            {
                local->tm_mon+=1;
                local->tm_mday=1;
                strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
                
            }
        }
        else if (local->tm_mon=2)
        {
            if(local->tm_mday>=28)
            {
                local->tm_mon+=1;
                local->tm_mday=1;
                strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
                
            }
        }
        if (local->tm_mon>=12)
        {
            local->tm_year+=1;
            local->tm_mon=1;
            strftime(setstrdisplay,80,"%Y-%m-%d %H:%M:%S",local);
        
            
        }


int CLF_DateTime::compare(CLF_DateTime* pa, CLF_DateTime* pb)
    {
        
            if(pa.local->tm_year>pb.local->tm_year)
            
            {
                cout<<"1"<<endl;
            }
            else if(pa.local->tm_year<pb.local->tm_year)
            {
                cout<<"-1"<<endl;
            }
            else if(pa.local->tm_yaer==pb.local->tm_year)
            {
                if (pa.local->tm_mon>pb.local->tm_mon)
                {
                    cout<<"1"<<endl;
                }
                else if(pa.local->tm_mon<pb.local->tm_mon)
                {
                    cout<<"-1"<<endl;
                }
                else if(pa.local->tm_mon==pb.local->tm_mon)
                {
                    if(pa.local->tm_mday>pb.local->tm_mday)
                    {
                        cout<<"1"<<endl;
                    }
                    else if(pa.local->tm_mday<pb.local->tm_mday)
                    {
                        cout<<"-1"<<endl;
                    }
                    else if(pa.local->tm_mday==pb.local->tm_mday)
                    {
                        if(pa.local->tm_hour>pb.local->tm_hour)
                        {
                            cout<<"1"<<endl;
                        }
                        else if(pa.local->tm_hour<pb.local->tm_hour)
                            {
                                cout<<"-1"<<endl;
                            }
                        else if(pa.local->tm_hour==pb.local->tm_hour)
                        {
                            if(pa.local->tm_min>pb.local->tm_min)
                            {
                                cout<<"1"<<endl;
                            }
                            else if(pa.local->tm_min<pb.local->tm_min)
                            {
                                cout<<"-1"<<endl;
                            }
                            else if (pa.local->tm_min==pb.local->tm_min)
                            {
                                if(pa.local->tm_sec!=0)
                                {
                                    cout<<"1"<<endl;
                                }
                                else  
                                {
                                    cout<<"0"<<endl;
                                }
                            }
                
                
    }

void main()
{
    CLF_DateTime pa(2007,11,8,14,52,10);
    CLF_DateTime pb(pa);
    char testdisplay[100];

    cout<<"Your input date and time is: ";
    pa.display(testdisplay);
    cout<<strdisplay<<endl;
    cout<<"Provide rounding:";
    pa.setdisplay(testdisplay);
    cout <<setstrdisplay<<endl;
    cout<<"compare time:";
    (pb);
}
33 回复
#2
孤魂居士2007-12-12 01:30
面试题目是这种
我看我就回去种地算了
#3
MilesWang2007-12-12 23:39
这几个else if 就能把人搞晕!
#4
中学者2007-12-13 08:06
没仔细看,但是有个最明显的错误就是拷贝函数的设计~
#5
风之梦2007-12-13 17:26
值行一看呀,回去研究一下
#6
beyond07022007-12-13 18:16
这真是面试题吗,真的话,俺可同意2#说的
#7
StarWing832007-12-13 21:20
这个程序挺简单的啊,哪里变态了??
同意4楼,拷贝函数也有问题……而且
int CLF_DateTime::compare(CLF_DateTime* pa, CLF_DateTime* pb)
这个函数太失败了……效率低下语句啰嗦……
诸如打字错误和括号匹配方面的问题就不说了,整个程序使用动态内存分配就是个错误。
两百多行代码,其实在五十行内就完全可以搞定……
这是我的实现:
程序代码:
#include <iostream>
using namespace std;
#include <ctime>

class CLF_DateTime : public tm {
    inline void carry(int& v1,int& v2,int v3){v1+=v2/v3;v2%=v3;}
public:
    CLF_DateTime(int year=1900,int month=1,int day=1,
        int hour=0,int min=0,int sec=0) {
            tm_year=year;tm_mon=month;tm_mday=day;
            tm_hour=hour;tm_min=min;tm_sec=sec;
    }
    ~CLF_DateTime(){}
    char* display(char* strdisplay) {
        strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this);
        return strdisplay;
    }
    char* setdisplay(char* strdisplay) {
        tm_min+=tm_sec>=30; tm_sec=0;
        carry(tm_hour,tm_min,60);
        carry(tm_mday,tm_hour,24);
        switch (tm_mon) {
        case 1:case 3:case 5:case 7:case 8:
        case 10:case 12:carry(tm_mon,tm_mday,31);break;
        case 2:carry(tm_mon,tm_mday,28);break;
        default:carry(tm_mon,tm_mday,30);            
        }
        carry(tm_year,tm_mon,12);
        return display(strdisplay);
    }
    int compare(CLF_DateTime& pb) {
        int t;
        if (t=tm_year-pb.tm_year)return t>0?1:-1;
        if (t=tm_mon-pb.tm_mon)return t>0?1:-1;
        if (t=tm_mday-pb.tm_mday)return t>0?1:-1;
        if (t=tm_hour-pb.tm_hour)return t>0?1:-1;
        if (t=tm_min-pb.tm_min)return t>0?1:-1;
        return t;
    }
};

void main() {
    CLF_DateTime pa(2007,11,8,23,59,59);
    CLF_DateTime pb(pa);
    char testdisplay[100];

    cout<<"Your input date and time is: ";
    cout<<pa.display(testdisplay)<<endl;
    cout<<"Provide rounding:"<<pa.setdisplay(testdisplay)<<endl;
    cout<<"compare time:"<<(pb)<<endl;
    getchar();
}  


[[italic] 本帖最后由 StarWing83 于 2007-12-13 23:40 编辑 [/italic]]
#8
孤魂居士2007-12-15 00:51

自惭形秽
#9
中学者2007-12-15 12:30
路过...............
#10
永夜的极光2007-12-16 14:31
要别人帮你改错就直接说,扯上华为干什么

一看就知道是假的,华为的题目会写得这么烂?
#11
单调黑白2007-12-17 09:20
回复 7# 的帖子
谢谢您的程序 好厉害啊 但是我运行了一下 有一些问题,
1.年输出的是3907
2.题目的意思是原有时间同四舍五入后的时间进行比较 原有时间大输出1,四舍五入时间大输出-1,相等输出0.您的程序不太符合题意.
3.您的程序我没有看到对闰年的判断.
谢谢指教!
#12
单调黑白2007-12-17 11:31
回复 7# 的帖子
我把您的程序改动了一下 但还是有问题!请您看看再给些指教 谢谢!
#include <iostream>
using namespace std;
#include <ctime>

class CLF_DateTime : public tm
{
    inline void carry(int& v1,int& v2,int v3)
{
    v1+=v2/v3;
    v2%=v3;
}
public:
    CLF_DateTime(int year=0,int month=0,int day=0,int hour=0,int min=0,int sec=0)
    {
            tm_year=year-1900;tm_mon=month-1;tm_mday=day;
            tm_hour=hour;tm_min=min;tm_sec=sec;
       }

    ~CLF_DateTime()
    {
    
    }

char* display(char* strdisplay)
    {
        strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this);
        return strdisplay;
    }
char* setdisplay(char* strdisplay)
    {
        tm_min+=tm_sec>=30;
        tm_sec=0;
        carry(tm_hour,tm_min,60);
        carry(tm_mday,tm_hour,24);
        switch (tm_mon)
        {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            carry(tm_mon,tm_mday,31);
            break;
        case 2:
            if (tm_year%400==0||(tm_year%4==0&&tm_year%100!=0))
                carry(tm_mon,tm_mday,29);
            else
                carry(tm_mon,tm_mday,28);
            break;
        default:
            carry(tm_mon,tm_mday,30);            
        }
        carry(tm_year,tm_mon,12);
        return display(strdisplay);
    }
int compare(CLF_DateTime& pb)
    {

        if(tm_year>pb.tm_year)
            return 1;
        else if(tm_year<pb.tm_year)
            return -1;
        else if(tm_yaer==pb.tm_year)
        {
            if (tm_mon>pb.tm_mon)
                return 1;
            else if(>tm_mon<pb.tm_mon)
                return -1;
        }    
        else if(tm_mon==pb.tm_mon)
        {
            if(tm_mday>pb.tm_mday)
                return 1;
            else if(tm_mday<pb.tm_mday)
                return -1;
        }    
        else if(tm_mday==pb.tm_mday)
        {
            if(tm_hour>pa.tm_hour)
                return 1;
            else if(tm_hour<pb.tm_hour)
                return -1;
        }
        else if(tm_hour==pb.tm_hour)
        {
            if(tm_min>pb.tm_min)
                return 1;
            else if(tm_min<pb.tm_min)
                return -1;
        }    
        else if (tm_min==pb.tm_min)
        {
            if(pb.tm_sec!=0)
                return 1;
            else  
                return 0;
                                
        }
    }

};
void main()
{
    CLF_DateTime pa(2007,12,31,23,59,59);
    CLF_DateTime pb(pa);
    char testdisplay[100];

    cout<<"Your input date and time is: ";
    cout<<pa.display(testdisplay)<<endl;
    cout<<"Provide rounding:"<<pa.setdisplay(testdisplay)<<endl;
    cout<<"compare time:"<<(pb)<<endl;
    getchar();
}
#13
sunkaidong2007-12-17 18:25
这个有点想07年的程序员的考试题目.区别在于一个是c语言一个是c++.不知道记错没有
#14
破坏神2007-12-17 20:07
我是初学者。。。。
完全看不懂啊。。。。
#15
StarWing832007-12-17 22:38
哎……你好像没看懂的conpare函数。我就举一个例子吧

        if(tm_year>pb.tm_year)
            return 1;
        else if(tm_year<pb.tm_year)
            return -1;
这一句,如果tm_year大于pb.tm_year返回1,反之返回-1,如果相等就判断别的。我的写法
int t;
if(t=tm_year-pb.tm_year)return t>0?1:-1;
这一句,如果tm_year大于pb.tm_year,那么t就是正的,那么就会返回1,反之返回-1,如果相等的话t就是0,也就是false,则会继续向下面运行。这个是以前写汇编程序的时候经常用到的方法,汇编的CMP语句其实就是对两个数相减返回结果。你先好好看我的compare。
你的那个版本的compare我实在是不敢再看了。你要是一直想写这种代码你干脆去研究Java和VB算了……
闰年是懒得写了,那个set...函数比较无聊,有时间不如你写个carry算了(时间进位函数)。那个函数就是个进位的问题。
最后要说的是。对这个结构体做包装本来就是个很无聊的事情……你添一些比较高级点的功能嘛………………

[[italic] 本帖最后由 StarWing83 于 2007-12-17 23:21 编辑 [/italic]]
#16
StarWing832007-12-17 23:05
程序代码:
#include <iostream>
using namespace std;
#include <ctime>
#define TM_TIMEBASE 1900
class CLF_DateTime : public tm {
    inline void carry(int& v1,int& v2,int v3){v1+=v2/v3;v2%=v3;}
    inline bool isleap(int y){return y%100?!(y%4):!(y%400);}
public:
    bool isleap(){return isleap(tm_year+TM_TIMEBASE);}
    CLF_DateTime(int year=1900,int month=1,int day=1,
        int hour=0,int min=0,int sec=0) {
            tm_year=year-TM_TIMEBASE;tm_mon=month-1;tm_mday=day;
            tm_hour=hour;tm_min=min;tm_sec=sec;
    }
    ~CLF_DateTime(){}
    char* display(char* strdisplay) {
        strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this);
        return strdisplay;
    }
    char* setdisplay(char* strdisplay) {
        tm_min+=tm_sec>=30; tm_sec=0;
        carry(tm_hour,tm_min,60);
        carry(tm_mday,tm_hour,24);
        tm_mday--;//tm_mday属于1~max但是判断属于0~max-1,故这里减一,以前的有Bug
        switch (tm_mon+1) {
        case 1:case 3:case 5:case 7:case 8:
        case 10:case 12:carry(tm_mon,tm_mday,31);break;
        case 2:carry(tm_mon,tm_mday,28+isleap());break;
        default:carry(tm_mon,tm_mday,30);            
        }tm_mday++;//恢复mday
        carry(tm_year,tm_mon,12);
        return display(strdisplay);
    }
    int compare(CLF_DateTime& pb) {
        int t;
        if (t=tm_year-pb.tm_year)return t>0?1:-1;
        if (t=tm_mon -pb.tm_mon )return t>0?1:-1;
        if (t=tm_mday-pb.tm_mday)return t>0?1:-1;
        if (t=tm_hour-pb.tm_hour)return t>0?1:-1;
        if (t=tm_min -pb.tm_min )return t>0?1:-1;
        if (t=tm_sec -pb.tm_sec )return t>0?1:-1;
        return t;
    }
};

void main() {
    CLF_DateTime pa(2000,2,28,23,59,59);
    CLF_DateTime pb(pa);
    char testdisplay[100];

    cout<<"Your input date and time is: "<<pa.display(testdisplay)<<endl;
    cout<<"leap year?"<<pa.isleap()<<endl;
    cout<<"Provide rounding:"<<pa.setdisplay(testdisplay)<<endl;
    cout<<"compare time:"<<(pb)<<endl;
    getchar();
}
1和3帮你改好了,2本来就不是错误。从代码看你的四舍五入是指将秒设置成0或者30然后进位。那么pa是调整后的时间,在我的程序里(注意数据跟你的不一样)pa是大于pb的,返回1是正确的。但是compare里面我漏写了一行代码所以没有判断秒,这里改了过来。还有,你的闰年检查有问题,注意年份要加上1900再检查。
程序对于错误的时间不会报错,只是将多出来的日子加到规整后的时间里。比如如果你写2000-2-30那么会被规整成2000-3-2(加了进位的一天,又加了2月份多出来的一天),如果希望报错的话在carry里面检查就可以了。
代码经仔细检查已经没有Bug了。你可以再查一遍。
最后,以后你要是需要别人改代码的时候最好不好带上华为……

[[italic] 本帖最后由 StarWing83 于 2007-12-17 23:56 编辑 [/italic]]
#17
单调黑白2007-12-18 10:08
回复 18# 的帖子
首先我想真心的对您说声谢谢!
对于一个不认识的人 您能如此细致的进行讲解 真的让我十分的感动!
我是一个c++的初学者,对于您写的程序我真的好佩服!其中有很多东西都是我无法想到的!看您的程序让我学习到了很多东西!谢谢
我希望能和您认识!并渴望和您成为朋友!
我的qq:20666839
我的msn:ppxxu@
#18
单调黑白2007-12-18 13:49
回复 18# 的帖子
我还想问您一下 如果我想把这个程序 的定义和实现部分分开 需要如何改动程序啊 我的意思就是在类里只是定义变量 然后在类外面实现 最后再用main()来调用 一共3个文件 一个.h 两个.cpp 希望您再给些指点 谢谢!
#19
StarWing832007-12-18 16:30
哦,这个很简单的。我就举个例子好了。你理解以后可以很简单地修改源代码。不过我提醒你,如果你把实现和声明分开的话,那么成员函数不再具有默认的inline修饰符(isleap和carry的inline修饰符是我为了强调加的),你需要手动为一些函数加上inline修饰。
假设有三个文件。test.h包含类声明。test.cpp包含类的实现。main.cpp包含对类的使用。代码如下:
在test.h中:
程序代码:
//下面两行是为了防止一个头文件被载入两次
#ifndef _TEST_H_
#define _TEST_H_

class test{
public:
    test();//注意分号结尾,没有实现代码
    void display();//同上
private:
    void print();
};
/*
和第1,2行呼应。意思是,如果定义了_TEST_H_,
那么就跳过上面的代码,如果没有定义,就定义。
这样这份代码就可以只包含一遍了。如果你使用
VC++2005的话,就只在文件开头加上一句
#pragma once就可以了,不需要这么麻烦
*/
#endif _TEST_H_
在test.cpp中:
程序代码:
//包含头文件
#include "test.h"
#include <iostream>
using namespace std;
test::test() {
    cout<<"in Test::Test\n";
}

void test::display(){
    cout<<"In Test::display\n";
    print();
}


void test::print(){
    cout<<"In Test::print\n";
}

 
在main.cpp中:
程序代码:
//使用源代码的时候,也需要包含头文件
#include "test.h"
#include <iostream>
using namespace std;
int main(){
    test t1;
    t1.display();
    getchar();
}
我没有对代码进行编译。只是简单地演示一下该怎么做。只需要像上面一样就可以了。实现和使用会被编译到不同的obj里面去。

[[italic] 本帖最后由 StarWing83 于 2007-12-18 16:33 编辑 [/italic]]
#20
StarWing832007-12-18 17:45
具体是这样的。
在CLF.h中:
程序代码:
#ifndef _CLF_H_
#define _CLF_H_
#include <ctime>
#define TM_TIMEBASE 1900

class CLF_DateTime : public tm {
    void carry(int& v1,int& v2,int v3);
    bool isleap(int y);
public:
    bool isleap();
    CLF_DateTime(int year=1900,int month=1,int day=1,
        int hour=0,int min=0,int sec=0);
    ~CLF_DateTime(){}
    char* display(char* strdisplay);
    char* setdisplay(char* strdisplay);
    int compare(CLF_DateTime& pb);
};
#endif
在CLF.cpp中:
程序代码:
#include "CLF.h"
#include <iostream>
using namespace std;

inline void CLF_DateTime::carry( int& v1,int& v2,int v3 ) {
    v1+=v2/v3;
    v2%=v3;
}

inline bool CLF_DateTime::isleap( int y ) {
    return y%100?!(y%4):!(y%400);
}

bool CLF_DateTime::isleap() {
    return isleap(tm_year+TM_TIMEBASE);
}

CLF_DateTime::CLF_DateTime( int year/*=1900*/,int month/*=1*/,int day/*=1*/, int hour/*=0*/,int min/*=0*/,int sec/*=0*/ ) {
    tm_year=year-TM_TIMEBASE;
    tm_mon=month-1;
    tm_mday=day;
    tm_hour=hour;
    tm_min=min;
    tm_sec=sec;
}

char* CLF_DateTime::display( char* strdisplay ) {
    strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this);
    return strdisplay;
}

char* CLF_DateTime::setdisplay( char* strdisplay ) {
    tm_min+=tm_sec>=30;
    tm_sec=0;
    carry(tm_hour,tm_min,60);
    carry(tm_mday,tm_hour,24);
    tm_mday--;
    switch (tm_mon+1) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        carry(tm_mon,tm_mday,31);
        break;
    case 2:
        carry(tm_mon,tm_mday,28+isleap());
        break;
    default:
        carry(tm_mon,tm_mday,30);
    }
    tm_mday++;
    carry(tm_year,tm_mon,12);
    return display(strdisplay);
}

int CLF_DateTime::compare( CLF_DateTime& pb ) {
    int t;
    if (t=tm_year-pb.tm_year)goto ret;
    if (t=tm_mon -pb.tm_mon )goto ret;
    if (t=tm_mday-pb.tm_mday)goto ret;
    if (t=tm_hour-pb.tm_hour)goto ret;
    if (t=tm_min -pb.tm_min )goto ret;
    if (t=tm_sec -pb.tm_sec )goto ret;
    return t;
ret:
    return t>0?1:-1;
}
在main.cpp中:
程序代码:
#include "CLF.h"
    #include "iostream"
    using namespace std;
   
    int main() {
    CLF_DateTime pa(2000,2,28,23,59,59);
    CLF_DateTime pb(pa);
    char testdisplay[100];

    cout<<"Your input date and time is: "<<pa.display(testdisplay)<<endl;
    cout<<"leap year?"<<pa.isleap()<<endl;
    cout<<"Provide rounding:"<<pa.setdisplay(testdisplay)<<endl;
    cout<<"compare time:"<<(pb)<<endl;
    getchar();
}


[[italic] 本帖最后由 StarWing83 于 2007-12-18 17:47 编辑 [/italic]]
#21
无缘今生2007-12-18 18:12
StarWing83, 你的耐心真让我佩服!!!
#22
单调黑白2007-12-19 16:25
高手快来!StarWing83兄弟快来!!
这是之前StarWing83帮我改的程序,但有个人对这段程序做了如下评语,大家觉得他说的有根据吗?如果没有请告诉我他说的哪不对!我好反驳他!急!


#include "CLF_DateTime.h"
#include <iostream>
using namespace std;

lnline void CLF_DateTime::carry( int& v1,int& v2,int v3 )
{
    v1+=v2/v3; //Remark From Terence:  在沒有測試的情況下導入數據 ( 數據完整性)
    v2%=v3; //Remark From Terence:  在沒有測試的情況下導入數據 ( 數據完整性)
}

lnline bool CLF_DateTime::isleap( int y )
{
    return y%100?!(y%4):!(y%400);   //Remark From Terence:  x ? a : b  這種語法是不建議使用的. (可讀性, 可維護性)
                                                    //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性)
 
}

bool CLF_DateTime::isleap()
{
    return isleap(tm_year+TM_TIMEBASE);
}

CLF_DateTime::CLF_DateTime(int year/*=1900*/,int month/*=1*/,int day/*=1*/, int hour/*=0*/,int min/*=0*/,int sec/*=0*/)
{
    tm_year=year-TM_TIMEBASE; //Remark From Terence:  在沒有測試的情況下導入數據 (數據完整性 )
    tm_mon=month-1;//Remark From Terence:  在沒有測試的情況下導入數據 ( 數據完整性)
    tm_mday=day;//Remark From Terence:  在沒有測試的情況下導入數據 ( 數據完整性)
    tm_hour=hour;//Remark From Terence:  在沒有測試的情況下導入數據 ( 數據完整性)
    tm_min=min; //Remark From Terence:  在沒有測試的情況下導入數據 (數據完整性 )
    tm_sec=sec; //Remark From Terence:  在沒有測試的情況下導入數據 (數據完整性 )
}

char* CLF_DateTime::display( char* strdisplay )
{
    strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this); //Remark From Terence:  在沒有測試strdisplay指針下使用指針 ( 指針使用安全)
    return strdisplay;
}

char* CLF_DateTime::setdisplay( char* strdisplay )
{
    tm_min+=tm_sec>=30; //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
    tm_sec=0;
    carry(tm_hour,tm_min,60);
    carry(tm_mday,tm_hour,24);
    tm_mday--;
    switch (tm_mon+1)
    {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        carry(tm_mon,tm_mday,31);
        break;
    case 2:
        carry(tm_mon,tm_mday,28+isleap());
        break;
    default:
        carry(tm_mon,tm_mday,30);
    }
    tm_mday++;
    carry(tm_year,tm_mon,12);
    return display(strdisplay);

    //Remark From Terence:  你把四捨五進變成什麼, 我說那是要可以設定進位精度的. 進位至分, 進位至時, 進位至日..............
     //Remark From Terence:  潤年 潤月 的計算已在 time 庫考慮了, 不用自己去做. 而且這樣做也不精確.
      
}

int CLF_DateTime::compare( CLF_DateTime& pb )
{
    int t=0;
    if (t=tm_year-pb.tm_year) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    if (t=tm_mon -pb.tm_mon ) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    if (t=tm_mday-pb.tm_mday) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    if (t=tm_hour-pb.tm_hour) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    if (t=tm_min -pb.tm_min ) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    if (t=tm_sec -pb.tm_sec ) //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
        goto ret; //Remark From Terence:  在goto是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性) (只在scriping language 用)
    return t; //Remark From Terence:  多點回傳, 是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性)
ret:
    return t>0?1:-1; //Remark From Terence:  在判斷式內運算是很差的語法. (可讀性, 可維護性) (若在校時使用這類語法會評係劣級)
                           //Remark From Terence:  多點回傳, 是很差的語法.它破壞了程式的邏輯結構 (可讀性, 可維護性)
}
#23
StarWing832007-12-19 17:09
首先,我应该承认。我没有判断一些函数的输入参数。改过如下:
程序代码:
CLF_DateTime::CLF_DateTime(int year/*=1900*/,int month/*=1*/,int day/*=1*/, int hour/*=0*/,int min/*=0*/,int sec/*=0*/) {
    assert(year>=TM_TIMEBASE);
    assert(month>=0&&month<=11);
    assert(day>=1&&day<=31);
    assert(hour>=0&&hour<=23);
    assert(min>=0&&min<=59);
    assert(sec>=0&&sec<=59);
    tm_year=year-TM_TIMEBASE;
    tm_mon=month-1;
    tm_mday=day;
    tm_hour=hour;
    tm_min=min;
    tm_sec=sec;
}

char* CLF_DateTime::display( char* strdisplay )  {
    assert(strdisplay!=NULL);
    strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this); //Remark From Terence:  在沒有測試strdisplay指針下使用指針 ( 指針使用安全)
    return strdisplay;
}
因为原先的代码就没有做这件事情,所以我忽略了,这是我的问题。因为是从别人的代码开始入手,我从一开始就忽略了一些必要的安全手法。平时写代码的时候我是很注意的,但是还不够。以后我会注意这方面的问题。

其次,对于闰年的判断,的确是很差的语法,不过相对于y%400==0||(y%100!=0 && y%4==0),我觉得在可读性上面是差不多的。作为一个子模块。我坚持自己的语法规则。现在的VS2005支持指向性变量类型判断。所以我抛弃了一些老的类型判断方法。(比如BOOL型写if(var),而int型写if(var!=0),指针写if(var!=NULL)等等。在不引起歧义的地方,我通常对普通变量写if(var),对指针写if(var!=NULL,这是我的风格。如果引起维护困难,我表示抱歉并改正。但是目前我并没有发现有什么不好。)

原先我的代码没有判断闰年的部分。而且我并没有得到对于setdisplay函数的任何要求。至始至终我没有看到对于整个项目的解释和要求(可以参看我前面的帖子)。我是根据单调黑白的代码提供的功能完成这个代码的。如果功能有出入不应该由我负责。

对compare的评语我不同意。首先这个函数是为了效率考虑才这么写的。原先我没有使用goto(参见我上面的帖子),使用goto是为了避免编译重复代码(这里是t>0?1:-1),而且,两个return放在后面,前面全是判断,结构化非常清晰,也十分利于调试和维护,我觉得在风格上面没有错误。goto不算洪水猛兽,正确的使用会带来效率的提升和清晰的结构化编程。对于“if (t=tm_year-pb.tm_year)”,Terence说是很差的语法。请提供一个同样高效的,并且利于维护和调试的compare,我乐于学习和进步。

其次是?:的问题。同上,对于?:我并不持否定态度。的确,滥用?:(比如嵌套使用)的确会影响代码的可读性。但是在很多情况,当使用if的时候会有重复代码的情形下,?:会提供更好的代码清晰性。我承认对代码没有做足够的优化,很多?:是可以用if代替的。但是并不是一看到?:就必须持否定的态度。事物都是有两面性的。t=sgn(m)?10:-10;绝对比if(sgn(m)!=0)t=10;else t=-10;要清晰可读得多。请参看下面我对?:的理解。

最后是carry问题。carry是私有内联函数。根据约定私有内联函数不需要判断输入参数的有效性。而且我在前面的回帖中特别强调过,carry没有做有效性检查,只是简单将多出来的时间加到上级时间里面去。如果需要检查,可以自己写代码(请参看上面的回帖),因为我并没有得到关于本程序的任何文档要求,所以这不是我的责任。

因为我仍在学习之中,如果有不妥和错误的地方请谅解。我会努力改正。但是对于不合理的东西我也应该有自己的判断。我也对糟糕的代码和难以理解维护的风格深通恶绝。但是糟糕的风格不代表仅仅是使用了goto和?:。任何事物的存在都有其合理性。我们不能一味禁止。我的理解是,对于元操作(比如上面的例子t=sgn(m)?10:-10;)使用?:可以增强代码的可读性和可维护性(你不需要改掉两个t=)。对于有固定出口的多重if代码,使用goto导向唯一出口可以增强代码的可读性和可维护性。其余的情况。我绝不会使用这两种语法。对于我的理解有误的地方,请指正。
最后,谢谢Terence耐心的评论和指责。我认识到了自己的不足,这样才能有所进步。对于Terence的劳动。我表示感激。谢谢。

[[italic] 本帖最后由 StarWing83 于 2007-12-19 17:18 编辑 [/italic]]
#24
StarWing832007-12-19 18:02
程序代码:
_VALIDATE_RETURN_ERRCODE(
    (
        ( tb->tm_mday >= 1 ) &&
        (
            // Day is in valid range for the month
            ( ( _days[ tb->tm_mon + 1 ] - _days[ tb->tm_mon ] ) >=
              tb->tm_mday ) ||
            // Special case for Feb in a leap year
            (
                ( IS_LEAP_YEAR( tb->tm_year + 1900 ) ) &&
                ( tb->tm_mon == 1 ) &&
                ( tb->tm_mday <= 29 )
            )
        )
    ),
    EINVAL
)
又及,上面是CRT对于日期(天)错误的判断,如果对assert仍然不满意,可以使用这个。
#25
StarWing832007-12-19 19:44
在吸取Terence的意见以及要求后,我的实现如下,如果还不能满足要求,请提供详细的要求文档。谢谢。
在CLF.h中:
程序代码:
#ifndef _CLF_H_
#define _CLF_H_
#include <ctime>

#define _YEAR_BASE          1900
#define _MAX_YEAR          138                  /* 2038 is the max year */

class CLF_DateTime : public tm {
public:
    enum FType {FT_SEC,FT_MIN,FT_HOUR,FT_DAY,FT_MON};
    CLF_DateTime(int year=_YEAR_BASE,int month=1,int day=1,
                 int hour=0,int min=0,int sec=0);
    ~CLF_DateTime();
    void SetTime(int year,int month,int day,int hour,int min,int sec);
    time_t GetTime();
    void Format(FType type);
    int Compare(CLF_DateTime& pb);
    char* Display(char* strdisplay);
    friend std::ostream& operator<<(std::ostream& o,CLF_DateTime& t);
};

//内联函数
inline time_t CLF_DateTime::GetTime() {
    return mktime(this);
}
#endif
在CLF.cpp中:
程序代码:
#include <iostream>
using namespace std;
#include "CLF.h"
#include <assert.h>//注:请使用自己的断言头文件

#define STR_MAX 100

//使用了CRT的方法
const char _days[]={31,29,31,30,31,30,31,31,30,31,30,31};

//如果v1超过了v3指定的值,则v2进位
inline void _format( int& v1,int& v2,int v3 ) {
    if (v1>=v3)v2++;
    v1=0;
}

CLF_DateTime::CLF_DateTime( int year/*=_YEAR_BASE*/,int month/*=1*/,int day/*=1*/,
                            int hour/*=0*/,int min/*=0*/,int sec/*=0*/ ) {
    SetTime(year,month,day,hour,min,sec);
}
CLF_DateTime::~CLF_DateTime() {
}
void CLF_DateTime::SetTime( int year/*=_YEAR_BASE*/,int month/*=1*/,int day/*=1*/,
                            int hour/*=0*/,int min/*=0*/,int sec/*=0*/ ) {
    assert(year>=_YEAR_BASE && year<=_YEAR_BASE+_MAX_YEAR);
    assert(month>=1 && month<=12);
    assert(day>=1 && day<=_days[month-1]);
    assert(hour>=0 && hour<=23);
    assert(min>=0 && min<=59);
    assert(sec>=0 && sec<=59);
    tm_year=year-_YEAR_BASE;
    tm_mon=month-1;
    tm_mday=day;
    tm_hour=hour;
    tm_min=min;
    tm_sec=sec;
}
char* CLF_DateTime::Display( char* strdisplay ) {
    assert(strdisplay!=NULL);
    strftime(strdisplay,80,"%Y-%m-%d %H:%M:%S",this);
    return strdisplay;
}
//对时间四舍五入
void CLF_DateTime::Format(FType type ) {
    for (;;) {
        _format(tm_sec,tm_min,30);
        if (type==FT_SEC)break;
        _format(tm_min,tm_hour,30);
        if (type==FT_MIN)break;
        _format(tm_hour,tm_mday,12);
        if (type==FT_HOUR)break;
        _format(tm_mday,tm_mon,_days[tm_mon]/2);
        tm_mday++;
        if (type==FT_DAY)break;
        _format(tm_mon,tm_year,6);
        break;
    }
    //规格化时间
    time_t temp=mktime(this);
    *this=(CLF_DateTime&)*localtime(&temp);
}
//比较函数,如果pb大返回-1,反之返回1,如果相等返回0
int CLF_DateTime::Compare( CLF_DateTime& pb ) {
    if (&pb==this)return 0;
    double temp=difftime(GetTime(),pb.GetTime());
    if (temp>0)return 1;
    if (temp<0)return -1;
    return 0;
}
ostream& operator<<( ostream& o,CLF_DateTime& t ) {
    char str[STR_MAX];
    return o<<t.Display(str);
}
在test.cpp中:
程序代码:
#include <iostream>
#include "CLF.h"
using namespace std;

int main(){
    CLF_DateTime t1(2000,2,29,23,59,59);
    CLF_DateTime t2(2000,2,12,11,13,12);
    //t2.Format(CLF_DateTime::FType(100));//不会出错
    t2.Format(CLF_DateTime::FT_DAY);
    cout<<t2<<endl;
    cout<<(t2);
    getchar();
}


[[italic] 本帖最后由 StarWing83 于 2007-12-20 09:37 编辑 [/italic]]
#26
中学者2007-12-20 08:29
评论得很有理嘛,但是我更佩服LS的。赖心真是好啊~~
#27
StarWing832007-12-20 09:38
程序员要有脾气,也要有修养。阿门………………
#28
中学者2007-12-20 11:02
呵呵~~~~~~~
#29
单调黑白2007-12-20 17:07
回复 27# 的帖子
兄弟 这是这个程序要完成的功能明细:
3. Reture String with specific format (reference to CTime:Format)
        e.g.

        CLF_DateTime a = CLF_DateTime(2007, 11, 4, 22, 29, 54, 9987);

        a.Format("yyyy-mm-dd HH:MM:SS");

        

        output:

        2007-11-04 22:29:54

4. Provide rounding

        CLF_DateTime a = CLF_DateTime(2007, 11, 4, 22, 29, 54, 9987);

        CLF_DateTime b = a.Rounding(MINUTE);

        

        b will be "2007-11-04 22:30:00.0000"

5. Provide Compare functions  

        CLF_DateTime a = CLF_DateTime(2007, 11, 4, 22, 29, 54, 9987);

        CLF_DateTime b = CLF_DateTime(2007, 11, 4, 22, 30, 15, 0000);

        int iresult;

 

        iresult = CLF_DateTime::Compare(a, b, MINUTE, ROUNDING);

 

        Results:

        (a>b, iresult = 1)

        (a=b, iresult = 0)

        (a<b, iresult = -1)


以下是terence再次做的评论(供大家学习参考):
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
對於programme
1. assert 只會在 Debug mode 下實現, 在Release mode 會自動除去.  你的programme 不 Release 的嗎?

2. if(y%400==0||(y%100!=0 && y%4==0)
     我沒有說這不對, 我是說 C 已做了潤年的工作
     況且, 這段 code 也不好理解, 三個月之後自己也看不懂了.
3. goto 的好與不好, 不是我們說的. 多看書吧.

    if (t=tm_year-pb.tm_year) 就是在 if 還運術, 出了bug後是很難Debug的. 以行為單位的 Debug 跟本不知是那裡出錯. 邏輯錯了更難改.

4. "t=sgn(m)?10:-10;绝对比if(sgn(m)!=0)t=10;else t=-10;要清晰可读得多"?

   //Checking the sign of m
   if(sgn(m) == 0)
   {// m is zero , 只有m是零, sgn(m)才會零
          t = -10;
   }else
   {// m is not zero
          t = 10;
   }

   你能看出上面一段的 bug 嗎? 這才叫清晰可讀, 可維護, 程式不是只是給你自己看的.
   binary file size 不會比用 t=sgn(m)?-10:10 多.
   執行速度不會比用 t=sgn(m)?-10:10 慢.
   因為他們確實用相同的機器碼.


   //Checking the sign of m
   if(sgn(m) >= 0)
   {// m is positive number or zero
          t = -10;
   }else
   {// m is negative number
          t = 10;
   }
     x ? a :b 只用在單元測試和內部測試用. (我們叫 quick and ugly)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
还有一个事 您写的这个最新的程序 我运行了 得到的结果不是需求所要的结果啊  您再看看?

谢谢!!
#30
StarWing832007-12-20 17:39
意见我接受。但是类的几个函数的声明拿来,要不然没法写。我怎么会知道构造函数最后一个参数是什么东西??
还有,你到底是包装的time.h还是MFC的CTime类?
最后,那个Compare是静态函数么?最后一个参数是什么意思?
#31
StarWing832007-12-20 17:44
顺便帮我问问terence,我最后那个代码的Format里面使用的内联_format提不提倡?不提倡该怎么改正?

还有,用断言是没关系的。我之前就说过了,如果日期错误时间是自动归结到正确的时间里面的(比如我写一月五十日,就会变成二月十九日)。所以就算是在Release版本也不会有很大的问题。不过这不是关键,关键是Debug都通不过你怎么Release??设置了断言,至少如果参数不合格Debug是绝对过不了的。应该在传参之前就检验参数的正确性,而不是在函数内去检查甚至默默地改正(隐式纠正错误,隐藏代码Dug最主要的原因!!)。除非你的这个类是作为库使用的。如果是库使用,那么也应该准备两套库,一套不加载符号的用在最终的Release版
本上,最求效率的最大化,一套加载符号,使用断言甚至为函数设置壳函数去最大化的发现代码中的Bug,这才是正确的设置方法。隐式纠正错误是绝对要不得的!!

还有一种办法是异常。但一般只是在系统出现崩溃性错误(如内存分配失败),或者可以很快控制异常链(比如在一个函数内处理本函数扔出的所有异常)。这样的参数有效性检查,绝对不需要去劳动异常这种重型武器。我宁愿我在Dubug的时候不停地弹断言失败的对话框,然后在调用方校验参数,也不愿意为一个被扔出十万八千里的异常忙的手忙脚乱(你想想,调用方连参数都不检查,他会catch异常么??)

期待类的详细说明。包括各成员函数的功能叙述和接口。不给接口也可以但是要详细合理的说明。像上面写的, a.Format("yyyy-mm-dd HH:MM:SS");这种东西。我这两天专门去熟悉了原本一窍不通的ctime库,但是还没听说strftime可以这么写的!!这个连MFC的CTime都不支持的!

我会认真去写这个类。在这几天中,我收获了很多。希望可以获得更多的这种学习的机会。但是也希望双方的合作和耐心,谢谢。

[[italic] 本帖最后由 StarWing83 于 2007-12-20 19:27 编辑 [/italic]]
#32
52316wsf2007-12-22 10:28
看晕了!
1