c语言学习进阶-C语言程序稳定性测试

C语言程序程序稳定性测试

(1)设计一个自动数据生成程序,能自动生成指定行数的随机整数并写入到一个文件当中,随机整数的范围可以被控制,例如控制在0 到100 间,这个程序的操作命令行参数如:d:>intgen.exe data1.txt 0 100 7777, 程序意味着产生0-100 之间的随机数共7777 个,并写入输出文件data1.txt中, 每行1 个数据, 共7777 行,程序执行完毕以后打开data1.txt 观察一下数据以及格式是否正确;
在C 语言中,rand() 可以用来产生随机数,但是这不是真正意义上的随机数,是一个伪随机数,我们称它为种子,他是以某一个递推公式推出来的一系列数,当这个数很大的时候,就符
合正态分布,当计算机开机后,这个种子的值就定了,非你破坏了系统,为改变这给种子的值,C 提供了srand() 函数,它的原形是void srand(inta)。rand 产生的随机数从0 到rand-max,
rand-max 定义在stdlib.h,其值至少为32767. 在调用此函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,rand() 在调用时会自动设随机数种子为1,一般用for语句来设置种子的个数。从x 到y,有y-x+1 个随机数,产生从x 到y 的数只需要下面代码中第25 行代码k=rand()%(y-x+1)+x;。
自动生成7777 个0-100 间的随机数代码intgen.c 如下:

#include <stdlib.h>
#include <stdio.h>
#include <time.h> //设置时钟种子
int main(int argc,char*argv[])
{
int i;
int k;//存放随机数
int a;//产生随机数个数
int x;//随机数区间起点
int y;//随机数区间终点
sscanf(argv[2],"%d",&x); //argv[]是字符串格式,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。从一个字符串中读进与指定格式相符的数据
sscanf(argv[3],"%d",&y);
sscanf(argv[4],"%d",&a);
FILE*fp2;//文件指针表示的写入流
if (argc!=5)
	{
		printf("参数输入不正确!");	
		printf("提示:命令 输出文件 随机数区间起点 随机数区间终点 随机数个数");
	}
srand( (unsigned)time( NULL ) );
	{
		fp2=fopen(argv[1],"w");//打开并写入参数argv[1]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化	
		for( i = 0; i < a; i++ )
	   {
			k=rand()%(y-x+1)+x;
			//printf( "产生随机数:%d\n", k);
			fprintf(fp2,"%d\n",k);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
	   } 
	}	
fclose(fp2);	
if (fclose(fp2)!=0);
	{
		printf("文件 %s\n 关闭错误",argv[1]);
	}
}
//验证:
//gcc intgen.c -o intgen.exe
//intgen.exe data1.txt 0 100 7777

