如果要实现指定字符串在标准输出流(一般为显示器)上闪烁,可以定义如下函数:
void bput(const char*s,int appe,int disa,int repe)
字符串s出现appe秒后,消失disa秒,重复以上操作repe次返回到调用方。
一、具体代码
#include<time.h>
#include<stdio.h>
#include<string.h>
void bput(char*s,int appe,int disa,int repe)
{
int char_len = strlen(s);
for(int i = 0;i < repe;i++)
{
printf("\r%s",s);
clock_t t1 = clock();
clock_t t2 = 0;
while(1000*(t2-t1)/CLOCKS_PER_SEC<appe)
{
t2 = clock();
}
printf("\r%*s",char_len,"");
clock_t t3 = clock();
clock_t t4 = 0;
while(1000*(t4-t3)/CLOCKS_PER_SEC<disa)
{
t4 = clock();
}
}
}
int main()
{
int appe = 0;
int disa = 0;
int repe = 0;
char s[20] = "";
printf("输入一个长度20以内的字符串:>");
gets(s);
printf("输入显示的毫秒数,消失的毫秒数,反复执行的次数(以空格隔开)");
scanf("%d %d %d",&appe,&disa,&repe);
bput(s,appe,disa,repe);
return 0;
}
让我们来具体解读一下bput函数的内容。
二、strlen函数:查询字符串的长度
strlen |
头文件 #include<string.h> |
格式 size_t strlen(const char *s) |
功能 计算s所指定的字符串长度(不包含空字符的字符数) |
返回值 返回值size_t表示末尾的空字符前面的字符的个数 |
函数接受的参数为字符指针或字符数组,不要随意改动字符串,改动后地址将会发生变化,所以用const修饰。
#include<stdio.h>
#include<string.h>
int main()
{
const char*a = "ABCDEF";
const char b[] = "ABCDEF";
int a_len = strlen(a);
int b_len = strlen(b);
printf("%d %d",a_len,b_len);//运行结果为6 6
return 0;
}
三、clock函数
clock |
头文件 #include<time.h> |
格式 clock_t clock() |
功能 求处理器调用某个进程所花费的时间 |
返回值 从定义与程序启动相关的编程环境的时间点起,用处理系统的最佳逼近返回程序占用处理 器的时间。默认返回为clock_t型时钟周期的总数,为了以秒为计量单位,必须用本函数除 以CLOCKS_PER_SEC宏的值。如果无法获取处理器调用该进程所花费的时间,或无法显 示数值,就返回值(clock_t)-1。(加粗的字体后面会解释) |
这里可以具体化为下图
得到时钟数后除以CLOCKS_PER_SEC宏的值(该编译环境下为1000)即可得到该次调用clock函数时,程序历经的时间(秒)。
clock_t型:该编译环境下将clock_t等同于unsigned型。clock_t等同于哪种类型(unsigned、unsigned long……)由编译环境决定。
CLOCKS_PER_SEC宏:由头文件<time.h>定义。直译为“每秒的时钟数”,如果时钟的精确度为0.001秒,那么一秒内就有1000个时钟,这个宏的值就定义为1000。不同的硬件和OS会导致时钟的精确度也不同,所以clock_t型表示数值的单位也取决于编程环境。
(clock_t)-1:指将-1强制转换成clock_t型,而不是指clock_t的值减1。
我们可以使用clock函数求两个时间点的差值以计算两次clock函数的时间点之间的时钟差:
#include<stdio.h>
#include<time.h>
int main()
{
clock_t t1 = clock();//计时起点
clock_t t2 = 0;
/*
一
段
程
序
*/
t2 = clock();//计时终点
double t = (t2 - t1)/CLOCKS_PER_SEC;//时钟差除以每秒时钟数,计算时间差(秒)
printf("运行这段程序用了%lf秒",t);
return 0;
}
如果我们先定义t1,再在一个循环内不断更新t2的值,并将(t2-t1)/CLOCKS_PER_SEC<x(x为指定秒数)作为循环的判断条件,即可达到使程序暂停x秒后再运行(在此时间段内运行循环)的效果:
#include<stdio.h>
#include<time.h>
int main()
{
clock_t t1 = clock();//计时起点
clock_t t2 = 0;
int x = 0;
scanf("%d",&x);
while((t2-t1)/CLOCKS_PER_SEC<x)
{
t2 = clock();//更新t2的时钟数
}
return 0;
}
综上易知,如果将(t2-t1)/CLOCKS_PER_SEC的分母乘1000,就可以得到程序运行的毫秒数。
#include<stdio.h>
#include<time.h>
int main()
{
clock_t t1 = clock();
clock_t t2 = 0;
int x = 0;//此时x为毫秒数
scanf("%d",&x);
while(1000*(t2-t1)/CLOCKS_PER_SEC<x)//分母乘1000,与毫秒作比较
{
t2 = clock();
}
return 0;
}
当然,使用clock函数来使程序暂停运行的效果,Sleep函数也可以达到:
#include<stdio.h>
#include<windows.h>//头文件windows.h
int main()
{
int x = 0;
scanf("%d",&x);
Sleep(x);//参数x为毫秒数
return 0;
}
#include<stdio.h>
#include<windows.h>//头文件为windows.h
int main()
{
int a = 300;
for(int i = 0;i<10;i++)
{
printf("\rABC");
Sleep(a);//参数可为变量
printf("\r%*s",3,"");
Sleep(300);//参数可为常量
}
return 0;
}
Sleep(int)函数的头文件为windows.h,参数可以为变量或常量。
使用如上的代码也可以实现字符串的闪烁显示,下面介绍\r和%*s使标准输出流上的字符串"ABC"和三个""交替覆盖显示的原理。
四、\r 、%*.*
回车符\r:输出回车符\r后,显示光标就会移动到本行开头。本行已显示字符串b的情况下,在\r后显示的内容a都将覆盖本行已有的内容b。如果a的长度大于b,那么将完全覆盖b的内容;如果a的长度小于b,那么a只从左往右数覆盖等于a长度的内容,其它内容不变。
#include<stdio.h>
#include<windows.h>
int main()
{
char*b = "最开始bbbbb";
printf("%s",b);
Sleep(1000);
char*a = "修改后aaaaa";
printf("\r%s",a);
}
输出内容:
****一秒后
如果修改后内容的长度比修改前的内容短,
#include<stdio.h>
#include<windows.h>
int main()
{
char*b = "最开始bbbbb";
printf("%s",b);
Sleep(1000);
char*a = "修改后aa";
printf("\r%s",a);
}
就会出现以下输出内容:
如果在循环中反复在本行开头显示两个字符串,让空白字符串和要显示的字符串交替覆盖,两个字符串等长或是空白字符串大于要显示的字符串时,即可达到让字符串闪烁显示的效果:
#include<stdio.h>
#include<windows.h>
int main()
{
char*b = "最开始bbbbb";
char*a = " ";
for(int i = 0;i<10;i++)//闪烁10次
{
printf("\r%s",b);
Sleep(300);
printf("\r%s",a);
Sleep(300);
}
}
在自定义字符串内容的情况下,提前准备一个等长的空白字符串显然不现实,那么我们可以用printf函数中的%*.*来控制输出的空白数量。然而这些"*"都可以替换为数字来实现printf函数中输出内容外指定"*"的值而达到的效果。
先讨论句点(.)左边的"*"。左边的"*"可以控制输出内容的最小输出宽度,如果输出内容达不到最小输出宽度,则在左侧用空格补全至最小宽度(在左侧指定了"-"的情况下,在右侧补全空格至最小宽度)。这个"*"也可以替换为数字来实现相同效果:
include<stdio.h>
int main()
{
int a = 20;
printf("%*d",4,a);//输出结果为: 20(共有4个字节的长度)
printf("%4d",a);//输出结果与在内容外控制"*"的值的效果相同
}
如果将printf函数要输出的内容改变成一个空字符串,并使用变量改变"*"的数值,以此输出内容的宽度,就可以输出自己指定长度的空白:
#include<stdio.h>
int main()
{
int len= 0;
scanf("%d",&len);
printf("\r%*s",len,"");//""代表输出空字符串
}
这样就可以得到想要长度的空白了。
句点(.)右侧的"*"(同时也可以是数字)在不同情况下的作用不同,总体概括为精度:
- d、i、o、u、x、X(整形)情况下,代表最小输出位数。
- e、E、f(浮点型)情况下,代表小数点后的输出位数。
- g、G(指数型)情况下,代表有效位数。
- s(字符串)情况下,代表从字符串中能输出的最大字符数。
五、总结
有了这些基础知识之后,我们再来看开头的函数就轻松得多了:
#include<time.h>
#include<stdio.h>
#include<string.h>
void bput(char*s,int appe,int disa,int repe)//appe和disa为毫秒数,所以后边要*1000
{
int char_len = strlen(s);//测得字符串数组s的长度
for(int i = 0;i < repe;i++)//重复repe次循环
{
printf("\r%s",s);//将光标移动到开头,并输出字符内容
clock_t t1 = clock();//初始化并开始记录此时的时钟数t1
clock_t t2 = 0;//初始化t2
while(1000*(t2-t1)/CLOCKS_PER_SEC<appe)//appe为毫秒数,所以前面乘1000
{ //显示appe毫秒
t2 = clock();//随时更新t2的时钟数
}
printf("\r%*s",char_len,"");//利用句点前的*输出和s等长的空白字符串(宽度相等的空字符串)
clock_t t3 = clock();//同t1,记录此刻时钟数
clock_t t4 = 0;
while(1000*(t4-t3)/CLOCKS_PER_SEC<disa)//消失disa毫秒
{
t4 = clock();
}
}
}
int main()
{
int appe = 0;
int disa = 0;
int repe = 0;
char s[20] = "";
printf("输入一个长度20以内的字符串:>");
gets(s);
printf("输入显示的毫秒数,消失的毫秒数,反复执行的次数(以空格隔开)");
scanf("%d %d %d",&appe,&disa,&repe);
bput(s,appe,disa,repe);
return 0;
}
当然这里的两次停顿也可以在引入windows.h头文件后使用Sleep函数代替。
//本人是刚接触c语言不久的小白,如有错误和不足还请指正:)