- 翁恺老师的C语言课 神作 5
- c prime plus 大而全 5
首先以一个轻松的视频课程了解c,然后
PS:以下关于标准库的内容没有详细写,我不认为这些内容具有可概括性
c prime plus
正如它的书名所示,它很好地介绍了C语言的主要内容,并且颇有广度与深度,读这本书确实能让人受益匪浅 但是要注意还缺少几部分内容:
- C语言经验,这会在接下来的几本书当中补全
- C语言极深的细节,这不一定是有效的,但是如果你想要了解,也许只有阅读C标准
- C语言的的编译链接以及硬件层面的细节,在汇编语言,计算机系统基础,计算机组成原理与体系结构,编译原理这些内容中提及,但也许相当具体的内容需要了解编译器实现
初识c语言
- 选择c语言作为程序设计基础语言的原因/c语言的底层性,例如最接近汇编,指针有利于理解内存模型
- c语言的设计宗旨/自由与快 为了快可以牺牲移植性
- 程序设计步骤/不要忽视非编写的步骤,当你的程序变得复杂,它们显得格外重要
c语言概述
- 如题
ps:c语言6大基本语句,c将赋值也认为一种运算符表达式,声明不是表达式
数据与c
- 浮点型精度6/13
- 对字面量的修饰很重要 (警惕自动类型转换)
- 字符/'FATE'赋值等同于'E',因为''在c中往往是int型
- 转义字符可以直接加编码
- 字面量的默认类型int/double
- 刷新输出缓冲区 (满/遇到\n/需要输入)fflush()强制刷
字符串和格式化输入/输出
- sizeof类型必须加() 返回类型是lu/llu (比较时注意类型)
- printf修饰符 # (完全展示)
- c会将连续字符串融合
- 注意scanf()的读取过程/缓冲区中留下了什么
- *在pri中是限制宽度(读取一个参数),scan中是跳过
- 函数参数在栈中,根据类型读取长度,但是物理先后由实现决定
运算符 表达式与语句
- C标准中的数据对象/左值用于标识存储位置/对象定位值
- 除法趋零截断
- 只有共享运算对象时才考虑结合律/否则由编译器决定
- a%b等于a-(a/b)*b
- 不要在变量多次出现时使用++--,因为顺序不确定
- c只保证序列点之前完成副作用
PS:关于复合语句 (块),它的值是最后一个语句的值;但是它需要被()才是表达式
C控制语句:循环
- 浮点数比较不要使用==
- 非0即为真
- ==时常量放在左边
- 逗号表达式是一个序列点,先左后右
C控制语句:分支和跳转
- else与同层次的最近if配对,c规定最少支持127层if else
- && ||都是序列点
- break只跳出一层
- 仅在跳出多重循环时考虑使用goto
- stwich case必需全是整型,标签还得是常量
字符输入/输出和输入验证
- 完全缓冲 (缓冲区满才刷新,常见512/4096字节)与行缓冲 (遇见换行就刷新)
- 计算机用\n^z或者记录字节数来标记文件的结束但c全认为是EOF (常见-1)
- 用循环与验证来保证正确的输入
函数
- 尽量单一出口
- C函数是平等的
- 指针 值为地址的变量
- 程序了解名称与值,计算机了解地址与值
数组与指针
- 数组可以指定初始化{[]=6}
- 数组指定大小为变量将建立VLA
- 数组名是首元素的地址
- 在形参中加const避免修改
- const与*的相对位置决定效果
- VLA必须是auto的
- 复合字面量 (块生存周期)
字符串与字符串函数
- 字符串字面量是创建了一个字符串常量
- 读入字符串时留好位置
- 命令行参数 (main的参数)
存储类别 链接和内存管理
作用域
- 块,函数,函数原型,文件
- 仅有goto标签是函数作用域
- 仅有函数声明的变量名才有函数原型作用域int fun(int n,int m,int[n][m]);
- 文件作用域即全局变量 (按默认外部链接即本程序)
- static可以使文件作用域内部链接
存储期
- 静态,线程,自动,动态分配
- 文件作用域拥有静态存储期 (本程序)
- _Thread_local声明一个对象在每个线程有一个备份
- 块作用域有自动存储期但static可以让它有静态存储期
- register声明寄存器变量 (C尽力)
- 跨文件使用文件作用域的变量要用extern声明
- 函数声明默认带extern
内存形式
- 浮点数内部全是0不一定值为0
- 静态数据在一起,自动在一起 (栈),动态分配在一起 (内存堆)
- volatile 可由外部改变 (防一手编译器)
- restrict 仅由我 (一个指针)改变 (让编译器优化)
- _Atomic原子性,同时单一线程访问
- 形参中,int* const/restrict name==int name[const/restrict], int name[static 20]表明name中最少元素数 (给编译器优化)
文件输入/输出
- 文件模式与二进制模式,文件模式会映射例如\r\n->\n
- exit()在最初main中==return()
- FILE是一个放文件信息的结构,其实是假结构类似void*
- 可以用二进制IO在文件中保存数据对象,数据文件不可移植
结构和其他数据类型
- 结构也有初始化器 struct node n={.next=NULL}
- 结构可以自赋值
- 伸缩型数组成员,占用结构剩余的空间,这种结构不能初始化
- 常用匿名联合在结构中作为成员
- 复杂声明()[]优先级>*
位操作
- 掌握逻辑位运算的常见掩码套路
- 填充位段中的"洞"
- 使用0宽度的字段可以跳过这个int的剩下位
- _Alignof(type)得到对齐要求 _Alignas指定对齐要求
- stdaligned.h->alignas alignof(与c++相同)
- aligned_alloc(对齐要求,字节数) 分配内存
C预处理器和C库
- 翻译字符,物理行转为逻辑行,划分序列:记号,空白,注释,然后用" "替换注释
- 类对象宏与类函数宏展开
- 不可重定义同名宏
- 类函数宏注意替换后的运算优先级
#x
可以在替换体中的字符串中使用x这一个宏参数的字符串形式##
可以将记号粘合- 类函数宏的参数可以用... 再用__VA_ARGS__展开 #define A(x,...) printf(#x,
__VA_ARGS__
) - getchar putchar不是函数是宏
- ungetc是退回不是写入
- 宏作用域是本文件
#if defined (AAA)==#ifdef AAA
- _Generic(object,type:value,default)泛型选择
- inline fun ();
- _Noreturn type fun ()宣告不返回主调函数
- atexit()将函数指针记录,exit()会逆序调用这些函数
- assert(bool)若为假则打印err,停止程序 _Static_assert(bool,char*)若为假则打印字符串,无法编译
- type fun (type i,int parmN,...){ va_list ap; va_start(ap,parmN); type j=va_arg(ap,type); va_end(ap); }
高级数据表示
介绍与实现了一些ADT (抽象数据类型)与相应的简单算法
不在此记录