【难度系数】3级
【任务描述】从文件读入C程序,统计其中的代码行、注释和空行数;并统计程序中的函数个数、函数的平均行数,以及规模最大和最小的函数及其开始行号。
【功能要求】(1)用户指定要读取的C源程序文件名,从文件中读入C语言源程序。(2)分析内容包括:代码行数,注释行数,空行数,函数个数,函数平均行数,规模最大/最小函数的函数名、代码行数、开始行号。
/*源程序简单分析器问题
从文件读入C程序,统计其中的代码行、注释和空行数;并统计程序中的函数个数、函数的平均行数,
以及规模最大和最小的函数及其开始行号
思路:创建结构体来保存信息,通过读取每一行代码保存在字符串中进行判断
难点:读取每一行,文件的操作。
注意:本代码基于个人的书写习惯以及符合规定的代码习惯而编写,并不适用于全部代码风格*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
struct item//创建结构体保存程序数据
{
int code_line;//代码行
int code_annotation;//代码注释
int code_space;//空行数
int number_fun;//函数个数
int fun_line[1024];//每个函数行
int fun_ave_line;//函数平均行数
int fun_max;//最大函数编号
int fun_min;//最小函数编号
int max_fun_line;//最大函数开始行
int min_fun_line; //最小函数开始行
char max_fun_name[1024];//最大函数名
char min_fun_name[1024];//最小函数名
};
int StrFind(char *c1,char *c2);//比较两个字符串是否完全相等,这里用来增加注释数
void t_file(struct item project,int bHs);//写入文件
int main()
{
struct item project;
struct item *p;
printf("-----------------------------------------------------\n");
printf(" 计算机科学与技术五班*-----*张洪荣*--*学号12110990619\n");
printf("-----------------------------------------------------\n");
//1.创建文件流,文件指针名=fopen(文件名,使用文件方式)打开失败则返回NULL;
FILE *fp=fopen("design.c","r");
//2:检测文件是否打开成功;
if(!fp)
{
printf("打开失败!\n");
return -1; //返回异常
}
// 储存行 最大函数名 最小函数名
char s,c[1024],max_fun_name[1024],min_fun_name[1024];
// 双引号 斜引号 函数 注释 空行 代码行 每个函数的行数 最大函数 最小函数 最大函数开始行 最小函数开始行 函数平均行
int bSyh=0,bXgx=0,bHs=0,bZs=0,nKh=0,nLine=0,fun_line[2555],max_fun,min_fun, max_fun_line,min_fun_line, fun_ave_line;
// "" /* {} //
memset(fun_line,0,sizeof(int)*2555);//将数组全部定义为0
int i=0,j=0,k,flag1,flag2,flag3=0,flag4=0;
while((fgets(c,sizeof(c),fp))!=NULL)//一行一行读取,当到文件末尾时返回NULL
{
nLine++;//用于记录此时在哪一行和总行数
if(c[0]=='\0'||c[0]=='\n')//判断空行,请注意如果\t不算空行!
nKh++;
char x[3]="//";//定义注释字符串
if(StrFind(c,x)!=-1)//寻找"//"类注释
bZs++;
for(i=0;i<sizeof(c);i++)//寻找'/* '类注释
{
int j=i+1;//后一个
if(c[i]=='/'&&c[j]=='*')
bZs++;
}
if(c[0]=='{'||c[0]==' '&&c[1]=='{')//通过函数开始的花括号来判断是否为函数
{
bHs++;
flag1=nLine;//记下函数开始的行数
}
if(c[0]=='}'||c[0]==' '&&c[1]=='}')
{
flag2=nLine;//记下函数结束的行数
fun_line[j++]=flag2-flag1+2;//加2是为了将函数头保存下来
}
}
k=0;
for(j=1;j<bHs;j++)//寻找最大函数
{
if(fun_line[k]<fun_line[j])
k=j;
}
max_fun=k+1;
for(j=1;j<bHs;j++)//寻找最小函数
{
if(fun_line[k]>fun_line[j])
k=j;
}
min_fun=k+1;
int sum,ave;
for(i=0;i<bHs;i++)//记录函数平均行数
sum+=fun_line[i];
ave=sum/bHs;
rewind(fp);//返回文件头部
int nLine2=0;//标记新一个总行数
while((fgets(c,sizeof(c),fp))!=NULL)//一行一行读取,当到文件末尾时返回NULL
{
nLine2++;//用于记录此时在哪一行和总行数
if(c[0]=='{'||c[0]==' '&&c[1]=='{')//通过函数开始的花括号来判断是否为函数
{
flag3++;//标记最小函数
flag4++;//标记最大函数
}
if(flag3==min_fun)
min_fun_line=nLine2;
if(flag4==max_fun-1)
max_fun_line=nLine2;
}
rewind(fp);//返回文件头部
nLine2=0;
while((fgets(c,sizeof(c),fp))!=NULL)//一行一行读取,当到文件末尾时返回NULL
{
nLine2++;//用于记录此时在哪一行和总行数
if(nLine2==max_fun_line)
strcpy(max_fun_name,c);//记录最大函数名
if(nLine2==min_fun_line)
strcpy(min_fun_name,c);//记录最小函数名
}
fclose(fp);
printf("代码总行数=%d\n",nLine);
printf("代码总空行=%d\n",nKh);
printf("代码总注释=%d\n",bZs);
printf("代码中函数个数=%d\n",bHs);
printf("代码中函数的行数\n");
for(i=0;i<bHs;i++)
printf("%d ",fun_line[i]);
printf("\n");
printf("最大函数编号=%d 最小函数编号=%d\n",max_fun,min_fun);
printf("最大函数开始行数=%d\n",max_fun_line);
printf("最小函数开始行数=%d\n",min_fun_line);
printf("最大函数名\n");
puts(max_fun_name);
printf("最小函数名\n");
puts(min_fun_name);
printf("函数平均行=%d",ave);
project.code_line=nLine;
project.code_space=nKh;
project.code_annotation=bZs;
project.fun_ave_line=ave;
project.fun_max=max_fun;
project.fun_min=min_fun;
project.max_fun_line=max_fun_line;
project.min_fun_line=min_fun_line;
project.number_fun=bHs;
strcpy(project.max_fun_name,max_fun_name);
strcpy(project.min_fun_name,min_fun_name);
for(i=0;i<bHs;i++)
project.fun_line[i]=fun_line[i];
t_file(project,bHs);
return 0;
}
int StrFind(char *c1,char *c2)
{
int i,j,len1=strlen(c1),len2=strlen(c2);
int flag=0;//当flag为2时即为//注释
for(i=0;i<len1;i++)
{
for(j=0;j<len2;j++)
{
if(c1[i]==c2[j])
flag++;
break;
}
}
if(flag==len2)
return 0;
else
return -1;
}
void t_file(struct item project,int bHs)
{
FILE *fpWrite=fopen("E:\\C\\C_mission\\code_analysis.txt","w");
if(fpWrite==NULL)
exit(0);
int i=0;
fprintf(fpWrite,"代码总行数=%d\n",project.code_line);
fprintf(fpWrite,"代码总空行=%d\n",project.code_line);
fprintf(fpWrite,"代码总注释=%d\n",project.code_line);
fprintf(fpWrite,"代码中函数个数=%d\n",project.code_line);
fprintf(fpWrite,"函数中的行数\n");
for(i=0;i<bHs;i++)
fprintf(fpWrite,"%d ",project.fun_line[i]);
fprintf(fpWrite,"最大函数编号=%d 最小函数编号=%d\n",project.fun_max,project.fun_min);
fprintf(fpWrite,"最大函数开始行数=%d\n",project.max_fun_line);
fprintf(fpWrite,"最小函数开始行数=%d\n",project.min_fun_line);
fprintf(fpWrite,"最大函数名\n");
fputs(project.max_fun_name,fpWrite);
fprintf(fpWrite,"最小函数名\n");
fputs(project.min_fun_name,fpWrite);
fprintf(fpWrite,"函数平均行=%d",project.fun_ave_line);
fclose(fpWrite);
}
分析程序:
/*回文数问题,难度4级
思路:先转换进制,再判断是否为回文数
二进制,八进制本来的算法便要倒叙,直接看倒叙和正序是否相即可判断*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int judge_ten(long x);//判断十进制是否为回文数
int numeration_change_judge_two(long x,long *s1);//转为二进制判断是否为回文数
int numeration_change_judge_eight(long x,long *s2);//转为八进制判断是否为回文数
int numeration_change_judge_sixteen(long x,long *s3);//转为十六进制判断是否为回文数
int main()
{
char ch;
long x;
long s1[30],s2[30],s3[30];//用于存放二进制,八进制,十六进制
printf("请输入一个十进制正整数\n");
scanf("%ld",&x);
judge_ten(x);
numeration_change_judge_two(x,s1);
numeration_change_judge_eight(x,s2);
numeration_change_judge_sixteen(x,s3);
printf("是否继续使用? Y/N\n");
scanf("%s",&ch);
if(ch=='N'||ch=='n')
return 0;
else if(ch=='Y'||ch=='y')
main();//递归调用主函数
printf("-----------------------------------------------------\n");
printf(" 计算机科学与技术五班*-----*张洪荣*--*学号12110990619\n");
printf("-----------------------------------------------------\n");
return 0;
}
int judge_ten(long x)
{
long s,y=0;
s=x;
while(s>0)
{
y=y*10+s%10;
s=s/10;
}
if(y==x)
printf("十进制 %ld\n",x);
return 0;
}
int numeration_change_judge_two(long x,long *s1)
{
long i,j,flag=x,len=0;//存放十进制数
long a[30],flag2,flag3=0;//方便倒叙用的数值a[30],flag2用来在倒叙中标记len flag3用于验证是否为回文数
for(i=0;flag!=0;i++)//转为二进制
{
a[i]=flag%2;
flag/=2;
len=i;
}
flag2=len;
for(j=0;j<=len;j++)//倒叙输入在s1数值中
s1[j]=a[flag2--];
for(i=0;i<=len;i++)//判断倒叙与正序是否完全相等
{
if(s1[i]==a[i])
flag3++;
}
if(flag3==len+1)//若符合条件就输出
{
printf("二进制 ");
for(i=0;i<=len;i++)
printf("%ld",s1[i]);
printf("\n");
}
return 0;
}
int numeration_change_judge_eight(long x,long *s2)
{
long i,j,flag=x,len=0;//存放十进制数
long a[30],flag2,flag3=0;//方便倒叙用的数值a[30],flag2用来在倒叙中标记len flag3用于验证是否为回文数
for(i=0;flag!=0;i++)//转为八进制
{
a[i]=flag%8;
flag/=8;
len=i;
}
flag2=len;
for(j=0;j<=len;j++)//倒叙输入在s1数值中
s2[j]=a[flag2--];
for(i=0;i<=len;i++)//判断倒叙与正序是否完全相等
{
if(s2[i]==a[i])
flag3++;
}
if(flag3==len+1)//若符合条件就输出
{
printf("八进制 ");
for(i=0;i<=len;i++)
printf("%ld",s2[i]);
printf("\n");
}
return 0;
}
int numeration_change_judge_sixteen(long x,long *s3)
{
long i,j,flag=x,len=0;//存放十进制数
long a[30],flag2,flag3=0;//方便倒叙用的数值a[30],flag2用来在倒叙中标记len flag3用于验证是否为回文数
for(i=0;flag!=0;i++)//转为十六进制
{
a[i]=flag%16;
flag/=16;
len=i;
}
flag2=len;
for(j=0;j<=len;j++)//倒叙输入在s1数值中
s3[j]=a[flag2--];
for(i=0;i<=len;i++)//判断倒叙与正序是否完全相等
{
if(s3[i]==a[i])
flag3++;
}
if(flag3==len+1)//若符合条件就输出
{
printf("十六进制 ");
for(i=0;i<=len;i++)//十六进制的输出需要进行调整
{
if(s3[i]>9)
printf("%c",s3[i]+55);//将十六进制大于9的部分输出
if(s3[i]<=9)
printf("%d",s3[i]);
}
printf("\n");
}
return 0;
}
结果: