复习:
1、输出缓冲区
程序输出的数据并没有立即写入到"文件",而是先存储到了缓冲区中,当满足一定条件时才会写入到文件中
1、遇到\n
2、遇到输入语句
3、缓冲区满4k
4、程序结束
5、手动刷新fflush
2、输入缓冲区
在终端输入的数据此时由终端保管,当按下回车后,数据由终端写入到程序的输入缓冲区,scanf函数再从缓冲区中读取数据到给变量赋值
1、当想要输入的是整型、浮点型数据,而缓冲区的数据是字符或符号时,此时类型不匹配读取失败,并且不会从缓冲区中拿走字符或符号,导致接下来的数据读取都失败
解决方法:
根据scanf的返回值判断变量是否从缓冲区中读取成功,如果失败,则先清空缓冲区再重新scanf,直到成功为止
scanf("%*[^\n]");
scanf("%*c");
stdin->_IO_read_ptr = stdin->_IO_read_end;
2、当使用fgets读取字符时,如果输入的字符超过size-1个,则缓冲区中会残留超出部分字符,这样会影响接下来的数据的读取
解决方法:
判断字符串的最后一个字符是否是\n,如果不是则说明缓冲区中有残留数据,需要清理缓冲区。
3、当先输入其他类型数据,紧接着输入字符、字符串型数据时,前一次可能会残留一个\n,会影响后面的字符、字符串的输入
输入字符:
scanf(" %c");
输入字符串:
gets(str1);
scanf("%*c");
gets(str);
3、常考的字符串处理函数
strlen、strcpy、strcmp、strcat
memcpy、memset、memcmp
4、常用的字符串处理函数
sscanf 解析字符串
sprintf 把各种类型的数据和提示信息拼接成字符串
预处理指令:
程序员所编写的代码并不能被真正的编译器编译,需要一段程序把代码翻译一下
翻译的过程叫做预处理,负责翻译的程序叫做预处理器,被翻译的代码叫做预处理指令,以#开头的代码都是预处理指令
查看预处理过程
gcc -E code.c 把预处理的结果显示到终端上
gcc -E code.c -o code.i 把预处理结果存储到code.i预处理文件中
预处理指令的分类:
#include 文件包含
#include <> 从系统指定路径查找并导入头文件
#include "" 从当前路径下查找,如果找不到再从系统指定路径查找并导入头文件
通过编译参数指定查找路径 -I /path
操作系统通过设置环境变量来指定头文件的查找路径
#define 定义宏
宏常量: #define 宏名 数据
#define MAX 50
优点:提高可读性、提高可扩展性(方便批量修改)、提高安全性、还可以用在case后面
注意:一般宏名全部大写、末尾不要加分号
预定义的宏:
__func__ 获取函数名
__FILE__ 获取文件名
__DATE__ 获取当 前日期
__TIME__ 获取当前时间
__LINE__ 获取当前行号
宏函数 带参数的宏
不是真正的函数,不检查参数类型,没有传参,只是值替换,没有返回值,只有表达式的计算结果
#define SUM(a,b,c) a+b+c
1、把代码替换为宏函数后面的表达式代码
2、把宏函数代码中使用的参数替换为调用者提供的数据
注意:定义宏常量、宏函数不能直接换行,可以使用续行符 \ 放在末尾可以换行
也可以使用大括号保护代码
宏的二义性:
由于宏所处的位置、参数不同导致宏函数有不同的解释和功能,这种叫做宏的二义性
如何避免二义性:
1、宏函数整体代码加小括号
2、每个参数都加小括号
3、使用宏函数时不要提供带自变运算符的变量作为参数
注意:容易出选择题,例如:哪个宏有二义性、选择出宏函数的结果
常考的笔试面试题:(C语言中与指针相关的知识点有哪些)
如果是普通类型,它们的功能上没有区别
#define INT int
typedef int INT;
如果是指针类型
#define INTP int*
INTP p1,p2,p3;//p1是指针,p2p3是int类型变量
typedef int* INTP;
INTP p1,p2,p3;//p1p2p3是指针
宏函数与普通函数的区别?
是什么?
宏函数:不是真正的函数,只是代码替换,用起来像函数
函数:是一段具有某项功能的代码,会被编译成二进制指令存储在代码段中,函数名就是它的首地址,有独立的命名空间、栈空间
有什么不一样?
函数: 返回值 类型检查 安全 入栈、出栈 速度慢 跳转
宏函数:运算结果 通用 危险 替换 速度快 冗余
条件编译:
根据条件决定让代码是否参与最终的编译
版本控制:
#if
#elif
#else
#endif
头文件卫士:防止头文件重复包含
#ifndef 宏名(头文件名全大写,_替代.)
#define 宏名(头文件名全大写,_替代.)
#endif// 宏名(头文件名全大写,_替代.)
判断、调试代码:
#ifdef 宏名(DEBUG)
#else
#endif
注意:可以通过编译参数-D宏名 定义宏
封装调试信息宏函数
#ifdef DEBUG
#define debug(...) printf(__VA_ARGS__);
#else
#define debug(...)
#endif
封装提示错误信息宏函数
#define error(...) printf("%s %s %s %m %d %s %s",__FILE__,__func__,__VA_ARGS__,__LINE__,__DATE__,__TIME__);
作业:
实现一个交换两个变量的宏函数,要求尽可能通用,能使用多少种方法
swap(num1,num2)