缓冲输出与内存分配:
程序输出有两种方式,一种是即时处理方式(往往造成较高的系统负担),另一种是先暂时存起来然后再大块写入,因此c语言实现通常都允许程序员进行实际的写操作之前控制产生的输出数据量。
这种能力一般使用setbuf库函数实现,如果buf是一个大小适当的字符数粗,那么setbuf(stdout,buf);语句将会通知I/O库,所有写入到stdout的输出都应该使用buf作为输出缓冲区,直到buf缓冲区的内容被填满or程序员直接调用fflush,buf的内容才会写入到stdout之中,举一个例子来看看:
int main()
{
int c;
static char buf[BUFSIZ]; //BUFSIZ由stdio.h给出
setbuf(stdout,buf);
while((c=getchar())!=EOF)
putchar(c);
}
书上这个例子太垃圾了,于是去网上搜了一下,换一个
#include <stdio.h>
char outbuf[BUFSIZ];
int main(void)
{
setbuf(stdout, outbuf); // 把缓冲区与流相连
puts("This is a test of buffered output.\n");
puts(outbuf);
fflush(stdout); // 刷新
puts(outbuf); // 输出
return 0;
}
输出结果:
This is a test of buffered output.. //不在oubuf,但在I/O流,因为缓冲和流已经相连,转入outbuf中
This is a test of buffered output.. //输出此时的outbuf,之后outbuf应该保存了两个一样的字符串了
This is a test of buffered output..
This is a test of buffered output.. //输出此时的outbuf
程序先把outbuf与输出流相连,然后输出一个字符串,这时因为缓冲区已经与流相连,所以outbuf中也保存着这个字符串,紧接着puts函数又输出一遍,所以现在outbuf中保存着两个一样的字符串。刷新输出流之后,再次puts,则又输出两个字符串。
预处理器:
1.不能忽视宏的空格:
#define f (x) ((x)-1)
这句话中,f (x)就是有毒的。
2.宏不是函数:
在最开始学c的时候,网上总有些人写出这样其实不太好的话
#define abs(x) (((x)>=0)?(x):-(x))
//宏定义中出现的这些括号只是预防引起与优先级有关的问题
//所以在你忘记优先级的时候,括号也是比较好用的
//———————————————————————————————————————不可视的境界线
//如果你去掉括号的话,也就是#define abs(x) x>0?x:-x
//你试一下表达式abs(a-b)还能work well吗
//同时,这个“-”号也很讲究
//宏,只是用于预处理的替换
函数就是函数,宏就是宏,宏不要搞得太复杂,naive,这一节不看了,反正我也不会写这种代码。
3.可移植性缺陷:
代码的可移植性是工程中很重要的因素,在我们小组十天内写出满分大作业的时候就意识到了这一点,因为帆帆用的devc++,czb用的xcode(哎,你说有钱该多好),我用的vs2017,有的地方就是我这能跑他那里GG,还有每个IDE都可能有自己安装的一些库文件,比如我的vs就集成了EGE(#include <graphics.h>);对于一般的萌新同学,在用学校的编译器和自己电脑上的ide体验也相当不好。同时,c语言的标准也在变更着。所以有些时候我们写的代码,最好就别和机器、 编译器关系太密切。现在还想不起很多的采坑点,等我再学深一些再回来补。
4.realloc:
#define newsize 100*sizeof(int)
free(p);
p=realloc(p,newsize);
练习:编写一个函数对于一个已经排好序的整数表实现二分查找,函数的输入是一个指向表头的指针,表中元素个数以及带查找的数值。函数的输出是一个指向满足查找要求的元素指针,当未找到的时候就输出一个NULL指针。
二分查找原理很简单,但是在实践中人们经常不能写好,比如我。书上写了两个版本,我们这里意思意思一下。
int *bsearch(int *t,int n,int x)
{
int lo=0,hi=n;
while(lo<hi)
{
int mid=(hi+lo)/2; //可以用int mid=(hi+lo)>>1代替,提高机器速度
if(x<t[mid])
hi=mid;
if(x>t[mid])
lo=mid+1
else
return t+mid;
}
return NULL;
}
位运算我还是没系统理解,改天仔细看看。不过在很多机器上,下标运算都比指针运算慢,我们看看老爷子是怎么写的(哎)。
int *bsearch(int *t,int n,int x)
{
int *lo=t,*hi=t+n;
while(lo<hi)
{
int *mid=lo+((hi-lo)>>1);
if(x<*mid) hi=mid;
else if(x>*mid) lo=mid+1;
else
return mid;
}
return NULL;
}
关于文章的最终part,stdarg部分理解不透,干货没啥(我就记了个%e %f %g)我就设成了私密水文,至此,这本书在开学前水完了= =。
Ps:
%g用来输出实数,它根据数值的大小,自动选f格式或e格式(选择输出时占宽度较小的一种),且不输出无意义的0。即%g是根据结果自动选择科学记数法还是一般的小数记数法