最近在复习C语言时发现自己对C语言某些格式化输出的规则还有些模糊,于是就重新总结学习了一下,果然温故知新,还是值得说一下滴。(其实就是手痒了想写点简单的内容,不过你可以先看一下接下来的这个小demo,看看关于格式化的东西都还记得不,检验一下自己的C语言基础怎么样)
检验一下自己
先展示一个有趣的小进度条demo:
效果就是一个加载进度条的动画
说明:包括进度条、加载百分比、以及一个小小的加载轮,由“ -\|/ ”组成
#include<stdio.h>
#include<windows.h>
#include<string>
#define SIZE 101
#define FLAG '='
int main() {
char buffer[SIZE];
memset(buffer, 0, sizeof(buffer));
int rate = 0;
const char* loadSign = "-\\|/";
int len = strlen(loadSign);
while(rate<=100){
printf("[%-100s][%d%%][%c]\r", buffer, rate, loadSign[rate % len]);
buffer[rate] = FLAG;
Sleep(100);
rate++;
}
printf("\n");
return 0;
}
代码就不细说了,相信大家都能看懂。
我要讲的主要是这行代码,如果接下来的问题你都清楚,那你可以退出了,你的基础很牢固:
printf("[%-100s][%d%%][%c]\r", buffer, rate, loadSign[rate % len]);
memset(buffer, 0, sizeof(buffer));
问题:
1)%-100s 是在干什么?“ - ” 和数字100是分别什么效果?
2)%% 是什么?
3)\r 是什么?
4)为什么要用memset函数将所有单位字节设置为0?(你不会忘了啥是memset吧???)
5)以及如果你学习了Linux系统操作,这段代码还能运行出正常效果吗?(涉及缓冲区问题)
格式修饰符
在%和格式符之间的符号叫做格式修饰符
%-100s中的-100就是格式修饰符,格式修饰符的意义在于对输出字符的宽度控制和精度控制
宽度控制(都是很简单的例子,没有图例,自己在编译器上输出试验)
1)如%5d,输出的内容至少5个字符宽,不足5个字符编译器会自动用空格填充,但是输出的内容是右对齐的!!
2)如%-5d,输出5个字符宽,与上面一样,唯一区别在于输出内容是左对齐的!
3)如%05d,宽度仍然是5,但不是空格补齐,而是字符0补齐的!
精度控制
1)如%.2f,浮点数保留两位小数
2)如%.2s,输出字符串的前两个字符
现在问题1)的答案已经可以得出了 %-100s 的输出效果:表示左对齐一个字符串,并保证占用100个字符宽,字符串不足100个字符宽的空格自动补齐。
转义字符(常见)
在进行字符输出时,有些字符是不能直接用的,如“ \ ”,还有些是字符表意无法直接表达的,如换行,都需要转义字符进行表示。
转义字符 | 含义 |
---|---|
\n | 换行 |
\r | 回车 |
\\ | 反斜杠 |
\' | 单引号 |
\'' | 双引号 |
\t | 水平制表符 |
%% | 百分号 |
\0 | 空字符 |
问题2)、3)、4)解决,注意这里的\r回车的含义不是键盘上的回车键,而是光标回到所在行的开头
问题4)单独说一下,因为这行代码将buffer
数组的所有字节都设置为0(即空字符'\0'),将100个字符宽的字符串设置为空,以便进度条的填充。
问题5):在Linux上这段代码的运行效果
这里就要引出缓冲区的概念了:在C语言中,缓冲区(Buffer)是用于临时存储输入/输出数据的内存区域,目的是减少频繁的系统调用(如write
或read
),提高I/O效率。
简单来说,windows的输出是无缓冲输出的,所以这段代码会直接输出到控制台。而在Linux中的输出属于行缓冲,只有碰到换行符才会输出到终端上。而demo中的输出代码结尾是 \r 是回车符,所以Linux的输出内容会停滞在缓冲区中直至程序结束或手动刷新缓冲区,那么运行效果就是什么也不显示,因为程序结束时终端也随之关闭。
解决方法:手动刷新缓冲区 在printf()代码的下一行添加 fflush(stdout) ,即每打印一次就刷新一次缓冲区,使每次打印都能输出到终端上即可。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define SIZE 101
#define FLAG '='
//进度条demo
int main(){
int rate = 0;
char buffer[SIZE];
memset(buffer,0,sizeof(buffer));
const char* l = "-\\|/";
int len = strlen(l);
while(rate<=100){
printf("[%-100s][%d%%][%c]\r",buffer,rate,l[rate%len]);
fflush(stdout);
buffer[rate]=FLAG;
usleep(100000);
rate++;
}
printf("\n");
return 0;
}
本篇的内容到这就结束了,嘿嘿,虽然内容简单,但我还是想狡辩一下。
我们在学习时的收获都是具有滞后性的,每次初学新内容都会忘得很快,所以时不时的复习很重要,就算是简单的东西在复习后也会有很深的收获,我想分享的不止是简单的知识,更是这种复习收获时带来的快乐。希望各位同仁多多努力,祝我们都有美好的前程^(* ̄(oo) ̄)^。