第九章 - DDL-Killer/The-road-of-Linxu-Group2024 GitHub Wiki
int printf(const char *format,.....)
printf函数本质:变量初始化
va_list
和va_start
va_list
:访问可变参数列表中的数据,这是一个特殊的数据类型,用于存储变长参数的列表信息va_start
:用于初始化va_list
变量,使它指向变长参数列表中的第一个参数,使我们可以依次读取每个参数
循环解析格式字符串
- 使用
whlie
遍历字符串 - 遇到
%
,跳过,然后判断后面的类型 - 如果没有,则直接存入缓冲区
解析格式说明符
- 使用
va_arg()
从va_list类型中取出一个目标类型的参数,给snprintf
转换 - 使用
snprintf
:把类型进行转换,把字符串的“%d”等等转换为转换说明存入缓冲区
int snprintf(char *str,size_t size,const char *format,...)
snprintf:- str:目标缓冲区,格式化之后的数据写入这个字符串
- size:指定缓冲区的大小
- format:格式化字符串,定义输出的格式
- ...:可变参数,根据format说明符传入要格式的值
输出结果
write(1,buffer,count)
将缓冲区的内容写入标准输出(1代表标准输出)——控制台
清理和返回
- 使用
va_end()
结束可变参数的读取 return count
返回成功写入的字符数
代码
复习函数
- 函数是完成特定任务的独立程序代码单元
- 语法规则定义了函数的结构和使用方式
创建并使用简单函数
- 函数原型指明了函数的返回值和函数接受的参数类型,这些信息称为函数的签名
- 函数中的变量是局部变量,该变量只属于starbar()函数
定义带形式参数的函数
- 函数名右边括号里面的变量称为形式参数
调用带实际参数的函数
- 实际参数提供了形式参数的值
- 实际参数要被求值,然后将值拷贝给被调函数的形式参数
黑盒视角
- 在调用函数中的私有局部变量不影响外面的主调函数变量
使用return从函数中返回值
- 设计用于测试函数的程序有时被称为驱动程序
- return另一个作用是,终止函数并把控制传给主调函数的下一条语句
函数类型
声明函数时必须声明函数的类型,带返回值的函数类型应该与其返回值类型相同
函数原型的优点
- 函数原型是一个强有力的工具,它让编译器捕获在使用函数时可能出现的许多错误或疏漏
递归
C允许函数调用它自己,这种调用过程称为递归
尾递归
- 最简单的递归形式是把递归调用置于函数的末尾,正好在return语句之前
- 尾递归是最简单的递归形式
递归和倒序计算
- 设计一个以二进制表示整数的方法和算法:
- 在二进制中,奇数的末尾一定是1,偶数的末尾一定是0,通过n%2,确定最后一位是是1还是0,这个数是最后打印的
- 要获得下一个数字,就n/2,这种方法相当于把小数点往前移动一位,然后继续n%2
- 第二步的结果小于2则停止计算,只要结果大于或等于2,则说明还有二进制位
递归的优缺点
- 优点:为某些编程问题提供了最简单的解决方案
- 缺点:会快速消耗计算机的内存资源,不方便阅读
编译多源代码文件的程序
**使用多个函数最简单的办法就是把它们都放在同一个文件里,然后像编译只有一个函数的文件那样编译
C语言的编译过程:预处理、编译、汇编、链接
- 预处理
- 宏替换
- 文件包括
- 条件编译
- 删除注释
- 编译
- 语法分析
- 语义分析:变量,函数,数据类型
- 优化:代码优化、优化循环
- 汇编
- 将编译生成汇编语言代码,转为机器代码
- 链接:多个目标文件与库文件结合在一起,生成可执行文件
- 符号解析:函数和变量引用链接在一起
- 库的加载:外邻库加载到最终可执行
- 地址条件:分配内存地址
UNIX和Linux
- GNU C编译器和编译器GCC,编译后生成
a.out
可执行文件
DOS命令
- 拓展名为
.obj
Windows和苹果的IDE编译器
- 集成开发环境是面向项目的
- 项目描述的是特定程序使用的资源,包括源代码文件
- IDE不用在项目列表中列出头文件,只需要管理使用的源代码文件
使用头文件
- 如果把main函数放在第一个文件里,把函数定义放在第二个文件里,那么第一个文件仍然要使用函数原型
- 把函数原型放在头文件中,就不用再每次使用函数文件时都写出函数的原型
- 程序中经常用C预处理定义符号常量,更好的办法是,把
#define
指令放进头文件,然后在每个源文件中使用#include
指令包含该文件即可 - 第一个程序清单包含main()函数,提供整个程序的组织结构,第二个函数清单包含支持的函数,假设这些函数在独立的文件中,最后还列出了头文件,包含了改程序中所有的自定义符号和函数原型
#include"hotel.h"
指令中的双引号表明被包含的文件位于当前目录中memu()
函数:测试scanf()的返回值来跳过非数值数据
查找地址:&运算符
- 指针是C语言最重要概念之一,用于储存变量的地址
- 一元&运算符给出变量的存储地址
- %p是输出地址的转换说明
指针简历
- 指针是一个值为内存地址的变量(数据对象)
间接运算符:*
假设已知:ptr = &bah
,使用间接运算符 * 找出储存在bah
中的值,也被称为解引用运算符
声明指针
- 类型说明符表明了指针所指向对象的类型,星号(*)表明声明的变量是一个指针