C和C++基本输入输出小谈

Table of Contents

今天翻了一下 Wunderlist ,发现有一个任务拖了好久,所以很有必要完成了。

记录是这样的:"把scanf/getchar/getch/gets这些讲一讲 by Tanky", 具体原因记不清了,大体是TankyWoo说好多 ACM 新手在输入输出这块问题还是比较多,所以希望我有时间总结一下,写一写。没想到拖了这么长时间,实在惭愧。

所以,本文的读者定位在初级/中级 ACMer 对语言的基本需求,我基本上没有 AC 过,但是作为一个过来人,我大体知道输入输出这一块会卡在什么地方。

以前写过类似总结性的笔记:C/C++输入输出流总结,C/C++表面上给程序员提供了丰富的输入输出接口,正如文章中所介绍的一大堆函数。但是,实际上,开发过程中用到的很少。对比 C,C++ 提供的不同输入输出函数,个人倾向于使用 C 语言的 fopen, fprintf, … 而不是 C++ 的 fstream 类。C 语言所提供的接口更灵活好用,而 C++ 的 ">>" "<<" 让本来很简单的语句变的不清晰和复杂。比如:

fprintf(fp, "This is a int %d, this is a float %f", int, float); // C
out << "This is a int" << int << ", this is a float " << float << endl; // C++

通过 fprintf 我一口气就可以读出来,我要输出的字符串是什么,而 out 不行。我一直觉得 C++ 的输出输出是非常鸡肋的,限制性多又难以理解,尤其是 flags 的开启与关闭。再如类似 width 和 precision,我更喜欢用 C 语言的 0.3f% 做格式化控制。

C++ 控制输入输出相对牛逼的一点是有 stringstream 类,功能强大,相对也比较好用。只是,略复杂。

ok,不再吐槽,回到正题。

如果挨个函数去解释的话,不知道这篇文章要写多长,也没有意义。最好的学习网站: www.cplusplus.com,很好的支持和跟进新标准。编译器推荐gcc,IDE推荐CodeBlocks,IDE的选择可以看 10个最佳的C/C++编译器和IDEs,Eclipse也挺好,但是太大了,不推荐。 /不要觉得这些东西不重要,选择最标准支持的好的编译器和一个易于调试的IDE,对于一个新手来说是至关重要的/。千万不要再用VC6.0了,标准支持太差。为什么不推荐 vs2010/vs2012? 不免费,重量级,微软太喜欢给程序员强加东西了。

下面说一下,我个人认为输出输出这块的迷惑点:

1 1.流的分类

当年,这是相当迷惑我的一个地方。也就是所谓的"二进制流"和"文本流",即"text file" or "binary file",代码上的区别就是打开文件时的参数有没有'b'。

怎么理解呢?我们知道计算机中所有的文件无非都是01二进制存储的,所以,所谓的文本流也是二进制文件,单靠字面的 text file , binray file 的区分很容易误导的。其实所谓的 text file 和 binary file 就是人肉眼能不能直观的看懂内容,能看懂即 text file ,看不懂 binray file。 你看我的博客内容是 text file,而一个可执行文件,一个 dll 就是 binary file 了。这两种文件,打开都是用 fopen,只是传入的参数有没有'b',对应的操作函数区别也比较大:

text file: fprintf fscanf, fputs, fgets ...
binary file: fread, fwrite, fseek, ftell, ...

ACM 的话,用前者比较多,但是实际应用中后者居多。以我个人的经历来说,text file我做项目基本上没有用过。个人特别喜欢 fwrite, fread, fseek … 这些函数,灵活性强,可控性强。它不会像 fscanf 使用考虑那么多,基本上这几个函数就可以满足我的文件操作需求了。

其实常用的函数也就这么几个,想 rewind 这种函数我从来没用过。

值得一提的是 C11 新填了一个参数 'x',作用是如果文件存在的话,打开文件失败。

The new C standard (C2011, which is not part of C++) adds a new standard subspecifier ("x"), that can be appended to any "w" specifier (to form "wx", "wbx", "w+x" or "w+bx"/"wb+x"). This subspecifier forces the function to fail if the file exists, instead of overwriting it.

2 2.文件打开失败

相信很多人会遇到这个问题,一般三个原因:

  1. 相对/绝对路径,这应该是最多数的情况了。绝对路径是相对盘符/根目录的,比如 C:\\program files, =/usr/bin/=,相对路径是相对工程和可执行文件的,取决于你真实运行的起始端;
  2. 文件正在被占用,同一个程序,运行了两次;
  3. 权限,如果在 Unix-like 系统下,如果文件打开失败,首先去找这个原因;
  4. 路径中的转义字符,"\"、"/"、路径中的空格都是常见问题,遇到的多了就知道了;

建议在 fopen 之后加一个 if 判断,确保第一时间得到文件打开失败的信息。

3 3. 文件无内容

文件打开成功,也写入了内容,程序关闭后无内容。原因是可能没有 fclose。如果想在程序运行的时候实时的看到文件内容的变化,可以写入一次调用一次 fflush(),调试程序可以这么用。但是,工程中就不要频繁的 fflush 了,会影响运行效率。

4 4. feof

这块出问题比较多,但是只要仔细的看文档,就不会有问题了。很容易记反!

A non-zero value is returned in the case that the end-of-file indicator associated with the stream is set. Otherwise, zero is returned.

5 5. 字符串截断符 '\0'

看看我遇到过的坑吧: C++|'\0'引发的小故事

6 6. getchar/getch

getchar() 两个注意点: 1. 读取一个字符并回现,但是只有接收到 回车 才会函数返回; 2. 返回值是 int 而不是 char;

getch() 两个注意点: 1. 不是标准C函数,不建议使用; 2. 读取一个字符不回现,印象中会立刻返回,不用等到接收到 回车;

7 最后,基本的格式化标准

这是所有的基础,你需要知道 %d 表示的整形,%f 表示的是浮点型,%s是字符串,且只以'\0'作为结束符等。类型不匹配也是经常出现的一个问题,在C中有的时候参数不匹配,编译不会报错,但是运行就直接崩掉了。

文件输入输出和控制台输入输出基本相同,fprintf 和 printf 对应等等,可以理解成控制台也是一个特殊的文件。

有几篇相关的文章,感兴趣可以去看看:

总感觉一写起来都有很多零碎的东西可以说。但是真正想说的是,遇到问题要勤于思考,勤于查阅,解决之后要勤于总结。即便C语言只是你的AC工具,我依旧建议你这么做。毕竟解决问题能力的培养才是重要的。

Date: 2013-10-20 00:00:00

Author: JerryZhang