凡是以#
开头的均为预处理命令。
宏定义简单点说就是查找替换。考虑下面的代码。
编译可以通过吗?试一下。
很明显,编译器并不知道x
的类型,而printf
函数试图打印x
的值,失败是不可避免的。
问题似乎已经找出来了,现在只需要将x
改为字符串。宏定义如下:
其实,和还有一种更加简洁的方法 。在C
中,有一个#
指令,也称为“字符串化运算符”,能将其参数转换为字符串。所以上面的宏定义可以修改如下。
注意:在宏定义时,其字符串要用小括号括起来,否则会产生出错误的编译,在运行时,得不到想 要的结果。
与函数一样,可以将可变长度参数传递给宏。 为此,将使用以下预处理器标识符。 要在宏中支持变长参数,必须在宏定义中包含省略号(...)。 __VA_ARGS__
预处理标识符负责提供给宏的可变长度参数替换。 连接运算符##
(又名粘贴运算符)用于连接变量参数。
看一下例子。 下面的宏采用可变长度参数,如printf
函数。 此宏用于错误记录。 宏打印文件名后跟行号,最后打印信息/错误消息。 第一个参数prio
确定消息的优先级,即它是信息消息还是错误,“流”可以是“标准输出”或“标准错误”。
- 当程序终止退出时,所有的数据将会随之消失。将数据保存在文件中则不会。
- 如果有很多的数据需要处理,自然不会采用手动输入的方式。然而,可以预先将数据存储在文件中,
C
提供了直接访问文件的函数,操作起来很方便。
- 可以将文件中的数据在不同计算机之间移植。
通常以.txt
为后缀,只包含平白文本内容,可以轻松地编辑和删除,维护代价小,易读,但安全性较低。
存储的并不是文本,而是其二进制表示。这可以存更多数据,可读性不强,但安全性较高。
不管是文本文件还是二进制文件,文件的主要操作都有一下几种:
打开文件的fopen
函数需要包含stdio.h
库。
熟悉典型的文件打开模式会很有帮助。
filer
只读如果文件不存在,fopen
返回NULLrb
只读(二进制形式)如果文件不存在,fopen
返回NULLw
只写文件如果存在,其内容将会被覆盖;不存在则创建wb
只写(二进制形式)文件如果存在,其内容将会被覆盖;不存在则创建a
在文件末尾添加内容如果文件不存在则被创建ab
在文件末尾添加内容(二进制形式)如果文件不存在则被创建r+
读、写如果文件不存在,fopen
返回NULLrb+
读、写(二进制形式)如果文件不存在,fopen
返回NULLw+
读、写文件如果存在,其内容将会被覆盖;不存在则创建wb+
读、写(二进制形式)文件如果存在,其内容将会被覆盖;不存在则创建a+
读、写如果文件不存在则被创建ab+
读、写(二进制形式)如果文件不存在则被创建
注意:所有文件使用完毕之后都应该关闭。
对于文本文件,使用函数 fprintf
和 fscanf
进行读写。
使用fprintf
向文件中写内容
程序读取一个整数然后将其存到文件program.txt
中。
使用fscanf
从文件中读取内容
程序从文件读取一个整数并将其打印到标准输出流。
另一些函数,比如fgetchar
、fputc
都可以以相同的方式使用。
对于二进制文件,使用函数fread
和fwrite
进行读写。
使用fwrite
向文件中写内容
使用fread
从文件中读取内容
使用函数fseek
获取数据
如果文件比较大但需要访问某一个位置的内容,这时候可能需要遍历整个文件。这显然浪费时间和内存。更简单的方式是使用fseek
函数。
第一个参数是文件指针,第二个是要找的偏移量,第三个是计算偏移量的开始位置。
这两个函数的返回值是什么?
printf
返回要打印字符的数量,或者当输出、编码错误时返回一个负数
对于字符串输出,使用puts
更加高效。printf
的底层实现比puts
复杂很多,并且用户在终端输入字符串时会产生安全问题。另外,puts
会自动换行,如果不想这样,使用fputs(str,stdout)
。
scanf
如果在接收第一个参数之前发生错误,将返回EOF
,否则返回输入的数量。
sprintf
输出字符到给定的字符数组。
fprintf
将内容输出到文件。
getc
从给定的输入流读取单个字符,成功时返回该字符对应的整数,通常是ASCII
码;失败时返回EOF
。
getch
通常出现在MS-DOS
使用的像Turbo C
之类的编译器的conio.h
头文件中,注意它不是C
标准库或者ISO
C
的一部分,或者说getch
没有被POSIX
定义。getch
从键盘读取一个字符但没有使用任何缓冲。与此相似的还有getche
。
fflush
通常用于输出流。fflush
可以清空输出缓冲,并把缓冲区的数据移控制台(标准输出流)或者磁盘(文件流)。以下是语法。
fflush
可以用在输入流吗?C
标准是不允许的。但有些编译器,如微软的Visual Studio
却允许。下面给出用例。
socket
编程是连接Internet
中两个节点(两台主机)并进行通信的一种方式。在典型的C/S
模式中,服务端被动地等待连接,而客户端主动请求连接。两者通过TCP/IP
协议栈实现进程间的通信。
Client
和Server
都要经历一定的阶段才能建立连接。流程图如下。