C语言-学习笔记 --《c primer plus》
Posted 水みず
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言-学习笔记 --《c primer plus》相关的知识,希望对你有一定的参考价值。
C语言
1. C语言基础
- 命名只能用字母、数字、下划线,名称第一位不能为数字。
- 函数包含:函数原型、函数调用、函数定义。 函数原型可以省略参数名,函数定义中不可以。
- 程序错误:语法错误、语义错误。
- 两个很大的数据相减,浮点数损失精度更多。因为任何一个区间内都存在无穷个实数,计算机的浮点数不能表示区间内的所有值。浮点数通常是实际值的近似值,例如,7.0可能被存储为6.9999。
- (1111)2=2**5 -1 二进制1111等于2的5次方减一。
- 100的16进制(%x)表示0x64,八进制(%o)0144。
- char grad=\'a\'; 用单引号框起来的是字符对应的ASCII码。" "双引号表示字符串。
- C语言中将字符常量视为int型,而非char型。char letter=\'B\';中B对应为66,存在32位存储单元中,现在grade截取后八位放在8为存储单元中。
- int 32位;float 32位,数值符号位1,指数位8(第一位为指数符号1),尾数位23,有6-7位有效数字。double b4位,符号1位,指数11位,尾数52位,有效数字15-16位。浮点型常量写法,如-1.56e3,3.4E5。没有后缀的浮点型,默认是double。
- C语言数值类型分为整数类型、浮点数类型。使用可移植类型可以保证数据类型位数是自己要求的位数,屏蔽掉不同系统的差异。一般包含精确宽度整数类型(C90)、最快最小宽度类型(C99、C11)。
- %zd z是修饰符、d是转换字符,修饰符不可以单独使用。
- ++a是a先加1再计算,a++是运算结束后加1。
- 形参中的char、short会自动升级成int,float会变成double。这是隐式类型装换,在使用时会自动进行裁切。主要是把所有的操作数转换为统一的长度,极大地简化了代码的生成,这样,压到堆栈中的参数都是同一长度的,所以运行时系统只需要知道参数的数目,而不需要知道它们的长度,是一种临时手段。
- 条件运算符(?: 三元运算符)比if else更简洁。
- 回显输入意味着用户输入的字符直接显示在屏幕上,无回显输入意味着击键后对应字符不显示。
- 可使用<符号重定向输入流,使用>符号重定向输出流。
- scanf 会把换行符留在输入队列。
- 递归每次调用都会创建一组变量,使用内存更多,且由于函数每次调用会花费时间,所以执行速度更慢,但在某些场景下解决更简单(如处理倒序)。
- C90不支持变长数组a[n](VLA,n为整型变量),C99支持VLA(不能使用static extern修饰),C11可选支持。
- 字符串初始化用指针与字符数组的区别:1、数组名是常量,而指针名是变量。2、初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针。建议在把指针初始化为字符串字面量时使用const限定符。3、不修改字符串,不要用指针指向字符串,需要修改字符串用字符数组。
- gets()、puts()在C11中被废弃,可用fgets()、fputs()、gets_s()(c11新增可选支持)替代。
2. 存储类别、链接和内存管理
- 存储期描述了通过标识符访问的对象的生存期。分为:静态存储期、线程存储期、自动存储期、动态分配存储期(malloc、calloc)。
- 静态存储期,它在程序执行期间一直存在。文件作用域变量具有静态存储期。块作用域变量也可以具有静态存储期,加上static即可。自动初始化为0。
- 线程存储期用于并发程序设计,具有线程存储期的变量,从被声明时到线程结束一直存在。用关键字 _Thread_local声明时,每个线程都有一个私有备份。
- 块作用域的变量通常具有自动存储期,进入这些块时,为这些变量分配内存,离开块时释放。
- 标识符用于访问对象(储存值的一块内存),可以用作用域、链接描述标识符的可见性。
- 作用域描述程序中可访问标识符的区域。分为块作用域、函数作用域、函数原型作用域和文件作用域。
- 链接分为:外部链接、内部链接、无连接。具有块作用域、函数作用域、函数原型作用域的变量都是无链接,是私有的。具有文件作用域的变量可以使外链接(默认extern)或者内部链接(static)。
- 自动变量是属于自动存储期的变量,具有自动存储期、块作用域且无链接。可显示使用auto(C++auto含义完全不同)。不会初始化。
- 寄存器变量同自动变量,不过是把变量放在寄存器中。不保证在寄存器中,无法获取地址,数据类型有限(寄存器位数有限)。
- 块作用域的静态变量,具有静态存储期的变量,用static声明。
- 外部链接的静态变量,具有文件作用域,外部链接和静态存储期。用extern声明,只能初始化一次且必须在定义时进行。
- C99和C11要求识别局部标识符的前63个字符和外部标识符的前31个字符。之前标准是前31和前6个。
- 内部链接的静态变量,具有静态存储期、文件作用域和内部链接。用存储类别说明符static声明。
- 存储类别说明符:auto、register、static、extern、_Thread_local、typedef。
- 函数也有存储类别,使用static说明函数为模块私有,可以解决命名冲突,默认是extern。
- 可以使用malloc、calloc(初始化为0)函数来自行分配内存,不过最后注意要free内存,防止内存泄漏。
- restrict,只能用于指针,表明该指针是访问数据对象的唯一且初始的方式。
- volatile限定符告知计算机,代理(其他程序)可以改变该变量的值。涉及到编译器的优化。
- _Atomic类型限定符,用在多线程中,声明原子类型的变量,C11可选支持。
3. 文件输入输出
- C把文件看作是一系列连续的字节,每个字节都能被单独处理。提供两种文件模式:文本模式、二进制模式。
- fopen()的模式字符串,r、w、a、x(C11)。getc(fp)、putc(fp)是从指定文件中获取一个字符。需要fclose()关闭。
- fseek()可以在打开的文件中,直接移动到任意字符。文件起始点模式有SEEK_SET、SEEK_CUR、SEEK_END。
- ftell()返回文件中当前位置。
- fgetpos()、fsetpos()是处理较大文件的新定位函数。
- fread()、fwrite(),在要求不损失精度的条件下保存和恢复值,用函数采用二进制模式进行读写。缺点:不同的操作系统可能使用不同的二进制表示法,所以数据文件可能具有不可移植性;甚至一个操作系统,不同的编译设置也会导致不同的二进制布局。
4.C预处理器和C库
- #define 来定义宏,包含明示常量、任何字符串、字符常量、类函数宏(宏带参数)、也可以为空,只做参数替换,不进行计算。替换部分可以用##将两个记号组合成一个记号、用#组合字符串、...与__VAR_ARGS__可用来自定义可变参数的宏,只能放在最后面。
- #include会查看后面的文件名并把文件的内容包含到当前文件中,即替换源文件的#include指令。
- 头文件中最常用的形式包含明示常量、宏函数、函数声明(函数原型)、结构模板声明、类型定义。
- #undef 用于取消已定义的#indefine指令,也就是取消已经定义的宏。
- 条件编译指令,#ifdef、#else、#endif,#ifdef max表示是否#define定义了MAX、或者包含了头文件,可以用来标记C语句块。与之相反的还有#ifndef、#else、#endif。主要用于防止多次包含头文件。
- #if、#elif与if、else if相似,后面跟整型常量表达式,如果表达式为非零,则表达式为真。
- 预定义宏:__DATE__,__FILE__,__LINE__,__STDC__,__STDC_HOSTED__,__STDC_version__,__TIME__,__func__。
- #line 重置__FILE__和__LINE__报告的文件名和行号。
- #error指令让预处理器发出一条错误信息,该消息包含指令中的文本。
- #pragma编译指示,用于控制分配给自动变量的内存量、设置错误检查严格程度、启用非标准语言特性等。
- _GENERIC泛型选择表达式,常用作#define宏定义的一部分。
- 内联函数(C99),标准规定具有内部链接的函数可以成为内联函数,最简单的使用方法是使用函数说明符inline和存储类别符。可以放在头文件中。因为是直接替换函数代码,所以可以避免函数调用的开销(建立调用、传递参数、跳转到函数代码并返回)。C99
- _Noreturn,这是第二个函数说明符,表明函数调用后,不返回主调函数。exit()和abort()都使用此声明。
- atexit(),在调用exit()退出时,调用最后注册的函数。
- assert(),接受一个整型表达式作为参数(一般为条件表达式、逻辑表达式),如果表达式为假(非零),assert()宏就在标准错误流(stderr)中写入一条错误信息,并调用abort()终止程序。可用#define NDEBUG禁用assert()。是在运行时检查。
- _Static_assert(),可以在编译时检查assert()表达式,可以让程序无法通过编译。可以出现在函数中。C11
- 在stdarg.h中,提供一些变参宏,即该宏可以接受可变数量的参数。包含有:va_start()、va_arg()、va_end()、va_copy()、va_list等。
5.高级数据表示
- 使用抽象数据类型方法编程:
- ADT(抽象数据类型),以抽象、通用的方式描述一个类型,包括该类型的操作。
- 设计函数接口表示这个新类型。
- 编写具体代码实现这个接口。
- 数组的优点:C直接支持、提供随机访问;缺点:在编译时确定大小、插入和删除很费时。
- 链表的优点:运行时确定大小、快速插入和删除元素;缺点:不能随机访问、用户必须提供编程支持。
- 随机访问表示同一时间访问一组序列中的一个随意组件。对数组而言,可以使用下标直接访问该数组中的任意元素。对链表而言,必须从首节点开始逐个移动到要访问到的节点,是顺序访问。
- 二叉查找树树是一种结合了二分查找策略的链接结构,是一种有序的二叉树。为了使左右子树更加平衡,可以使用AVL(平衡二叉树)。
以上是关于C语言-学习笔记 --《c primer plus》的主要内容,如果未能解决你的问题,请参考以下文章
《C++ Primer Plus》学习笔记 第1章 预备知识
C Primer Plus (第6版) 读书笔记_Chapter 1