生成随机数运行结果如下图写完数据后已经采用fclose(fp2) 关闭写入流,但是提示文件未关闭成功。
在这里插入图片描述
(2)将生成的数据文件data1.txt 作为p.exe 的输入数据文件执行计算,例如:d:>p.exe data1.txt data2.txt 7,这样将输入数据的7 次方计算结果输出到data2.txt;
代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include <ctype.h> 
#include <stdlib.h> 
int main(int argc,char*argv[])
{
	FILE*fp1,*fp2;//文件指针表示的两个流
	if (argc!=4)
	{
		printf("参数输入不正确!");	
		printf("提示:命令 输入文件 输出文件 幂次");
	}
		if(fp1==NULL)
	{
		printf("输入文件打开失败");
		return 0;
	}
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	int a,c, i=0,j=0;
	int lines = 0; //行数
	int temp;//用于求幂
	float x,y;//x为输入的数字,y为输出的数字
	//fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
	
	//检测行数//
	while((c = fgetc(fp1))!= EOF)
	{
		if(c=='\n') 
		lines++; 
	} 
	lines = lines+1; 
	fclose(fp1);
    
	int data[ lines ]; //存放运算结果 
	char sdigit [ lines*2]; //检测格式数组

	//判断文件格式/	
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
	{
		fscanf(fp1,"%s",sdigit);
		for(j=0;sdigit[j];++j)
		{
			if(isdigit(sdigit[j]))
			{
			//x=sdigit[j];
			//y=pow(x,3);
			//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
			}//返1
			else
			{
				printf("文件中有字母或汉字");
			    //fprintf(fp2,"%c\n",sdigit[j]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容	
			    exit(0);
			}
		
		}
	}
	fclose(fp1);
	//写入文件/
	//float x,y;//x为输入的数字,y为输出的数字
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
	while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
	{
		fscanf(fp1,"%f\n",&x);//格式化的文件输入,读入并且赋值给实际参数,从第一个参数fp1指定的流中读入内容
		//scanf("%d",&x);//总是从标准输入流stdin中读入内容
		//y=x*x*x;//计算x的三次方
		sscanf(argv[3],"%d",&temp); //argv[3]是字符串格式,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。从一个字符串中读进与指定格式相符的数据
		printf("temp:%d",temp);
		data[i]=pow(x,temp);
		printf("data[%d]:%d",i,data[i]);
		//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
		//prinf("%d",&y);//总是从标准输入流stdin中输出内容
	    fprintf(fp2,"%d\n",data[i]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
		i++;
	}
	fclose(fp1);
	fclose(fp2);
	return 0;
	if (fclose(fp1)!=0);//关闭文件成功关闭则返回值为0
	{
		printf("文件 %s\n 关闭错误",argv[1]);
	}
	if (fclose(fp2)!=0);
	{
		printf("文件 %s\n 关闭错误",argv[2]);
	}
}

将生成的0-100 的随机数进行7 次方的计算时输出文件如图:
在这里插入图片描述
发现所有输出结果相同,猜测是计算后数据溢出,采用整型变量int 存储其取值范围为-32768 到32767,超出这个范
围就不能储存,在编译解决一些实际问题时,可定义一些无符号数据类型节省数据空间即可将 int 型改为unsigned int, 此时存储范围为0 到65535。或者实用长型long int(简写为long) 替代 int,甚至是unsigned long int、unsigned long long int 使数据空间更大。k 考虑到100 的7 次方数值范围为10 的14 次方化为二进制约为2 的47 次方即需要至少47 位二进制表示,故要选用
unsigned long int 或long long int 来定义数据类型,也可以采用double 型(比特数为64 位)。
通过代码调试证明了上图乱码原因是数据类型定义不正确造成的,改进后计算结果如下图:
在这里插入图片描述
(3)将输入文件数据扩展到10 万行, 测试p.exe 是否还能正确的执行计算并输出结果;
执行intgen.exe data1.txt 0 100 100000 命令,产生10 万行的随机数据的文件data1.tex 如下图:
在这里插入图片描述
将生成的10 万行0-100 的随机数测 p.exe,进行7 次方的计算时输出文件如下图:在这里插入图片描述
(4)修改计算程序p.exe 的源代码, 加入执行时间的计算,从而能够输出程序的计算时间, 针对输入数据文件100 行,1000 行,1 万行,10 万行等得出程序计算的消耗时间结果;
C 语言程序的运行时间,一般采用两种方法,一种是精确到毫秒时间,一种是精确到微妙时间,精确到微秒时间原理是CPU 次数除以频率,用到函数包#includewindows.h<>函数包,精确到毫秒时间用到函数包#includetime.h<>函数包里的clock() 函数,修改计算程序p.exe 的源代码,精确到微秒级编译生成p4.exe,精确到毫秒秒级编译生成p5.exe,为了方便下题绘图,分别将p4.exe 与p5.exe 不同行数的数据运行时间写入time1.txt 与time2.txt 中。
在p.c 中加入执行时间计算函数,对程序运行时间进行计时(p4.c 中的9-16 行、83-86 行),以及创建了一个运行时间的输入流,将每次运行时间输入到time1.txt 中(p4.c 中的86-87 行),微秒级编译代码p4.c 如下所示:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include <ctype.h> 
#include <stdlib.h> 
#include <Windows.h>
int main(int argc,char*argv[])
{
	double run_time;
	LARGE_INTEGER time_start;	//开始时间
	LARGE_INTEGER time_over;	//结束时间
	double dqFreq;		//计时器频率
	LARGE_INTEGER f;	//计时器频率
	QueryPerformanceFrequency(&f);
	dqFreq=(double)f.QuadPart;
	QueryPerformanceCounter(&time_start);	//计时开始
		FILE*fp1,*fp2,*fp3;//文件指针表示的两个流
		if (argc!=4)
		{
			printf("参数输入不正确!");	
			printf("提示:命令 输入文件 输出文件 幂次");
		}
			if(fp1==NULL)
		{
			printf("输入文件打开失败");
			return 0;
		}
		fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
		int a,c, i=0,j=0;
		int lines = 0; //行数
		int temp;//用于求幂
		float x,y;//x为输入的数字,y为输出的数字
		//fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
		//检测行数//
		while((c = fgetc(fp1))!= EOF)
		{
			if(c=='\n') 
			lines++; 
		} 
		lines = lines+1; 
		fclose(fp1);
		double data[ lines ]; //存放运算结果 
		char sdigit [ lines*2]; //检测格式数组
		//判断文件格式/	
		fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
		while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
		{
			fscanf(fp1,"%s",sdigit);
			for(j=0;sdigit[j];++j)
			{
				if(isdigit(sdigit[j]))
				{
				//x=sdigit[j];
				//y=pow(x,3);
				//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
				}//返1
				else
				{
					printf("文件中有字母或汉字");
					//fprintf(fp2,"%c\n",sdigit[j]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容	
					exit(0);
				}
			}
		}
		fclose(fp1);
		//写入文件/
		//float x,y;//x为输入的数字,y为输出的数字
		fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
		fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
		while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
		{
			fscanf(fp1,"%f\n",&x);//格式化的文件输入,读入并且赋值给实际参数,从第一个参数fp1指定的流中读入内容
			//scanf("%d",&x);//总是从标准输入流stdin中读入内容
			//y=x*x*x;//计算x的三次方
			sscanf(argv[3],"%d",&temp); //argv[3]是字符串格式,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。从一个字符串中读进与指定格式相符的数据
			data[i]=pow(x,temp);
			//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
			//prinf("%d",&y);//总是从标准输入流stdin中输出内容
			fprintf(fp2,"%f\n",data[i]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
			i++;
		}
		QueryPerformanceCounter(&time_over);	//计时结束
		run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq;
		//乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒
		printf("\nrun_time:%fus\n",run_time);
		fp3=fopen("time1.txt","a");//打开并写入time1.txt输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
		fprintf(fp3,"%f\n",run_time);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
		return 0;
		fclose(fp1);
		fclose(fp2);
		fclose(fp3);
		return 0;
		if (fclose(fp1)!=0);//关闭文件成功关闭则返回值为0
		{
			printf("文件 %s 关闭错误",argv[1]);
		}
		if (fclose(fp2)!=0);
		{
			printf("文件 %s关闭错误",argv[2]);
		}
		if (fclose(fp3)!=0);
		{
			printf("文件time1.txt关闭错误");
		}
}
/
//验证
//gcc p4.c -o p4.exe
//gcc intgen.c -o intgen.exe
//intgen.exe data1.txt 0 100 100
//p4.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 1000
//p4.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 10000
//p4.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 100000
//p4.exe data1.txt data2.txt 7

对代码进行验证一,产生100 行随机数据,计算7 次方后输出运行时间如图:
在这里插入图片描述
对代码进行验证二,产生1000 行随机数据,计算7 次方后输出运行时间如图:
在这里插入图片描述
对代码进行验证三,产生1 万行随机数据,计算7 次方后输出运行时间如图:
在这里插入图片描述
对代码进行验证四,产生1 万行随机数据,计算7 次方后输出运行时间如图:
在这里插入图片描述
输出的time1.txt 文件如图:
在这里插入图片描述

对10 万行的数据反复执行发现每次时间有很大偏差,产生这种结果的原因是程序调用系统
CPU 并且现在CPU 支持动态调频,所以运行时间也有所不同。
在这里插入图片描述
在p.c 中加入执行时间计算函数clock();,对程序运行时间进行计时(p5.c 中的9-16 行、83-86 行),以及创建了一个运行时间的输入流,将每次运行时间输入到time2.txt 中(p5.c 中的86-87 行),微秒级编译代码p5.c 如下所示:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include <ctype.h> 
#include <stdlib.h> //用到rand()函数
#include<time.h>   //用到clock()函数
int main(int argc,char*argv[])
{
	double begintime,endtime,run_time;
	begintime=clock();	//计时开始
	FILE*fp1,*fp2,*fp3;//文件指针表示的两个流
	if (argc!=4)
	{
		printf("参数输入不正确!");	
		printf("提示:命令 输入文件 输出文件 幂次");
	}
		if(fp1==NULL)
	{
		printf("输入文件打开失败");
		return 0;
	}
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	int a,c, i=0,j=0;
	int lines = 0; //行数
	int temp;//用于求幂
	float x,y;//x为输入的数字,y为输出的数字
	//fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
	//检测行数//
	while((c = fgetc(fp1))!= EOF)
	{
		if(c=='\n') 
		lines++; 
	} 
	lines = lines+1; 
	fclose(fp1);
	double data[ lines ]; //存放运算结果 
	char sdigit [ lines*2]; //检测格式数组
	//判断文件格式/	
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
	{
		fscanf(fp1,"%s",sdigit);
		for(j=0;sdigit[j];++j)
		{
			if(isdigit(sdigit[j]))
			{
			//x=sdigit[j];
			//y=pow(x,3);
			//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
			}//返1
			else
			{
				printf("文件中有字母或汉字");
			    //fprintf(fp2,"%c\n",sdigit[j]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容	
			    exit(0);
			}
		}
	}
	fclose(fp1);
	//写入文件/
	//float x,y;//x为输入的数字,y为输出的数字
	fp1=fopen(argv[1],"r");//打开并读取参数argv[1]对应的输入文件
	fp2=fopen(argv[2],"w");//打开并写入参数argv[2]对应的输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
	while(!feof(fp1))//feof本身是一个非负的整型常量,表明以达到文件末尾
	{
		fscanf(fp1,"%f\n",&x);//格式化的文件输入,读入并且赋值给实际参数,从第一个参数fp1指定的流中读入内容
		//scanf("%d",&x);//总是从标准输入流stdin中读入内容
		//y=x*x*x;//计算x的三次方
		sscanf(argv[3],"%d",&temp); //argv[3]是字符串格式,sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。从一个字符串中读进与指定格式相符的数据
		data[i]=pow(x,temp);
		//fprintf(fp2,"%f\n",y);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
		//prinf("%d",&y);//总是从标准输入流stdin中输出内容
	    fprintf(fp2,"%f\n",data[i]);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
		i++;
	}
	endtime = clock();	//计时结束
	run_time=endtime-begintime;
	printf("\nrun_time::%fms\n", run_time);
	fp3=fopen("time2.txt","a");//打开并写入time2.txt输出文件,与“w”相比“a”也可以写入文件,但是写之前文件不进行格式化
	fprintf(fp3,"%f\n",run_time);//格式化的文件输出,读入并且赋值给实际参数,从第一个参数fp2指定的流中输出内容
	return 0;
	fclose(fp1);
	fclose(fp2);
	fclose(fp3);
	return 0;
	if (fclose(fp1)!=0);//关闭文件成功关闭则返回值为0
	{
		printf("文件 %s\n 关闭错误",argv[1]);
	}
	if (fclose(fp2)!=0);
	{
		printf("文件 %s\n 关闭错误",argv[2]);
	}
	if (fclose(fp3)!=0);
	{
		printf("文件time1.txt关闭错误");
	}
}
/
//验证
//gcc p5.c -o p5.exe
//gcc intgen.c -o intgen.exe
//intgen.exe data1.txt 0 100 100
//p5.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 1000
//p5.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 10000
//p5.exe data1.txt data2.txt 7
//intgen.exe data1.txt 0 100 100000
//p5.exe data1.txt data2.txt 7

对代码进行和微秒级相同的验证,计算7 次方后输出运行时间如图:
在这里插入图片描述
对比time1.txt 与time2.txt 的计时数据发现,当程序计算复杂度越低时,毫秒级的计时程序计时误差越大,并且程序计算复杂度小到一定程度时,输出计算时间为0。
毫秒级计时随机数据的7 次方运行时间如图:
在这里插入图片描述
毫秒级计时随机低复杂度计算运行时间如图:

在这里插入图片描述
采用matlab 绘制运行时间图像,代码及绘制图像如图:
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值