实验五 Linux环境下系统函数的应用
学号:6130116217
专业班级:计算机科学与技术165班
课程名称:Linux程序设计实验
一、实验项目名称
Linux环境下系统函数的应用
二、实验目的
1.掌握数学函数库的使用
2.掌握随机数生成的方法
3.掌握时间与日期函数的使用
4.掌握内存分配函数的使用
5.掌握排序函数的使用
三、实验基本原理
Linux环境下的系统函数
四、主要仪器设备及耗材
硬件: PC机;
软件:Windows OS,VMware,Fedora10.0或其他Linux发行版。
五、实验步骤
1. 数学函数库
设计一个正余弦计算器,程序运行时,询问用户想计算正弦、余弦还是两者均需要计算,输入的是角度还是弧度?确定后,返回相关结果。
代码如下:
#include<stdio.h>
#include<math.h>
int n;
double k;
double pi=acos(-1.0);
int main()
{
while(1)
{
printf("which do you want to calculate: \n");
printf("1:sin \n");
printf("2:cos \n");
printf("3:sin and cos \n");
printf("4:exit \n");
scanf("%d",&n);
switch(n)
{
case 1:
printf("which do you want to input: \n");
printf("1:angle \n");
printf("2:radian \n");
scanf("%d",&n);
if(n==1)
{
printf("please input the angle: \n");
scanf("%lf",&k);
printf("sin(%lf)=%lf\n",k,sin(k/180*pi));
}
else if(n==2)
{
printf("please input the radian: \n");
scanf("%lf",&k);
printf("sin(%lf)=%lf\n",k,sin(k));
}
break;
case 2:
printf("which do you want to input: \n");
printf("1:angle \n");
printf("2:radian \n");
scanf("%d",&n);
if(n==1)
{
printf("please input the angle: \n");
scanf("%lf",&k);
printf("cos(%lf)=%lf\n",k,cos(k/180*pi));
}
else if(n==2)
{
printf("please input the radian: \n");
scanf("%lf",&k);
printf("cos(%lf)=%lf\n",k,cos(k));
}
break;
case 3:
printf("which do you want to input: \n");
printf("1:angle \n");
printf("2:radian \n");
scanf("%d",&n);
if(n==1)
{
printf("please input the angle: \n");
scanf("%lf",&k);
printf("sin(%lf)=%lf\n",k,sin(k/180*pi));
printf("cos(%lf)=%lf\n",k,cos(k/180*pi));
}
else if(n==2)
{
printf("please input the radian: \n");
scanf("%lf",&k);
printf("cos(%lf)=%lf\n",k,cos(k));
}
break;
case 3:
printf("which do you want to input: \n");
printf("1:angle \n");
printf("2:radian \n");
scanf("%d",&n);
if(n==1)
{
printf("please input the angle: \n");
scanf("%lf",&k);
printf("sin(%lf)=%lf\n",k,sin(k/180*pi));
printf("cos(%lf)=%lf\n",k,cos(k/180*pi));
}
else if(n==2)
{
printf("please input the radian: \n");
scanf("%lf",&k);
printf("sin(%lf)=%lf\n",k,sin(k));
printf("cos(%lf)=%lf\n",k,cos(k));
}
break;
case 4:
return 0;
}
}
return 0;
}
编译
当使用gcc编译器编译含数学函数的C程序时,会出现undefined reference to `sin’错误.这种错误一般是由于缺少库造成的。-lm
执行
2. 随机数生成方法
(1)编写一个猜数游戏程序,先产生一个1到1000之间的随机整数,要求用户输入一个数,程序提示猜大了、猜小了和恭喜你猜对了,直到猜中,退出程序。
vim 2.c
#include<stdio.h>
#include<stdlib.h>
int n,k;
int main()
{
srand((int)time(0));
n=1+1000.0*rand()/(RAND_MAX+1.0);
// printf("n=%d\n",n);
k=-1;
while(k!=n)
{
if(k!=-1)
{
if(k<n)
printf("it is too small\n");
else
printf("it is too big\n");
}
printf("please input the number you guess:\n");
scanf("%d",&k);
}
printf("the number is %d,congratulations on your correct answer",n);
return 0;
}
编译
运行
(2)修改程序,限定猜数次数,则猜数过程中达到猜数次数还未猜中时,提示猜数失败而退出。
vim 22.c
#include<stdlib.h>
int n,k,count;
int main()
{
srand((int)time(0));
n=1+1000.0*rand()/(RAND_MAX+1.0);
printf("n=%d\n",n);
k=-1;
while(k!=n)
{
if(k!=-1)
{
if(k<n)
printf("it is too small\n");
else
printf("it is too big\n");
}
if(count++==5)
{
printf("sorry,you've run out of guesses and you failed.\n");
break;
}
printf("number of attemtps: %d ,5 times altogether.\n",count);
scanf("%d",&k);
}
if(count<=5)
printf("the number is %d,congratulations on your correct answer\n",n);
else
printf("the number is %d,I'm sorry you failed.\n",n);
return 0;
}
编译
运行
猜数成功
猜数失败
3. 时间与日期函数
(1)编写程序显示当前格林尼治时间以及北京时间
vim 3.c
#include <time.h>
int main()
{
time_t timep; /* 时间结构体变量 */
char *wday[]= {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
struct tm *p;
time (&timep); /*取得当前的时间*/
printf("current GMT: \n");
printf("%s\n",asctime(gmtime(&timep)));/*将时间和日期以字符串格式表示*/
p=localtime(&timep); /*取得当地时间并按真实世界的时间日期来表示*/
printf("current Beijing time: \n");
printf ("%d-%d-%d ",(1900+p->tm_year), (1+p->tm_mon), p->tm_mday);
printf("%s %d:%d:%d\n",wday[p->tm_wday],p->tm_hour,p->tm_min,p->tm_sec);
return 0;
}
编译
运行
(2)调试课本例4.8
#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
#include<unistd.h>
#ifdef __unix__
# include <unistd.h>
#elif defined _WIN32
# include <windows.h>
#define sleep(x) Sleep(1000 * (x))
#endif
int main()
{
long int begin,sec,stop;
struct timeval tv1, tv2;
struct timezone tz;
char tmp;
begin=0;
stop=0;
sec=0;
system("clear");
printf("计时器程序(单位s)\n");
printf("输入b(begin)计时器开始计时\n");
printf("输入w(watch)查看已经累计时间\n");
printf("输入r(rest)重新开始计时\n");
printf("输入s(stop)暂停计时器\n");
printf("输入e(end)结束计时器\n");
while(1)
{
scanf("%c",&tmp);
if(tmp=='b')
{
if(begin==1&&stop==0)
printf("计时器已经启动!\n");
if(begin==0&&stop==0)
{
printf("计时器启动\n");
gettimeofday(&tv1,&tz);
sec=0;
begin=1;
}
if(stop==1)
{
gettimeofday(&tv1,&tz);
stop=0;
printf("暂停结束!\n");
}
}
if(tmp=='w')
{
if(stop==0)
{
gettimeofday(&tv2,&tz);
printf("已经计时%ld 秒\n",sec+tv2.tv_sec-tv1.tv_sec);
}
if(stop==1)
printf("已经计时%ld 秒\n",sec);
}
if(tmp=='s')
{
if(stop==1)
{
printf("计时已经暂停!\n");
}
if(stop==0)
{
gettimeofday(&tv2,&tz);
sec=sec+tv2.tv_sec-tv1.tv_sec;
printf("计时暂停,已经计时%ld 秒\n",sec);
stop=1;
}
}
if(tmp=='r')
{
gettimeofday(&tv2,&tz);
printf("已经计时%ld 秒\n",sec+tv2.tv_sec-tv1.tv_sec);
printf("计时器在5 秒后被重置!\n");
sleep(5);
begin=0;
sec=0;
stop=0;
system("clear");
printf("计时器程序(单位s)\n");
printf("输入b(begin)计时器开始计时\n");
printf("输入w(watch)查看已经累计时间\n");
printf("输入r(rest)重新开始计时\n");
printf("输入s(stop)暂停计时器\n");
printf("输入e(end)结束计时器\n");
}
if(tmp=='e')
break;
}
return 0;
}
编译
运行
4. 内存分配
编写程序,动态申请一个数组,数组元素个数为10个,数组元素类型为int。程序运行时,提示用户输入10个数,接下来输出该数组的最大值与最小值。
注意:(1)比较malloc和calloc的区别
(2)在程序最后要释放动态申请的内存空间
答:malloc它允许从空间内存池中分配内存,malloc()的参数是一个指定所需字节数的整数.例如:P=(int*)malloc(nsizeof(int));colloc与malloc类似,但是主要的区别是存储在已分配的内存空间中的值默认为0,使用malloc时,已分配的内存中可以是任意的值.colloc需要两个参数,第一个是需要分配内存的变量的个数,第二个是每个变量的大小.
例如:P=(int)colloc(n,colloc(int));
①使用malloc
#include<stdio.h>
#include<stdlib.h>
int *a;
int max=-0x3f3f3f3f;
int min=0x3f3f3f3f;
int main()
{
a=(int *)malloc(sizeof(int)*10);
printf("请输入10个整数\n");
for(int i=0; i<10; ++i)
{
scanf("%d",&a[i]);
if(a[i]>max)
max=a[i];
if(a[i]<min)
min=a[i];
}
free(a);
a=NULL;
printf("最大值: %d\n",max);
printf("最小: %d\n",min);
return 0;
}
编译运行
②使用calloc
#include<stdio.h>
#include<stdlib.h>
int *a;
int max=-0x3f3f3f3f;
int min=0x3f3f3f3f;
int main()
{
a=(int*)calloc(sizeof(int),10);
printf("请输入10个整数\n");
for(int i=0; i<10; ++i)
{
scanf("%d",&a[i]);
if(a[i]>max)
max=a[i];
if(a[i]<min)
min=a[i];
}
free(a);
printf("最大值: %d\n",max);
printf("最小: %d\n",min);
return 0;
}
编译运行
5.排序算法
编写程序,从附加文件File1.txt中读数据,每一行为一个字符串,对所有字符串从小到大进行排序,排序结果保存到文件File1-result.txt中。要求:
(1)分别应用快速排序和冒泡排序算法进行排序,并且用getimeofday函数比较两个算法所需时间。
(2)比较不带缓存以及带缓存的文件读写方法
①不带缓存 快速排序
vim 5.c
//不带缓存 快速排序
#include<stdio.h>
#include<string.h>
#include<sys/time.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
int compare( char *version1, char *version2);
int part(char a[255][255],int left,int right);
void quicksort(char a[255][255],int left,int right);
char buf[255][255];
int count,p;
struct timeval beg,end;
int fp;
char temp[10];
int main() {
gettimeofday(&beg,NULL);
if( (fp = open("File1.txt",O_RDONLY))<0) {
printf("打开文件File1.txt出错");
exit(0);
}
printf("排序前:\n");
while (read(fp, temp, 1) >0) {
buf[count][p]=temp[0];
if(buf[count][p]!='\n') {
p++;
} else {
printf("%s", buf[count]);
p=0;
count++;
}
}
printf("单词个数: %d\n\n",count);
close(fp);
//快速排序
quicksort(buf,0,count-1);
if( (fp = open("File1-result.txt",O_WRONLY))<0) {
printf("打开文件File1-result.txt出错");
exit(0);
}
printf("排序后:\n");
for(int i=0; i<count; i++) {
printf("%s",buf[i]);
p=0;
while(buf[count][p]!='\0')
write(fp,&buf[count][p],1);
}
printf("单词个数: %d\n\n",count);
close(fp);
gettimeofday(&end,NULL);
int us= 1000000 * (end.tv_sec-beg.tv_sec)+ end.tv_usec-beg.tv_usec;
printf(" %d ms\n\n",us/1000);
}
int part(char a[255][255],int left,int right) {
char temp[255];
strcpy(temp,a[left]);
while(left<right) {
while(left<right&&compare(a[right],temp)>0)
right--;
strcpy(a[left],a[right]);
while(left<right&&compare(a[left],temp)<=0)
left++;
strcpy(a[right],a[left]);
}
strcpy(a[left],temp);
return left;
}
void quicksort(char a[255][255],int left,int right) {
if(left<right) {
int pos=part(a,left,right);
quicksort(a,left,pos-1);
quicksort(a,pos+1,right);
}
}
int compare( char *version1, char *version2) {
char* ver1 = version1;
char* ver2 = version2;
//入参判断
if(NULL == ver1 || NULL == ver2) {
if (NULL != ver1) {
return -3;
}
if (NULL != ver2) {
return -2;
}
return -1;
}
while ((*ver1 != '\0') && !(*(ver1) - *(ver2))) {
ver1++, ver2++;
}
if (*(ver1) == '\0' && *(ver2) == '\0') {
return 0;
} else {
if (*(ver1)-*(ver2)>0) {
return 1;
} else {
return -1;
}
}
}
编译
运行
②带缓存 冒泡排序
vim 55.c
//带缓存 冒泡
#include<stdio.h>
#include<string.h>
#include<sys/time.h>
#include<unistd.h>
#include<stdlib.h>
int compare( char *version1, char *version2);
char buf[255][255];
int count;
struct timeval beg,end;
FILE *fp;
int main() {
gettimeofday(&beg,NULL);
if( (fp = fopen("File1.txt","r+"))==NULL) {
printf("打开文件File1.txt出错");
exit(0);
}
printf("排序前:\n");
while(!feof(fp)) {
fgets(buf[count],255,fp);
printf("%s",buf[count++]);
}
printf("单词个数: %d\n\n",count-1);
fclose(fp);
//冒泡排序
for(int i=0; i<count-1; ++i) {
for(int j=count-1; j>=i+1; --j) {
if(compare(buf[j-1],buf[j])>0) {
char temp[255];
strcpy(temp,buf[j]);
strcpy(buf[j],buf[j-1]);
strcpy(buf[j-1],temp);
}
}
}
//fp = fopen("G:\\大三下\\linux\\实验\\Linux程序设计实验5\\Linux程序设计实验5\\File1-result.txt","w+");
if( (fp = fopen("File1-result.txt","w+"))==NULL) {
printf("打开文件File1-result.txt出错");
exit(0);
}
printf("排序后:\n");
for(int i=0; i<count; i++) {
printf("%s",buf[i]);
fputs(buf[i],fp);
}
printf("单词个数: %d\n\n",count-1);
fclose(fp);
gettimeofday(&end,NULL);
int us= 1000000 * (end.tv_sec-beg.tv_sec)+ end.tv_usec-beg.tv_usec;
printf(" %d ms\n\n",us/1000);
}
int compare( char *version1, char *version2) {
char* ver1 = version1;
char* ver2 = version2;
//入参判断
if(NULL == ver1 || NULL == ver2) {
if (NULL != ver1) {
return -3;
}
if (NULL != ver2) {
return -2;
}
return -1;
}
while ((*ver1 != '\0') && !(*(ver1) - *(ver2))) {
ver1++, ver2++;
}
if (*(ver1) == '\0' && *(ver2) == '\0') {
return 0;
} else {
if (*(ver1)-*(ver2)>0) {
return 1;
} else {
return -1;
}
}
}
编译
运行
六、实验数据及处理结果
七、思考讨论题
(1)使用数学库函数时,gcc编译需要注意问题?
答:c语言中包含math.h时,用gcc编译时要-lm参数。
(2)除了使用gettimeofday测试程序运行时间,还有什么方法可以测试程序运行时间,这些方法的优缺点有哪些?
答:其他方法如下:
1.GetTickCount()
2.Clock()
3.Timer()
gettimeofday可以精确到微秒,这些方法没有gettimeofday精确。
八、参考资料
1.金国庆等,Linux程序设计(第二版),浙江大学出版社,2014年4月
2. Neil Matthew,《Linux程序设计》(第4版), 人民邮电出版社,2014年9月
3. 杨宗德,《Linux高级程序设计》(第三版),人民邮电出版社,2012年11月
4. Daniel P.,《深入理解Linux内核》(第三版),中国电力出版社,2013年1月