设为首页 加入收藏

TOP

深入理解C语言----标准I/O小结(缓冲区,I/O函数及其他相关问题)(二)
2014-11-23 19:48:26 来源: 作者: 【 】 浏览:18
Tags:深入 理解 语言 ---- 标准 I/O 小结 缓冲区 函数 及其他 相关 问题
出。
puts()虽然安全,但是他的不方便在于,每次将换行符写到输出。

因此,我们贯彻这样的方针,坚持使用fgets和fputs,并自己处理换行符。


各I/O函数的效率对比可参看APUE5.9


格式化I/O:

格式化输出:

int printf ( const char * format, ... );
int fprintf (FILE *fp, const char * format, ... );
int snprintf (char *buf, size_t n, const char * format, ... );

注意参数转换说明中 %[flags][fldwidth][lenmodifier]convtype,宽度和精度字段可被置为*,而后用一个整形参数指定其值。

printf的实现:

printf是C中为数不多的变参函数之一,主要通过stdarg.h中的一系列宏来对参数列表进行处理。其源码实现可以参看:点击打开链接和点击打开链接

使用变参函数机制,简单模拟printf

#include
  
   
#include
   
     #include
    
      #include
     
       void simon_printf(char *fmt, ...) { char buf[10]; char *p = fmt; char c_tmp, *s_tmp; int i_tmp; double f_tmp; va_list ap; va_start(ap, fmt); while (*p) { if (*p != '%') { putchar(*p++); continue; } else { switch (*++p) { case 'd': { i_tmp = va_arg(ap, int); // sprintf(buf, "%d", i_tmp); // write(STDOUT_FILENO, buf, strlen(buf)); printf("%d", i_tmp); break; } case 'f'://float在内部被提升为double { f_tmp = va_arg(ap, double); printf("%f", f_tmp); break; } case 'c'://char在内部被提升为int { i_tmp = va_arg(ap, int); printf("%c", i_tmp); break; } case 's': { for(s_tmp = va_arg(ap, char*); *s_tmp; s_tmp++) printf("%c", *s_tmp); break; } } p++; } } va_end(ap); } int main() { int a = 1; float b = 2.0; char c = 'a'; char *str = {"test"}; simon_printf("This is a test Message:\n int:%d\n float:%f\n string: %s\n char:%c\n ", a, b, str, c); return 0; }
     
    
   
  


格式化输入:

int scanf(const char *format, ...);
int fscanf(FILE *fp, const char *format, ...);
int sscanf(const char *buf, const char *format, ...);

scanf中*表示抑制,不把该输入赋值给对应变量,即跳过。

scanf()还有一些正则用法:[]表示输入字符集,可以使用连字符表示范围,scanf() 连续吃进集合中的字符并放入对应的字符数组,直到发现不在集合中的字符为止。用字符 ^ 可以说明补集。把 ^ 字符放为扫描集的第一字符时,构成其它字符组成的命令的补集合。

通常并不推荐使用scanf()的正则用法,用法复杂, 容易出错。编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率。

关于输入缓冲区清空:

1)fflush(NULL)

fflush的定义说得很清楚了,这种用法导致的结果不确定

If the given stream was open for writing (or if it was open for updating and the last i/o operation was an output operation) any unwritten data in its output buffer is written to the file.
If stream is a null pointer, all such streams are flushed.
In all other cases, the behavior depends on the specific library implementation. In some implementations, flushing a stream open for reading causes its input buffer to be cleared (but this is not portable expected behavior).
The stream remains open after this call.
When a file is closed, either because of a call to fclose or because the program terminates, all the buffers associated with it are automatically flushed.

如果stream指向输出流或者更新流(update stream),并且这个更新流最近执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream指向的文件(如标准输出文件stdout)。
fflush(NULL)清空所有输出流和上面提到的更新流。
否则,fflush函数的行为是不确定的。取决于编译器,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,而gcc就不支持。

2)setbuf(stdin, NULL);
setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区,在没有特殊要求的情况下还是适用的


3)int c;
while((c = getchar()) != '\n' && c != EOF);
由代码知,不停地使用getchar()获取缓冲区中字符,直到获取的字符c是换行符’\n’或者是文件结尾符EOF为止。这个方法可以完美清除输入缓冲区,并且具备可移植性。


4)scanf("%[^\n]%*c");
这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。


首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言总结――结构体(struct)使.. 下一篇语义分析:C语言表达式的语法树生..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: