作者:邵瑛杰
2019.3.1
#include<stdio.h>
#include<fstream.h>
//输入
void insert(char st[100])
{
printf("请输入年月日,以xxx/xxx/xxx的格式输入:");
scanf("%s",st);
}
//文件导入的方式输入
void insert1(char st[100])
{
int f;
printf("是否要更改文件。1:要 2:不要\n");
scanf("%d",&f);
if(f==1)
{
printf("请输入年月日,以xxx/xxx/xxx的格式输入:");
ofstream outfile("in.txt",ios::out);
scanf("%s",st);
outfile<<st;
outfile.close();
}
else
{
ifstream infile("in.txt",ios::in|ios::nocreate);
infile>>st;
printf("%s",st);
infile.close();
}
}
//检查输入格式是否正确
int check1(char st[100])
{
int x=0; //标记/的个数
for(int i=0;st[i]!='\0';i++)
{
if((st[i]>'9'||st[i]<'0')&&(st[i]!='/'))
return 0;
else if(st[i]=='/')
x++;
}
if(x!=2)
return 0;
return 1;
}
//检查年月日输入是否正确
int check2(char st[100],int year,int month ,int day)
{
if(year<2010)
return 0;
if(month>12||month<1)
return 0;
if(day<1||day>31)
return 0;
if(month==2&&day>29)
return 0;
if(month==4&&day>30)
return 0;
if(month==6&&day>30)
return 0;
if(month==9&&day>30)
return 0;
if(month==11&&day>30)
return 0;
return 1;
}
//将年月日分离出来
void extract(char st[100],int &year,int &month ,int &day)
{
year=0;month=0;day=0;
int i=0;
int x=0;//标志是第几次找到/;
while(st[i]!='/')
{
year=(st[i]-'0')+year*10;
i++;
}
i++;
while(st[i]!='/')
{
month=(st[i]-'0')+month*10;
i++;
}
i++;
while(st[i]!='\0')
{
day=(st[i]-'0')+day*10;
i++;
}
}
//判断是否为闰年
int runnian(int year)
{
if((year%4==0&&year%100!=0)||year%400==0)
return 1;
else
return 0;
}
//计算本年有多少天
int getday(int year ,int month ,int day)
{
int sum=0;
switch(month)
{
case 1:sum+=0;break;
case 2:sum+=31;break;
case 3:sum+=59;break;
case 4:sum+=90;break;
case 5:sum+=120;break;
case 6:sum+=151;break;
case 7:sum+=181;break;
case 8:sum+=212;break;
case 9:sum+=243;break;
case 10:sum+=273;break;
case 11:sum+=304;break;
case 12:sum+=334;break;
}
if(runnian(year))
sum++;
sum+=day;
return sum;
}
//计算至2010.1.1有多少天
int allday(int year,int month ,int day)
{
int sum=0;
for(int i=2010;i<year;i++)
if(runnian(year))
sum+=366;
else
sum+=365;
sum+=getday(year,month,day);
return sum;
}
//判断打鱼还是晒网 且以文件的形式输出
void display(int year,int month,int day)
{
ofstream outfile("out.txt",ios::out);
int a,b;
a=allday(year,month,day);
b=a%5;
if(b>0&&b<4)
outfile<<"今天打鱼";
else
outfile<<"今天晒网.";
outfile.close();
ifstream infile("out.txt",ios::out);
char st[100];
infile>>st;
printf("%s",st);
infile.close();
}
//判断打鱼还是晒网且是手动的输出
void judge(int year ,int month ,int day)
{
int a,b;
a=allday(year,month,day);
b=a%5;
if(b>0&&b<4)
printf("今天打鱼.");
else
printf("今天晒网.");
}
int main()
{
int f1;
char st[100];
int year=0,month=0,day=0;
printf("请选择是手动输入还是文件输入 1:文件输入 2:手动输入\n");
scanf("%d",&f1);
while(1)
{
if(f1==1)//判断是手动还是文件输入
insert1(st);
else
insert(st);
while(1)
{
if(check1(st)) //检查输入格式
break;
else
{ printf("输入错误,重新输入\n");if(f1==1) insert1(st);else insert(st);}
}
extract(st,year,month,day);//分离年月日
while(1)
{
if(check2(st,year,month,day)) //检查输入的年月日
break;
else
{ printf("输入错误,重新输入\n");break;}
}
if(check1(st)&&check2(st,year,month,day))
break;
}
if(f1==1)//判断是文件还是手动
judge(year,month,day);
else
display(year,month,day);
return 0;
}
编程风格汇总:
一、在程序的版式上
1、程序块要采用缩进风格编写 ,缩进的空格数为 4 个。 原因说明: 由开发工具自动生成的代码可能不一致,但如果开发工具可以配置,则应该统一配 置缩进为 4 个空格。
2、缩进或者对齐只能使用空格键 ,不可使用 TAB 键。说明 : 使用 TAB 键需要设置 TAB 键的空格数目是 4 格。
3、相对独立的程序块之间,变量说明之后必须加空行。 说明 : 以下情况应该是用空行分开:
1)函数之间应该用空行分开;
2)变量声明应尽可能靠近第一次使用处,避免一次性声明一组没有马上使用的变量;
3)用空行将代码按照逻辑片断划分;
4)每个类声明之后应该加入空格同其他代码分开。
4、 较长的语句(>80 字符)要分成多行书写。
1)长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行 要进行适当的缩进,使排版整齐,语句可读。
2)若函数或过程中的参数较长,则要进行适当的划分。
3)循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式 要在低优先级操作符处划分新行,操作符放在新行之首。
5、不允许把多个短语句写在一行中,即一行只写一条语句。 说明: 一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅 读,并且方便于写注释。
6、if、for、do、while、case、switch、default default default 等语句自占一行 等语句自占一行,且 if、for、 do、while 等语句的执行语句部分无论多少都要加括号,等语句的执行语句部分无论多少都要加括号{}。
7、代码行之内应该留有适当的空格。说明:采用这种松散方式编写代码的目的是使代码更加清晰。
1)关键字之后要留空格。象 const、virtual、inline、case 等关键字之后至少要留一 个空格, 否则无法辨析关键字。象 if、for、while 等关键字之后应留一个空格再跟左 括号‘( ’, 以突出关键字。
2)函数名之后不要留空格, 紧跟左括号’(’ , 以与关键字区别。
3)‘( ’ 向后紧跟,‘ )’、‘ ,’、‘ ;’ 向前紧跟, 紧跟处不留空格。
4)值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“ =”、“ +=” “ >=”、“ <=”、“ +”、“ *”、“ %”、“ &&”、“ ||”、“ <<” 、“ ^” 等二元操作符 的前后应当加空格。
5)一元操作符如“ !”、“ ~”、“ ++”、“ –”、“ &”( 地址运算符) 等前后不加 空格。 7)象“[ ]”、“ .”、“ ->” 这类操作符前后不加空格。
8、 程序块的分界符(如 C/C++语言的大括号‘{’和‘}’)应各独占一行并且 应各独占一行并且 位于同一列,同时与引用它们的语句左对齐 ,同时与引用它们的语句左对齐。在函数体的开始 。在函数体的开始、类的定义、结构的定义、 枚举的定义以及 if、for、do、while、switch、case 语句中的程序都要采用如上的缩 语句中的程序都要采用如上的缩 进方式。
二、在注释上
1、源文件头部应进行注释,列出:生成日期、作者、模块目的/功能等。
2、函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回 值等。
3、注释应该和代码同时更新 ,不再有用的注释要删除。
4、注释的内容要清楚,不能有二义性。 说明: 错误的注释不但无益反而有害。
5、避免在注释中使用非常 :避免在注释中使用非常用的缩写或者术语。
6、注释的主要目的应该是解释为什么这么做,而不是正在做什么。如果从上下 文不容易看出作者的目的,说明程序的可读性本身存在比较大的问题 ,应考虑对其重构。
7、避免非必要的注释
8、注释的版式 说明:注释也需要与代码一样整齐排版 。
1)注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
2)注释与所描述内容进行同样的缩排。
3)将注释与其上面的代码用空行隔开。
4)变量、常量、宏的注释应放在其上方相邻位置或右方。
9、对于所有有物理含义的变量,如果其命名不是充分自注释的,在声明 时都必须加以注释,说明其物理含义。
10、数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释,必须加以注释。对数据结构的注释应放在其上方相邻位置 ,不可放在下面;对结构中的每个域的注释可放在此域的右方。
11、对重要变量的定义需编写注释 ,特别是全局变量,更应有较详细的注释,包 括对其功能、取值范围、以及存取时注意事项等的说明 、以及存取时注意事项等的说明。
12、分支语句(条件分支、循环语句等)需编写注释。 说明: 这些语句往往是程序实现某一特定功能的关键,对于维护人员来说,良好的注释帮助更好的理解程序,有时甚至优于看设计文档。
13、 注释不宜过多 也不能太少,源程序中有效注释量控制在 20%~30%之间。 说明: 注释是对代码的“提示”,而不是文档,不可喧宾夺主,注释太多会让人眼花缭乱。
三、在标识符命名上
1、命名尽量使用英文单词 :力求简单清楚 ,避免使用引起误解的词汇和模糊的 ,使人产生误解。 说明: 较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。
2、命名规范必须与所使用的系统风格保持一致,并在同一项目中统一 ,并在同一项目中统一。 说明
1)如在 UNIX 系统,可采用全小写加下划线的风格或大小写混排的方式,但不能使 用大小写与下划线混排的方式。
2)用作特殊标识如标识成员变量或全局变量的 m_和 g_,其后加上大小写混排的方 式是允许的。
3、常量、宏和模板名采用全大写的方式 、宏和模板名采用全大写的方式,每个单词间用下划线分隔。
4、枚举类型 enum 常量应以大写字母开头或全部大写 enum 常量应以大写字母开头或全部大写。
5、命名中若使用了特殊约定或缩写,则要有注释说明。 说明: 应该在源文件的开始之处,对文件中所使用的缩写或约定,特别是特殊的缩写,进 行必要的注释说明。
6、自己特有的命名风格,要自始至终保持一致,不可来回变化。
8、函数名以大写字母开头,采用谓-宾结构(动-名),且应反映函数执行什么 操作以及返回什么内容。
四、在程序的可读性上
1、用括号明确表达式的操作顺序 ,避免使用默认优先级。
2、不要编写太复杂、多用途的复合表达式。
3、涉及物理状态或者含有物理意义的常量 ,避免直接使用数字,必须用有意义的枚举或常量来代替。
4、禁止使用难以理解,容易产生歧义的语句。
五、在变量、结构上
1、尽量少使用全局变量,尽量去掉没必要的公共变量。 说明: 公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间 的耦合度。
2、变量被创建之后应当及时把它们初始化,以防止把未被初始化的变量当成右值使用。说明:在 C/C++中引用未经赋值的指针,经常会引起系统崩溃。
3、留心具体语言及编译器处理不同数据类型的原则及有关细节。
4、尽量减少没有必要的数据类型默认转换与强制转换。 说明: 当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化。
5、当声明用于分布式环境或不同 CPU 间通信环境的数据结构时 CPU 间通信环境的数据结构时,必须考虑机器 的字节顺序、使用的位域及字节对齐等问题 、使用的位域及字节对齐等问题。 说明:
1)在 Intel CPU 与 SPARC CPU,在处理位域及整数时,其在内存存放的“顺序”正 好相反。
2)在对齐方式下,CPU 的运行效率要快一些。
六、C++专用规范
1、在高警告级别下干净地编译。 使用编译器的最高警告级别。要求干净的(没有警告的)构建(build)并理解所有 的警告。通过修改代码来消除警告,而不是通过降低警告级别来消除。对于明确理解其 含义,确信不会造成任何问题的警告,则可以局部关闭。
2、确保资源为对象所占有,使用显式的 RAII 和智能指针 RAII 和智能指针。
3、主动使用 const,避免使用宏。 应该尽可能的使用常量而不用变量,另外在定义数值的时候,应该把 const 做为默 认的选项。
4、合理使用组合(composition)和继承 (composition)。 继承是 C++中耦合度最强的关系之一。软件工程的一条重要原则是尽量减少耦合,在 组合和继承都能均可适用的情况下,应该优先考虑使用组合。组合的意思是将一种类型 以成员变量方式嵌入相关类型中。组合有如下优点:
1)在不影响调用代码的同时也更灵活。
2)编译期绝缘性好,编译时间也能缩短。
3)代码不可预测程度降低(有些类不适合作为基类)。
5、尽可能局部地声明变量,这通常是在程序具备了足够的数据来初始化变量之后, 并紧接着首次使用该变量之前。 例外:
1)有时将变量从循环内提出到循环外是有益的。
2)由于常量不增加状态,因此本条对常量不适用。
6、尽量用异常来报告错误。与错误码相比,要尽量用异常来报告错误。对一些无法使用异常的错误,或者一些不属于错误的情况,可以用状态码(status code,例如:返回码,errno)来报告。如果不可能或不需要从错误中恢复,那么可以使用其它方法,比如正常或非正常地终止程序。在 C++中,和用错误码来报告错误相比,用异常来报告错误具有许多明显的优势,所有这些都使得编出来的代码更健壮:
1)程序员不能无视异常:错误码的最糟糕的缺点就是在默认情况下它们会被忽略; 即使是给予错误码微不足道的关注,都必须显式地编写代码,以接受错误并做出反应。程序员因为偶然(或因为懒惰)而忘记关注错误码是很平常的事。这使得代码复查变得更困难。
2)异常会自动传递:默认情况下错误码不会跨作用域传递;为了把一个低层的错误 码通知高层的调用函数,程序员必须在中间层的代码中显式地手工编写代码以传递 该错误。异常会自动地跨作用域传递,直到被处理为止。
3)异常处理从主控制流中去除了错误处理及恢复:错误码的检测及处理,一旦要写的话,就必须夹杂在主控制流中(并使之变得难以理解)。这使得主控制流以及错误 处理的代码都更难以理解和维护。异常处理很自然地把错误检测及恢复移到醒目的 catch 代码块中,即它使错误处理既醒目,又易于使用,而不是纠缠在主控制流中。
七、在 可测性上
1、在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。
2、在同一项目组或产品组内,调测打印出的信息串的格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。
3、编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)。
4、在进行集成测试/系统联调之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。
5、使用断言来发现软件问题,提高代码可测性。
6、用断言来检查程序正常运行时不应发生但在调测时有可能发生的非法情况。
7、不能用断言来检查最终产品肯定会出现且必须处理的错误情况。
8、对较复杂的断言加上明确的注释
9、用断言确认函数的参数。
10、用断言保证没有定义的特性或功能不被使用。
11、用断言对程序开发环境(OS/Compiler/Hardware)的假设进行检查。
12、正式软件产品中应把断言及其它调测代码去掉(即把有关的调测开关关掉)。
13、在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响。
14、用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。
15、软件的DEBUG版本和发行版本应该统一维护,不允许分家,并且要时刻注意保证两个版本在实现功能上的一致性。
16、在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。
17、调测开关应分为不同级别和类型。
18、编写防错程序,然后在处理错误之后可用断言宣布发生错误。
八、在 代码编辑、编译、审查 上
1、打开编译器的所有告警开关对程序进行编译。
2、在产品软件(项目组)中,要统一编译开关选项。
3、通过代码走读及审查方式对代码进行检查。
4、测试部测试产品之前,应对代码进行抽查及评审。
5、编写代码时要注意随时保存,并定期备份,防止由于断电、硬盘损坏等原因造成代码丢失。
6、同产品软件(项目组)内,最好使用相同的编辑器,并使用相同的设置选项。
7、要小心地使用编辑器提供的块拷贝功能编程。
8、合理地设计软件系统目录,方便开发人员使用。
9、某些语句经编译后产生告警,但如果你认为它是正确的,那么应通过某种手段去掉告警信息。
10、使用代码检查工具(如C语言用PC-Lint)对源程序检查。
11、使用软件工具(如 LogiSCOPE)进行代码审查。
九、在代码测试及维护上
1、单元测试要求至少达到语句覆盖。
2、单元测试开始要跟踪每一条语句,并观察数据流及变量的变化。
3、清理、整理或优化后的代码要经过审查及测试。
4、代码版本升级要经过严格测试。
5、使用工具软件对代码版本进行维护。
6、正式版本上软件的任何修改都应有详细的文档记录。
7、发现错误立即修改,并且要记录下来。
8、关键的代码在汇编级跟踪。
9、仔细设计并分析测试用例,使测试用例覆盖尽可能多的情况,以提高测试用例的效率。
10、尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试。
11、仔细测试代码处理数据、变量的边界情况。
12、保留测试信息,以便分析、总结经验及进行更充分的测试。
13、不应通过“试”来解决问题,应寻找问题的根本原因。
14、对自动消失的错误进行分析,搞清楚错误是如何消失的。
15、修改错误不仅要治表,更要治本。
16、测试时应设法使很少发生的事件经常发生。
17、明确模块或函数处理哪些事件,并使它们经常发生。
18、 坚持在编码阶段就对代码进行彻底的单元测试,不要等以后的测试工作来发现问题。
19、去除代码运行的随机性(如去掉无用的数据、代码及尽可能防止并注意函数中的“内部寄存器”等),让函数运行的结果可预测,并使出现的错误可再现。
**我的风格总结:**
姓名
时间
编译器
代码加注释
心得:
学会了怎么使用c++的文件输入和输出。
学会了怎么使用Visio画流程图,还有程序的调试,我进行了好几次调试,分别找各种bug,
刚开始是只判断了格式,后来加了一个day的判断,
保证月的天数不超。后来又改了一些文件输入的格式,各种输入的方法,
使程序更人性化。