导图社区 C语言(2)
大一新生自学C语言弄出来的C语言总结,如果有什么错误或缺少的地方,恳请各位大佬指正。欢迎大家一起来学习!
编辑于2025-03-03 15:44:56C语言
问题
size_t类型是个什么玩意?
语句分为哪几类?
优点
能够直接访问硬件
设计特性
C是一门流行的语言,融合了计算机科学理论和实践的控制特性。 C语言的设计理念让用户能轻松地完成自顶向下的规划、结构化编程和模块化设计。因此,用C语言编写的程序更易懂、更可靠。
高效性
C是高效的语言。在设计上,它充分利用了当前计算机的优势,因此C程序相对更紧凑,而且运行速度很快。 实际上,C 语言具有通常是汇编语言才具有的微调控制能力,可以根据具体情况微调程序以获得最大运行速度或最有效地使用内存。
注:汇编语言是为特殊的中央处理单元设计的一系列内部指令,使用助记符来表示;不同的CPU 系列使用不同的汇编语言。
可移植性
C是可移植的语言。这意味着,在一种系统中编写的C程序稍作修改或不修改就能在其他系统运行。如需修改,也只需简单更改主程序头文件中的少许项即可。 从8位微处理器到克雷超级计算机,许多计算机体系结构都可以使用C编译器(C编译器是把C代码转换成计算机内部指令的程序)。 但是要注意,程序中针对特殊硬件设备(如,显示监视器)或操作系统特殊功能(如,Windows8或OSX)编写的部分,通常是不可移植的。 由于C语言与UNIX 关系密切,UNIX 系统通常 会将C编译器作为软件包的一部分。安装Linux 时,通常也会安装C编译器。 供个人计算机使用的C编译器很多,运行各种版本的Windows和Macintosh(即Mac)的PC都能找到合适的C编译器。 因此,无论是使用家庭计算机、专业工作站,还是大型机,都能找到针对特定系统的C编译器。
强大而灵活
C语言功能强大且灵活(计算机领域经常使用这两个词)例如,功能强大且灵活的UNIX操作系统,大部分是用C语言写的; 其他语言(如,FORTRAN、Perl、Python、Pascal、LISP、Logo、BASIC)的许多编译器和解释器都是用C语言编写的。 因此,在UNIX机上使用FORTRAN时,最终是由C程序生成最后的可执行程序。 C程序可以用于解决物理学和工程学的问题,甚至可用于制作电影的动画特效。
面向程序员
C语言是为了满足程序员的需求而设计的,程序员利用C可以访问硬件、操控内存中的位。C语言有丰富的运算符,能让程序员简洁地表达自己的意图。 C语言不像Pascal 甚至是C++那么严格。这样的灵活性既是优点也是缺点。 优点是,许多任务用C来处理都非常简洁(如,转换数据的格式); 缺点是,你可能会犯一些莫名其妙的错误,这些错误不可能在其他语言中出现。 C语言在提供更多自由的同时,也让使用者承担了更大的责任。 另外,大多数C实现都有一个大型的库,包含众多有用的C函数。 这些函数用于处理程序员经常需要解决的问题。
缺点
要享受用C语言自由编程的乐趣,就必须承担更多的责任。特别是,C语言使用指针,而涉及指针的编程错误往往难以察觉。C语言紧凑简洁,结合了大量的运算符。正因如此,我们也可以编写出让人极其费解的代码。
常识
K&R C
C语言发展之除并没有任何标准,直到出现了K&R C(经典C标准),但是只定义了C语言,没有定义C库。
美国国家标准协会(ANSI)与1983组建了一个委员会,开发了一套新的标准,与1989年正式发布。 该标准(ANSI C)定义了C语言和C标椎库,国际标椎化组织于1990年采用了这套标准。这就是C90标椎(业界人士也称ANSI C 标准)
C89/C90
最早的C语言标准,由美国国家标准学会(ANSI)和国际标准化组织(ISO)于1989年联合发布。
规定了C语言的基本语法、数据类型、运算符等,并定义了一个基本的标准库。
C99
1994年,由ANSI/ISO联合委员会开始修订C标准。
1999年,1994年对C语言的修订引出了ISO 9899:1999的发表,它通常被称为C99。
引入了新的语言特性,如单行注释、布尔类型、变长数组、复合字面量等。 此外,C99标准还增加了更多的库函数,包括对复数数学、格式化输入输出、浮点数环境等的支持。
C11
2011年,国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C语言标准委员会(ISO/IEC JTC1/SC22/WG14)正式发布了C11标准。
在C99的基础上进行了进一步改进,并引入了一些新的特性,如类型泛型、多线程支持、匿名结构体和联合体、对 Unicode 字符的支持等。C11还扩展了标准库,增加了新的头文件和函数,如对多线程编程的支持、原子操作、时间和日期处理等。
C17/C18
2018 年发布,是目前为止最新的 C 语言编程标准,用来修订 C11 标准。
没有引入新的语言特性,只对 C11 进行了补充和修正。
一个C语言程序由一个或多个源程序文件组成
一个源程序文件由以下三个部分组成
预处理指令
C编译系统在对源程序进行“翻译”以前,先由一个预处理器(也称预处理程序、预编译器)对预处理指令进行预处理。
例:#include <stdio.h>
#include<stdio.h>的作用相当于把stdio.h文件中的所有内容都输入该行所在的位置。 实际上,这是一种“拷贝-粘贴”的操作。include 文件提供了一种方便的途径共享许多程序共有的信息。
由预处理得到的结果与程序其他部分一起,组成一个完整的、可以用来编译的最后的源程序,然后由编译程序对该源程序正式进行编译,才得到目标程序。
全局变量
在函数之外进行的数据声明。
函数定义
函数是C程序的主要组成部分,是C程序的基本单位。程序的几乎全部工作都是由各个函数分别完成的, 在程序中,每个函数都用来实现一个或几个特定的功能。编写C程序的工作主要就是编写一个个函数。
一个C语言程序是由一个或多个函数组成的,其中必须包含一个 main函数(且只能有一个main 函数)。
一个函数包括两个部分。
函数首部。即函数的第1行,包括函数名、函数类型、函数属性、函数参数(形式数)名、参数类型。一个函数名后面必须跟一对圆括号,括号内写函数的参数名及其类型。 如果函数没有参数,可以在括号中写void,也可以什么都不写。
函数体。即函数首部下面的花括号内的部分。 如果在一个函数中包括有多层花括号,则最外层的一对花括号是函数体的范围。
声明部分:定义在本函数中所用到的变量。
执行部分。由若干个语句组成,指定在函数中所进行的操作。
注:在某些情况下也可以没有声明部分,甚至可以既无声明部分也无执行部分。
注:每个C程序都一定会包含一个且只有一个main函数,每一次c程序运行时都一定会从main函数开始运行。
文件名的含义
用C语言编写程序时,编写的内容被存储在文本文件中,该文件被称为源代码文件(source code file)。大部分C系统,都要求文件名以.c结尾(如,wordcount.c和budget.c)。
在文件名中,点号(.)前面的部分称为基本名(basename),点号后面的部分称为扩展名(extension)。因此,budget是基本名,c是扩展名。基本名与扩展名的组合(budget.c)就是文件名。
文件名应该满足特定计算机操作系统的特殊要求。 例如,MS-DOS是IBM PC及其兼容机的操作系统,比较老旧,它要求基本名不能超过8个字符。因此,刚才提到的文件名wordcount.c就是无效的DOS 文件名。 有些UNIX系统限制整个文件名(包括扩展名)不超过14个字符,而有些UNIX系统则允许使用更长的文件名,最多255个字符。Linux、Windows和Macintosh OS都允许使用长文件名。
C语言编程原理
C编程的基本策略是,用程序把源代码文件转换为可执行文件(其中包含可直接运行的机器语言代码)。 典型的C实现通过编译和链接两个步骤来完成这一过程。编译器把源代码转换成中间代码,链接器把中间代码和其他代码合并,生成可执行文件。C使用这种分而治之的方法方便对程序进行模块化,可以独立编译单独的模块,稍后再用链接器合并已编译的模块。通过这种方式,如果只更改某个模块,不必因此重新编译其他模块。另外,链接器还将你编写的程序和预编译的库代码合并。中间文件有多种形式。我们在这里描述的是最普遍的一种形式,即把源代码转换为机器语言代码,并把结果放在目标代码文件(或简称目标文件)中(这里假设源代码只有一个文件)。虽然目标文件中包含机器语言代码,但是并不能直接运行该文件。因为目标文件中存储的是编译器翻译的源代码,这还不是一个完整的程序。 目标代码文件缺失启动代码(startup code)。
启动代码充当着程序和操作系统之间的接口。例如,可以在MS Windows或Linux系统下运行IBMPC兼容机。这两种情况所使用的硬件相同,所以目标代码相同,但是 Windows和Linux 所需的启动代码不同,因为这些系统处理程序的方式不同。目标代码还缺少库函数。几乎所有的C程序都要使用C标准库中的函数,例如,concrete.c中就使用了printf()函数。目标代码文件并不包含该函数的代码,它只包含了使用printf()函数的指令。printf()函数真正的代码存储在另一个被称为库的文件中。库文件中有许多函数的目标代码。链接器的作用是,把你编写的目标代码、系统的标准启动代码和库代码这3部分合并成一个文件,即可执行文件。对于库代码,链接器只会把程序中要用到的库函数代码提取出来(见图1.4)。
简而言之,文件和可执行文件都由机器语言指令组成的, 但目标文件中只包含编译器为你编写的代码翻译的机器语言代码, 可执行文件中还包含你编写的程序中使用的库函数和启动代码的机器代码。在有些系统中,必须分别运行编译程序和链接程序, 而在另一些系统中,编译器会自动启动链接器,用户只需给出编译命令。
C Primer Plus图1-4
从源文件到可执行文件的过程
预处理:test.c→test.i
预处理器将源文件(.c文件)进行预处理,生成预处理后的文件(.i文件)。
宏替换
头文件展开
条件编译
处理其他预处理指令#pragma等
去注释
编译:test.i→test.s
编译器将预处理后的文件(.i文件)进行词法分析、语法分析、语义分析以及优化,生成汇编文件(.s文件)。
汇编:Linux:test.s→test.o / Windows:test.s→test.obj
汇编器将汇编文件(.s文件)根据汇编指令与机器指令的对照表进行翻译,生成目标文件(.o/.obj文件),即机器可以识别的二进制文件。
链接:Linux:test.o→test.out / Windows:test.obj→test.exe
链接器将多个目标文件(.o/.obj文件)和库文件进行链接,生成可执行文件(.out/.exe文件)。
库文件
库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库, 它提供给使用者一些可以直接拿来用的变量、函数或类。
库是特殊的一种程序,编写库的程序和编写一般的程序区别不大, 只是库不能单独运行。
静态库
静态库在程序的链接阶段被复制到了程序中
命名规则:
Linux:libxxx.a
Windows:libxxx.lib
Linux下静态库的制作:
gcc获得.o文件 gcc -c a.c b.c
将.o文件打包,使用ar工具(archive) ar rcs libxxx.a a.o b.o
优点:
静态库被打包到应用程序中加载速度快。
发布程序无需提供静态库,移植方便。
缺点:
消耗系统资源,浪费内存。
更新、部署、发布麻烦。
动态库(共享库)
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。
命名规则:
Linux:libxxx.so
Windows:libxxx.dll
Linux下动态库的制作:
gcc获得.o文件,得到和位置无关的代码 gcc -c -fpic/-fPIC a.c b.c
gcc得到动态库 gcc -shared a.o b.o -o libxxx.so
优点:
可以实现进程间资源共享(共享库)。
更新、部署、发布简单。
可以控制何时加载动态库。
缺点:
加载速度比静态库慢。
发布程序时需要提供依赖的动态库。
静态库、动态库区别来自链接阶段如何处理,链接成可执行程序。分别称为静态链接方式和动态链接方式。
库的好处:1. 代码保密;2. 方便部署和分发。
预处理指令
#define指令定义一个宏定义
#undef指令删除一个宏定义
#include指令导致一个指定文件的内容被包含到程序
#include <文件名>
子主题用于属于C语言自身库的头文件
先搜寻当前目录,然后搜寻系统头文件所在的目录(或多个目录)
#include "文件名"
用于所有其他头文件,也包含任何自己编写的文件
先搜寻当前目录,然后搜寻系统头文件所在的目录(或多个目录)
#if、#ifdef、#ifndef、#elif、#else和#endif指令可以根据预处理器可以测试的条件来确定是将一段文本块包含到程序中还是将其排除在程序之外。
#error、#line、#pragma
注:指令都以#开始
#符号不需要在一行的行首,只要它之前只有空白字符就行。在#后是指令名,接着是指令所需要的其他信息。
在指令的符号之间可以插入任意数量的空格或水平制表符
指令总是在第一个换行符处结束,除非明确地指明要延续
如果想在下一行延续指令,我们必须在当前行的末尾使用'\'字符。
指令可以出现在程序中的任何地方
但我们通常将#define和#include指令放在文件的开始,其他指令则放在后面,甚至可以放在函数定义的中间。
注释可以与指令放在同一行
实际上,在宏定义的后面加一个注释来解释宏的含义是一种比较好的习惯。
头文件的定义
#include指令告诉预处理器打开指定的文件,并且把此文件的内容插入到当前文件中。 因此,如果想让几个源文件可以访问相同的信息, 可以把此信息放入一个文件中,然后利用#include指令把该文件的内容带进每个源文件中。 把按照此种方式包含的文件称为头文件(有时称为包含文件),头文件的扩展名为.h。
内置
编译器自带的类型
计算机表示内存大小的单位
bit(位)(比特)
byte(字节)
半字
word(字)
双字
KB
MB
G
T
1T=1024G=1024^2MB=1024^3KB=1024^4bit
1双字=2字=4半字=8字节=64bit
记数法
数字
1000000000
123000
322.56
0.000056
科学记数法
1.0×10^9
1.23×10^5
3.2256×10^2
5.6×10^-5
指数记数法(e记数法)
1.0e9
1.23e5
3.2256e2
5.6e-5
进制
0x或0X前缀表十六进制
0前缀表八进制
%x或%X数字以十六进制显示
%o数字以八进制显示
%d数字以十进制显示
若要显示各进制前缀,则必须分别使用%#o、%#x、%#X。
标识符命名规则
可以用小写字母、大写字母、数字和下划线_来命名。 而且名称的第1个字符必须是字母或下划线,不能是数字。
C语言的名称区分大小写,即把同一个字母的大小和小写区分为两个不同的字符❤️
同一条声明可声明多个变量
等价
int feet,fathoms;
int feet; int fathoms;
声明
引用性声明(声明) (referncing declaration)
不需要建立存储空间的。
例:extem int a其中变量a是在别的文件中定义的。
定义性声明(定义) (defining declaration)
需要建立存储空间的。
例:int a在声明的时候就已经建立了存储空间。
初始化
初始化在计算机编程领域中指为数据对象或变量赋初值的做法。
函数传参顺序:从右到左
转义字符
转义字符(Escape character),所有的ASCII码都可以用“\”加数字(一般是8进制数字)来表示。而C语言中定义了一些字母前加""来表示常见的那些不能显示的ASCII字符,如\0,\t,\n等,就称为转义字符;
\0 空字符(NULL) 在c语言中代表“字符串结束符”
\a 警报符(alert) 发出听觉或视觉上的警报
\b 退格符(backspace) 将当前位置移到前一列
\f 换页符(form feed) 换页,将当前位置移到下一页开头
\n 换行符(new line) 换行,将当前位置移到下一行开头
\r 回车符(carriage return) 将当前位置移到本行开头
\t 水平制表符(horizontal tab) 将当前位置移动到下一个水平制表位置
\v 垂直制表符(vertical tab) 将当前位置移动到下一个垂直制表位置
\\ 字符\
\? 字符 ?
\’ 字符 ’
\" 字符 "
注:转义字符虽然由两个及两个以上的字符构成,但它表示的却是单个字符
注:转义字符及其作用如图3-1
C程序设计3-1
把书拿回来后,把图片换一下❤️❤️
二元运算需要三个元素:二元运算符以及该运算符作用的两个变量。
位操作
保留
原样不动
清零
全部为0
置位
全部为1
取反
1变0,0变1
对C语言来说,真为1假为0
EOF意思是end of file,本质上是-1。
一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。
内嵌的循环中还可以嵌套循环,这就是多层循环。
各种语言中关于循环的嵌套的概念都是一样的。
单撇号'内为单个字符',双撇号"内为多个字符"。
程序的错误被称为bug
找出并修正程序的错误的过程叫做调试
文件
文件名包含3部分:文件路径+文件名主干+文件后缀
注:文件的后缀名决定了一个文件的默认打开方式。
注:文件路径指的是从盘符到该文件所经历的路径中各符号名的集合。
例: c:\code\mycode\test.txt
这里的c:\code\mycode\就是文件路径,test就是文件名主干,.txt就是文件后缀。
程序文件
子主题
注:后缀为.c
目标文件
注:windows环境后缀为.obj
可执行程序
windows环境后缀为.exe
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
步长:地址属性。做加1操作需移动的字节数
位宽:所占的内存大小,实质为有多少个二进制数字。
数据溢出:溢出的本质是数据二进制的长度超出了对应数据类型的内存大小。
程序会自动将超出内存大小的二进制值抹去。
大于最大值,叫做向上溢出(overflow);小于最小值,叫做向下溢出(underflow)。
2^16=6,5536
2^32=42,9496,7296
2^64=1844,6744,0737,0955,1616
注意事项
注意编码规范
注意变量的可读性,尽量不要使用例如单个字母的命名方式,除非是循环变量。
注释书写规范
/*注释*/
结束符号可以放在任何位置
//注释//
结束符号必须与开始符号在同一行
注:当注释符号出现在字符串中时,被视为是字符串的一部分。
先定义,后初始化,有需要再声明。
定义:数据类型 变量名
创建一个变量
初始化:数据类型 变量名1 = 常量
给变量赋值
注:可以在没有定义的情况下,直接初始化,会自动创建一个变量并赋值。
声明:extern 数据类型 变量名
告诉编译器有这个变量。
注:变量必须已经被创建
在每个数据声明和语句的最后必须有一个分号。
编写C语言的过程
1.定义程序的目标
在脑中构想出程序应实现的效果。
2.设计程序
具体想想怎样实现效果,程序该分为哪几个部分,每个部分又该有什么样的功能。
3.编写代码
编写代码将功能实现。
4.编译
经过编译,将代码翻译成机器语言。
5.运行程序
运行程序看看效果。
6.测试和调试程序
用多种不同的方法和手段测试,看看程序能否达到想要的效果。
7.维护和修改程序
根据自己的需要修改程序。
在执行交互式程序时,当你使用键盘输入信息后,必须敲一下Enter或Return键,来告诉程序该进行下一步了。
变量
局部变量
字节长度
随数据类型
生命周期
局部变量:所在函数体执行时,分配空间,执行结束,释放空间
作用域
所在函数可用
存储区域
栈空间
全局变量
字节长度
随数据类型
生命周期
全局变量:所在程序执行时,分配空间,执行结束,释放空间
作用域
从其定义开始到文件结尾
注:在声明之上的函数需要extern外部声明
存储区域
数据段
注:若局部变量和全局变量同名,则在局部变量有效范围内,以局部变量为主。
数据类型
基本(内置)数据类型
int(基本整型)
short int(短整形)
long int(长整形)
long long int(长长整形)(C99)
signed(前缀)
有符号:意为储存其中的值只能是正数。
例:signed short int的范围为0~2^16
注:signed、int可省略
unsigned(前缀)
无符号:意为储存其中的值可以为负数。
例:unsigned short int的范围为-2^8~2^8
注:int可省略
注:int可省略
注:C标准没有具体规定各种类型数据所占用存储单元的长度,这是由各编译系自行决定的。
char(字符型)
字符型数据是以字符的ASCII代码存储在存储单元中的,一般占一个字节。
由于ASCI代码也属于整数形式,因此在C99标准中,把字符类型归纳为整型类型。
_Bool int(布尔值)
在编程中,表示真或假的变量被称为布尔变量(Boolean variable),所以_Boo1是C语言中布尔变量的类型名。
_Boo1类型的变量只能存储1(true)(真)或0(false)(假)。 如果把其他非零数值赋给_Boo1类型的变量,该变量会被设置为1。
要在 C 中使用 bool,必须包含头文件“stdbool.h”。
float(单精度浮点型)
至少能表示六位有效数字,且取值范围至少是-3.4*10^-38∽3.4*10^38。
double(双精度浮点型)
至少能表示十五位有效数字,取值范围为-1.5*10^-308~1.5*10^308。
long double(长双精度浮点型)
表示的有效数字比double多,取值范围比double厂。
复数浮点形
float_Complex(复数类型)
float_Complex 类型的变量应包含两个float类型的值,分别表示复数的实部和虚部。
double_Complex(复数类型)
long double_Complex(复数类型)
float_Imaginary(虚数类型)
double_Imaginary(虚数类型)
long double_Imaginary(虚数类型)
size_t(无符号整数类型)
注:unsigned表有符号类型(全集),singned表无符号类型(正整数集)
派生数据类型
指针类型(*)
指针
指针是一种数据类型,它可以定义变量,变量保存的值是地址,由于地址是固定长度,所以指针变量的长度是固定长度, 由于不同地址的步长不一样,所以要不同指针类型的变量来保存
直接操作硬件的寄存器地址,从而实现直接访问硬件。
注:const修饰的指针,const在*左表示指针指向的内容不可修改,const在*右表示指针的指向不可修改。
格式
数据类型 * 变量名1 = &变量名2
“变量名1”是指向“数据类型”变量的指针。
把变量名2的地址赋给变量名1。
多级指针
层层转包,单线联系
n级指针
数据类型 (n个*) 变量名1 = (相同的)数据类型 (n-1个*) 变量名2
注:一级指针保存变量的地址,二级以上指针只能保存前一级指针的地址。
注:只有在多级指针前面加上对应多的“*”运算符才能取到最初变量保存的值,不然取到的就只是对应级指针的地址。
设a、b、c、d、e,分别为一/二/三/四/五级指针,int i = 2;int * a = &i; int ** b = &a;……;int ***** e = &d;
*e获取d的地址,**e获取c的地址,***e获取b的地址,****e获取a的地址,*****e获取i的变量值。
字符指针
和字符串指针是一个意思,只是偏向强调的重点不同, 字符指针强调指向的是一个字符的地址, 而字符串指针强调的是指向一个字符串的首字符的地址。
字符串指针
指向一个字符串的首字符的地址。
注:指针指向的值保存在数据段的or段,该数据不可被修改。
万能指针
void *
可以接收任何类型指针的地址
注:想要对void类型指针变量进行解引用,就要将void类型指针变量进行强制类型转换,从void*强制转换为这个指针中存储的地址指向的值的类型。
文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息 (如文件的名字,文件状态及文件当前的位置等)。 这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE。
格式
FILE* 指针名
注:stdio.h头文件把3个文件指针与3个标准文件相关联,C程序会自动打开这3个标准文件。
标准文件
标准输入
标准输出
标准错误
文件指针
stdin
stdout
stderr
通常使用的设备
键盘
显示器
显示器
数组类型([])
数组
数组(array)是按顺序存储的一系列类型相同的值,是一组有序数据的集合。
数组的元素被依次存储在内存中相邻的位置。
用一个数组名来代表整个数组
用于识别数组元素的数字被称为下标、索引或偏移量。下标必须是整数,而且要从0开始计数。
用一个数组名和下标来唯一地确定数组中的元素,
由于计算机键盘只能输入有限的单个字符而无法表示上下标,C语言规定用方括号中的数字来表示下标。
数组格式
数据类型 数组名[数组长度]
数据类型 字符[数字或常量表达式]
调用格式
数组名[下标]
数组名[数字或常量表达]
注:定义数组时用到的“数组名[数组长度]”和引用数组元素时用的“数组名[下标]”形式相同,但含义不同。
数组长度从1开始,下标从0开始。
多维数组
二维数组
格式
数据类型 数组名[数字1][数字2]
一个“数组名”大数组中包含“数字1”个小数组,而每个小数组又都能包含“数字2”个变量。
三维数组
格式
数据类型 数组名[数字1][数字2][数字3]
一个“数组名”大数组中包含“数字1”个中数组,而每个中数组又都能包含“数字2”个小数组,而每个小数组又都能包含“数字3”个变量。
……
…
…………
………………………
变长数组 VLA
C99允许数组的[ ]中的值是整形变量或是整形表达式。
注:变长数组是指用整型变量或表达式声明或定义的数组,而不是说数组的长度会随时变化,变长数组在其生存期内的长度同样是固定的。
注:变长数组不等于动态数组,本质还是静态数组,也就是说,数组的长度在变量的整个生命周期中是不可变的
注:变长数组只能是局部变量数组
注:变长数组不能在定义的时候进行初始化
例:int n; scanf("%d",&n); int aaa [n];
注:变长数组必须是自动存储类别,即不能使用extern或static存储类别说明符
注:由于变长数组只能是局部变量,且必须是自动存储类别,因此变长数组分配在栈上
注:可变长数组对于多维数组也适用(如array[a][b] )
注:需编译器支持此特性
注:VS系列编译器均不支持该特性
字符数组
用来存放字符数据的数组是字符数组。在字符数组中的一个元素内存放一个字符。
定义
char c[] ={'I',' ', 'a','m',' ','h','a','p','p','y','/0'}
char c[]={"I am happy"}
注:花括号可省略
注:用字符数组存放字符串
注:由于字符型数据是以整数形式(ASCII代码)存放的,因此也可以用整型数组来存放字符数据,但比较浪费存储空间。
字符串
由多个字符组成,其末尾通常隐藏/0。
凡是指向或保存字符串地址的,其指向或保存的都是字符串首字符的地址。
注:C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符型数组中的。
在C语言中,是将字符串作为字符数组来处理的。
在实际工作中,人们关心的往往是字符串的有效长度而不是字符数组的长度。例如,定义一个字符数组长度为100,而实际有效字符只有40个。为了测定字符串的实际长度,C语言规定了一个“字符串结束标志”,以字符’0'作为结束标志。如果字符数组中存有若干字符,前面9个字符都不是空字符('o'),而第10个字符是个0',则认为数组中有一个字符串,其有效字符为9个。也就是说,在遇到字符N0'时,表示字符串结束,把它前面的字符组成一个字符串。注意:C系统在用字符数组存储字符串常量时会自动加一个0'作为结束符。例如Cprogram"共有9个字符。字符串是存放在一维数组中的,在数组中它占10个字节,最后
注:数组名是指针变量,保存数组首元素的地址。
注:数组中的每一个元素都属于同一个数据类型,不能把不同类型的数据放在同一个数组中。
结构体类型(struct)
共用体类型(union)
函数类型
函数类型用来定义函数,描述一个函数的接口,包括函数返回值的数据类型和参数的类型。
基本类型(包括整型和浮点型)和枚举类型变量的值都是数值,统称为算术类型(arithmetic type)。
算术类型和指针类型统称为纯量类型(scalar type),因为其变量的值是以数字来表示的。
数组类型和结构体类型统称为组合类型(aggregate type)
共用体类型不属于组合类型,因为在同一时间内只有一个成员具有值。
enum(枚举类型)
枚举类型是程序中用户定义的整数类型。
void(空)类形
无返回值
注:不同类型的数据在内存中占用的存储单元长度是不同的。
注:数据类型相互转换方法
在变量前面加上一个数据类型名,并用小括号将这个类型名括起来。
如:c=(unsigned long)a*b
注:强制类型转换运算符优先级高于算术运算符
注:隐式类型转换
char→short→int→long→float→double
限定符
const
限定一个变量为只读 (可调用,但不能改变)。
注:在C语言中,用const类型限定符声明的是变量,不是常量。
volatile
直接存取原始内存地址
例:volatile int a
确保本条指令不会被编译器的优化而忽略。
volatile对应的变量可能在你的程序本身不知道的情况下发生改变
比如多线程的程序,共同访问的内存当中,多个程序都可以操纵这个变量
你自己的程序,是无法判定何时这个变量会发生变化
还比如,他和一个外部设备的某个状态对应,当外部设备发生操作的时候, 通过驱动程序和中断事件,系统改变了这个变量的数值,而你的程序并不知道。
对于volatile类型的变量,系统每次用到他的时候都是直接从对应的内存当中提取, 而不会利用cache当中的原有数值,以适应它的未知何时会发生的变化, 系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。
关键字
K&R C
auto
break
case
char
数据类型:字符型
continue
default
do
double
数据类型:双精度浮点型
else
extern
声明这个变量(函数),告诉编译器在外部文件中已经这个变量(函数),要通过编译。
float
数据类型:单精度浮点型
for
goto
if
int
数据类型:整型
long
数据类型:长整型
register
修饰变量作为一个寄存器变量,让该变量的访问速度达到最快。
例:register int a
寄存器变量是指一个变量直接引用寄存器, 也就是对变量名的操作的结果是直接对寄存器进行访问。
注:待声明为寄存器变量的类型应该是CPU寄存器所能接受的类型,寄存器变量是单个变量,变量长度应该小于等于寄存器长度。
注:不能对寄存器变量使用取地址符“&”,因为该变量没有内存地址。
注:尽量在大量、频繁操作时使用寄存器变量,且声明的变量个数应该尽量少。
注:该关键字,现在已经不会有人在使用了,因为现在的编译器已经很智能了,能够进行比人更好的代码优化(会自动识别给需要的变量加上 register )。 早期编译器需要人为指定register,来进行手动优化,现在不需要了。
restrich
return
short
数据类型:短整型
sizeof
计算变量(或数据类型)在当前系统中占用内存的字节数
格式
sizeof(参数1)
注:后面的括号可以省略
注:既是运算符,又是关键字
static
注:在函数中声明变量时, static 关键字指定变量只初始化一次,并在之后调用该函数时保留其状态。
注:在声明变量时,变量具有静态持续时间,并且除非您指定另一个值。
注:static关键字没有赋值时,默认赋值为 0
注:在全局和/或命名空间范围(在单个文件范围内声明变量或函数时)static关键字指定变量或函数为内部链接,即外部文件无法引用该变量或函数。
注:全局变量和函数本身是具有外部链接属性的,在Hello.c文件中定义的全局变量和函数, 在test.c文件中可以通过【链接】来使用;
但如果全局变量被static修饰,那这个外部链接属性就会被修改成内部链接属性,此时这个全局变量就只能在自己的源文件中使用;
注:如果加了static,就会对其它源文件隐藏。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。 static可以修饰函数和变量,将其对其他源文件隐藏起来,从而避免命名冲突。对于函数来讲,static的作用仅限于该隐藏功能。
struct
switch
typedef
给数据类型重命名
例:typedef unsignsd long int UNIT
将unsignsd long int类型命名为UNIT
好处
解决编译器默认有无符号移植性问题
提高代码可读性
提高编码效率
为程序进行加密
union
unsigned
数据类型(前缀):无符号
while
C89
const
enum
signed
数据类型(前缀):有符号
void
数据类型:空
volatile
C99
inline
C11
_Alignas
_Alignof
_Atomic
_ Bool
数据类型:布尔型
_Complex
数据类型:复数
_Generic
_Imaginary
数据类型:虚数
_Noreturn
_Static_assert
_Thread_local
运算符
sizeof
计算变量(或数据类型)在当前系统中占用内存的字节数
既是运算符,又是关键字
基本算术运算符
+
一元
标明或改变一个值的代数符号(正负)
二元
加法运算符
使其两侧的值相加
-
一元
标明或改变一个值的代数符号(正负)
二元
减法运算符
左侧的数减去右侧的数
*
一元
间接(解引用)(间接寻址)运算符
给出存储在指针指向地址上的值
设int pooh = 5,ptr = &pooh, val = *ptr,则val = pooh = 5
二元
乘法运算符
使其两侧的数相乘
/
除法运算符
左侧的数除以右侧的数
在C语言中,整数除法结果的都分被丢弃,这一过程被称为截断(truncation)。
%
求模运算符
给出左侧整数除以右侧整数的余数
只能用于整数
++
递增(自加)运算符
将其运算对象递增(自加)1
只有圆括号的优先级比其高
“++变量名”和“变量名++”的区别
在打印过程中“++变量名”被替换成变量名,“变量名++”被替换成变量的值
“++变量名”先加,也就是说,他先把传到自身的数加1, 再把自身的数传播给下一个数,其自身的数比传到自身的数多1。
“变量名++”后加,也就是说,他把传到自身的数直接传给下一个数, 只是在传到下一个数的前一瞬间才加1,其自身的数和传到自身的数一样。
--
递减(自减)运算符
将其运算对象递减(自减)1
只有圆括号的优先级比其高
“--变量名”和“变量名--”的区别
在打印过程中“--变量名”被替换成变量名,“变量名--”被替换成变量的值
“--变量名”先减,也就是说,他先把传到自身的数减1, 再把自身的数传播给下一个数,其自身的数比传到自身的数少1。
“变量名--”后减,也就是说,他把传到自身的数直接传给下一个数, 只是在传到下一个数的前一瞬间才减1,其自身的数和传到自身的数一样。
运算符优先级如图1-5-1
C Primer Plus图1-5-1
pow
指数运算符
例:pow(a,b):返回a的b次幂
赋值运算符
=
将右边的值赋给左边
在C语言里,“=”代表赋值,而不是等于❤️
复合算术赋值
+=
x+=y代表x=x+y
-=
x-=y代表x=x-y
*=
x*=y代表x=x*y
/=
x/=y代表x=x/y
%=
x%=y代表x=x%y
复合位运算赋值
&=
x&=y代表x=x&y
|=
x|=y代表x=x|y
^=
x^=y代表x=x^y
>>=
x>>=y代表x转换为二进制后右移y位,结果赋值给x并输出
如x = 2 x >>= 3
结果x = 16
<<=
x<<=y代表x转换为二进制后左移y位,结果赋值给x并输出
如x = 16 x <<= 3
结果x = 2
所有的位运算都先将数值转化为二进制, 在运算完成后再将数值转化为原来的进制。 (无转换要求情况下)
在c语言里,为了语法的简单性,推出了一系列的组合运算符,但核心的思想都是:左边和右边的变量做运算,结果存入左边变量。
关系运算符
>
大于
<
小于
!=
不等于
==
等于
>=
大于等于
<=
小于等于
注:上述符号的意思都是判断,当满足符号意思时,则运行符号语句, 不满足符号意思时则跳过符号语句。
逻辑运算符
&&
逻辑与,F=A&&B。当A、B的值都为真(即非0值,下同)时,其运算结果F为真(具体数值为1,下同); 当A、B值任意一个为假(即0,下同)时,结果为假(具体数值为0,下同)。
||
逻辑或,F=A||B。当A、B值任意一个为真时,其运算结果F为真;当A、B值都为假时,结果F为假。
!
逻辑非,F=!A。当A值为假时,其运算结果F为真;当A值为真时,结果F为假。
位运算符
&
一元
给出变量的存储地址
如果 pooh是变量名, 那么&pooh是变量的地址。
二元
按位与,F=A&B。将A、B两个字节中的每一位都进行与运算,再将得到的每一位结果组合为总结果F。
与运算:当两个参与运算的数中有一个数为0,则运算结果为0,都为1结果为1
A=0b11001100 B=0b11110000 F=0b11000000
|
按位或,F=A|B,将A、B两个字节中的每一位都进行或运算,再将得到的每一位结果组合为总结果F。
或运算:当两个参与运算的数中有一个数为1,则运算结果为1,都为0结果为0
A=0b11001100 B=0b11110000 F=0b11111100
~
按位取反,F=~A。将A字节内的每一位进行非运算(就是取反),再将得到的每一位结果组合为总结果F。
非运算:非运算的结果只有两个,非0得1,非(非0)得0, 即:非假即真,非真即假。0表示假,只要不是0的数都表示真
A=0b11001100 F=0b00110011
注:运算优先级是非—>与—>或
^
按位异或。F=A^B。异或的意思为,如果运算双方的值不同(即相异),则结果为真,双方值相同则结果为假。
在C语言里没有按变量整体值进行的异或运算,故仅以按位异或为例。
A=0b11001100 B=0b11110000 F=0b00111100
<<
左移
>>
右移
条件运算符
?:
格式:×=( y < 0 ) ? - y : y ;
在=和;之间的内容就是条件表达式,该语句的意思是“如果y小于0,那么x=-y;否则x=y”。
逗号运算符
,
逗号运算符把两个表达式连接成一个表达式,并保证最左边的表达式最先求值。
逗号运算符可以用于在一个语句中计算多个表达式的值,并返回最右边表达式的值。
如图0-0-1
在循环和条件语句中,逗号运算符可以用于简化控制流程。
如图0-0-2
逗号运算符可以在函数调用时传递多个参数,特别是在参数数量不确定的情况下。
如图0-0-3
指针运算符
&
给出变量的存储地址
如果 pooh是变量名, 那么&pooh是变量的地址。
*
间接(解引用)(间接寻址)运算符
给出存储在指针指向地址上的值。
设int pooh = 5;int * ptr = &pooh;int val = 0;运行val = *ptr,则val = pooh = 5。
函数
子主题完成特定任务的独立程序代码单元。语法规则定义了函数的结构和使用方式。
格式
返回值类型 函数名 (形式参数列表) { 函数体 }
在程序中,函数名一般会在三种途径被使用
程序开头函数的声明
函数的调用
函数的定义
在调用一个有参数的函数时,函数名后边括号中的参数叫作实际参数,简称实参。而被调用的函数在进行定义时,括号里的参数叫作形式参数,简称形参。
函数定义中指定的形参为局部变量,在未发生函数调用时不占内存, 只有函数调用时,函数中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。
形参必须指定数据类型,和定义变量一样,因为它本来就是局部变量。
主调函数在调用函数之前,应对被调函数做原型声明。
实参可以是常量,也可以是简单或者复杂的表达式,但是要求它们必须有确定的值, 在调用发生时将实参的值传递给形参。
实参和形参的数据类型应该相同或者赋值兼容。 和变量赋值一样, 当形参和实参出现不同类型时,按照不同类型数值的赋值规则进行转换。
实参向形参的数据传递是单向传递,不能由形参再回传给实参。 也就是说,实参值传递给形参后,调用结束,形参单元被释放,而实参单元仍保留并且维持原值。
注:各种函数格式中的size_t、int、void*等前缀都是为了方便理解,在实际操作中是不会写出来的。
C89
assert.h断言
仅包含assert宏,它允许我们在程序中插入自我检查。一旦任何检查失败,程序就会被终止。
ctype.h字符串分类
提供用于字符分类及大小写转换的函数。
errno.h错误码
提供了errno(“error number”)。errno是一个左值(lvalue),可以在调用特定库函数后进行检测,从而判断调用过程中是否有错误发生。
float.h浮点数宏定义
定义了与浮点数类形相关的宏。这些宏提供了浮点数的特性和限制,例如最大值、最小值、精度等。
limits.h最大值与最小值
提供int、short、char、long类型最大值与最小值的宏定义,包括有符号与无符号。其中无符号最小值等于0,有符号最小值等于最大值相反数加1。
locale.h本地化
提供一些函数来帮助程序适应针对某个国家或地区的特定行为方式。例如日期、时间、货币、数字格式等。
math.h数学运算
提供常用的数学运算,包括:正弦/余弦/正切的三角函数、指数函数、对数函数、取绝对值、取模运算、向上取整、向下取整等。
setjmp.h长跳转
提供长跳转指令功能,与函数内的短跳转goto作用类似。
提供了setjmp函数和longjmp函数。setjmp函数会“标记”程序中的一个位置,随后可以用longjmp返回被标记的位置。 这些函数可以用来从一个函数跳转到另一个(仍然在活动中的)函数中,而绕过正常的函数返回机制。 setjmp函数和longjmp函数主要用来处理程序执行过程中出现的严重问题。
signal.h信号
提供了用于处理异常情况(信号)的函数,包括中断和运行时错误。
stdarg.h可变参数
提供了一些工具用于编写参数个数可变的函数。
提供可变参数的遍历,由va_start()、va_arg()和va_end()三个函数组成,还有一个va_list可变参数列表。
stddef.h常用定义
定义了一些有用的类型和宏,这些类型和宏在C编程中非常常用。
stdio.h输入/输出
提供了大量的输入/输出函数,
printf
输出(I)函数
转换说明
a
浮点数、十六进制数和p记数法(C99/C11)
A
浮点数、十六进制数和p记数法(C99/C11)
c
以字符形式输出,只输出单个字符。
d
有符号十进制整数
e
浮点数,e记数法
E
浮点数,e记数法
f
浮点数,十进制记数法
g
根据值的不同,自动选择%f或%e。%e格式用于指数小于-4或者大于或等于精度时。
G
根据值的不同,自动选择%f或%E。%E格式用于指数小于-4或者大于或等于精度时。
i
有符号十进制整数(与%d相同)
o
无符号八进制整数
p
指针
s
字符串
u
无符号十进制整数
x
无符号十六进制整数,使用十六进制数0f
X
无符号十六进制整数,使用十六进制数0F
%
打印一个百分号
修饰符
标记
-
待打印项左对齐。即从字段的左侧开始打印该项
示例:"%-20s"
+
有符号值若为正,则在值前面显示加号;若为负,则在值前面显示减号
示例:"%+6.2f"
空格
有符号值若为正,则在值前面显示前导空格(不显示任何符号):若为负,则在值前面显示减号+标记并覆盖空格
示例:"% 6.2f"
#
把结果转换为另一种形式。如果是%o格式,则以0开始;如果是%x或%X格式,则以0x或0X开始; 对于所有的浮点格式,#保证了即使后面没有任何数字,也打印一个小数点字符。对于%g和%G格式,#防止结果后面的0被删除。
示例:"%#o”、"%#8.0f"、"%+#10.3e"
0
对于数值格式,用前导0代替空格填充字段宽度。 对于整数格式,如果出现-标记或指定精度,则忽略该标记。
示例:"%010d"和"%08.3f"
数字
最小字段宽度:如果该字段不能容纳待打印的数字或字符串,系统会使用更宽的字段。
示例:"%4d"
.数字
精度:对于%e、%E和%f转换,表示小数点右边数字的位数。对于%g和%G转换,表示有效数字最大位数。对于%s转换,表示待打印字符的最大数量。 对于整型转换,表示待打印数字的最小位数。如有必要,使用前导0来达到这个位数。只使用.表示其后跟随一个0,所以%.f和%.0f相同。
示例:"%5.2f"打印一个浮点数,字段宽度为5字符,其中小数点后有两位数字
h
和整型转换说明一起使用,表示short int或unsigned short int类型的值。
示例:"%hu"、"%hx"、"%6.4hd"
hh
和整型转换说明一起使用,表示signed char或unsigned char类型的值。
示例:"%hhu”、"%hhx"、"%6.4hhd"
j
和整型转换说明一起使用,表示intmax_t或uintmax_t类型的值。这些类型定义在stdint.h中。
示例:"%jd”、"%8jx"
l
和整型转换说明一起使用,表示long int或unsigned long int类型的值。
示例:"%ld"、"%lu"
ll
和整型转换说明一起使用,表示long long int或unsigned long long int 类型的值(C99)。
示例:"%lld"、"%llu"
L
和浮点转换说明一起使用,表示1ong double类型的值。
示例:"%Lf"、"%10.4Le"
t
和整型转换说明一起使用,表示ptrdiff_t类型的值。ptrdiff_t是两个指针差值的类型(C99)。
示例:"%td"、"%12ti"
z
和整型转换说明一起使用,表示size_t类型的值。size_t是sizeof返回的类型(C99)。
示例:"%zd"、"%12zd"
格式
int printf( const char *format, ... );
printf(“'%''修饰符''格式控制字符串'”,参数1,参数2,…)
格式控制字符串就是转换说明中的字符,告诉编译器你想以什么样的方式打印出来。
例:int a = 5;printf(“%d”,a);运行,输出5
注:打印过程中只修改格式控制字符串
例:int a = 5;printf(“a = %d”,a);运行,输出a = 5
注:“format”表示格式字符串,“...”表示可变参数列表。
sprintf
将格式化的字符串输出到一个字符数组中。
转换说明
%
印出百分比符号,不转换。
b
整数转成二进位。
c
整数转成对应的 ASCII 字元。
d
整数转成十进位。
f
整数转成浮点数。
默认保留小数点后6 位数字
“%m.nf“
m表示打印的宽度,n表示小数点后的位数。
o
整数转成八进位。
s
整数转成字符串。
x
整数转成小写十六进位。
X
整数转成大写十六进位。
格式
int sprintf(string format, mixed [args]...)
sprintf(参数,“格式控制字符串”,参数1,参数2,…)
将参数1/2/3/…以字符串类型赋给“参数”
注:str:指向要写入的字符串的指针。
format:包含格式控制符的字符串,用于指定输出的格式。
...:可变参数列表,根据格式化字符串中指定的格式进行输出。
fprintf
将数据写入到文件
格式
int fprintf( FILE *stream,const char *format,... )
fprintf(文件指针,格式控制字符串,字符/数字)
将“字符/数字”以“格式控制字符串”所示格式输入到“文件指针中”。
注:写入失败返回EOF
scanf
输入(O)函数
转换说明
c
子主题把输入解释成字符
d
把输入解释成有符号十进制整数
e、f、g、a
把输入解释成浮点数(C99标准新增了a)
E、F、G、A
把输入解释成浮点数(C99标准新增了A)
i
把输入解释成有符号十进制整数
o
把输入解释成有符号八进制整数
p
把输入解释成指针(地址)
s
把输入解释成字符串。从第1个非空白字符开始,到下一个空白字符之前的所有字符都是输入。
u
把输入解释成无符号十进制整数
x、X
把输入解释成有符号十六进制整数
俢饰符
*
抑制赋值(详见后面解释)
数字
最大字段宽度。输入达到最大字段宽度处,或第1次遇到空白字符时停止
hh
把整数作为signed char或unsigned char 类型读取
ll
把整数作为long long或unsigned iong long 类型读取(C99)
h、l或L
"%hd"和"%hi"表明把对应的值存储为short int类型。 "%ho"、"%hx"和"%hu"表明把对应的值存储为 unsigned short int类型。 "%ld"和"%li"表明把对应的值存储为long类型。 “%o”、"%lx"和"%lu"表明把对应的值存储为unsigned long 类型。 "%le"、"%lf"和"%lg"表明把对应的值存储为double 类型。 在e、f和g前面使用L而不是l,表明把对应的值被存储为long double 类型。 如果没有修饰符,d、i、o和x表明对应的值被存储为int类型, f和g表明把对应的值存储为float类型。
j
在整型转换说明后面时,表明使用intmax_t或uintmax_t类型(C99)
z
在整型转换说明后面时,表明使用sizeof的返回类型(C99)
t
在整型转换说明后面时,表明使用表示两个指针差值的类型(C99)
格式
int scanf(const char *format, ...);
scanf(“'%''修饰符''格式控制字符串'”,参数1,参数2,…)
格式控制字符串就是转换说明中的字符,告诉编译器你输入的东西想解释成什么样。
例:int a = 5;scanf(“%d”,a);运行,输入10,回车,a的值就被修改成10了。
注:“format”是一个格式字符串,“...”表示可变参数列表。
如果用scanf()读取基本变量类型的值,在变量名前加上一个&;如果用scanf()把字符串读入字符数组中,不要使用&。
fscanf
从文件中读取数据
格式
int fscanf(FILE *stream,const char *format,...)
fscanf(文件指针,格式控制字符串,&变量名)
从“文件指针”中按“格式控制字符串”所示格式读取数据并存放到“&变量名”中
注:不是随机读取,是读取文件中“变量名”的数值,如果文件中没有,则为读取失败,返回 EOF(-1)。
fopen
打开文件
打开方式
“r”(只读) 为了输入数据,打开一个已经存在的文本文件,如果指定文件不存在则出错。
“w”(只写) 为了输出数据,打开一个文本文件,如果指定文件不存在则建立一个新的文件。
“a”(追加) 向文本文件尾添加数据,如果指定文件不存在则建立一个新的文件。
“rb”(只读) 为了输入数据,打开一个二进制文件,如果指定文件不存在则出错。
“wb”(只写) 为了输出数据,打开一个二进制文件,如果指定文件不存在则建立一个新的文件。
“ab”(追加) 向一个二进制文件尾添加数据,如果指定文件不存在则出错。
“r+”(读写) 为了读和写,打开一个文本文件,如果指定文件不存在则出错。
“w+”(读写) 为了读和写,建议一个新的文件,如果指定文件不存在则建立一个新的文件。
“a+”(读写) 打开一个文件,在文件尾进行读写,如果指定文件不存在则建立一个新的文件。
“rb+”(读写) 为了读和写打开一个二进制文件,如果指定文件不存在则出错。
“wb+”(读写) 为了读和写,新建一个新的二进制文件,如果指定文件不存在则建立一个新的文件。
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写,如果指定文件不存在则建立一个新的文件。
格式
FILE *fopen( const char *filename,const char *mode )
fopen( 文件名,打开方式 )
fclose
关闭文件
格式
int fclose ( FILE * stream )
fclose (文件名 )
getc
从 FILE* 指针指向的文件中读取1个字符
格式
int getc(FILE *stream)
getc (文件名)
fgets
从文件中读取数据
格式
int fputs(const char* str,FILE* stream)
fgets(变量名, 变量大小, 文件指针)
从“文件指针”中读取最多“变量的大小”个字符到第“变量名”中
注:读取失败返回EOF
putc
一次写入一个字符到文件中
格式
int putc(int char,FILE *stream)
putc(字符,文件名)
将“字符”写入到“文件名”中
fputc
将字符串写入到指定的文件中
格式
int fputs(const char* str,FILE* stream)
fputc(字符串,文件指针)
将“字符串”写入到“文件指针中”
getchar
从标准输入(通常是键盘)读取一个字符
格式
int getchar (void)
getchar(变量名)
注:getchar 读取输入缓冲区中的下一个字符,并在读取成功后将其从缓冲区中删除。
注:getchar返回字符的ASCII码值(整数)。
注:写入失败返回EOF
putchar
将一个字符输出到标准输出(通常是控制台)。
格式
int putchar(int character);
putchar(变量名)
stdlib.h通用工具
提供内存分配与释放、随机数的生成、进程退出、执行命令行、字符串转数值类型、二分查找算法、快排算法、求绝对值等操作。
malloc
用于申请一块连续的指定大小的内存块区域,以void*类型返回分配的内存区域地址。
格式
void *malloc(unsigned size)
malloc(数字)
注:实现原理:链表连接所有空闲的空间,组成最终分配的空间。
注:返回类型为无类型(void)指针,也即是通用指针,本质上是内存地址,需要进行类型转换。
注:在使用完malloc函数开辟的空间之后,需要释放(free函数),否则会造成内存泄漏。
注:在使用malloc函数开辟的空间中,不要移动指针,否则可能出现申请的空间和释放的空间大小不一致。
free
释放不需要的内存空间。
格式
void free(void *ptr)
free(参数)
注:在申请内存之后,需要及时将不再使用的内存空间进行释放,否则会导致内存耗尽。
calloc
为n个元素的数组分配内存,每个元素长度为size个字节
格式
void *calloc(unsigned n,unsigned size)
calloc(数字1,数字2)
注:与malloc() 函数的区别:calloc()函数会将所有字节置0来初始化该内存空间
realloc
为数组分配空间之后,若发现数组过大或过小,realloc() 函数可以调整已申请内存的大小。
格式
void *realloc(void *ptr,unsigned size)
realloc(参数,数字)
ptr指向原先通过malloc()、calloc()或realloc()获得的内存块。
size为内存块的新大小。
注:当分配内存减小时,realloc()仅改变索引信息
注:当分配内存扩大时
当前内存后还有空间:直接扩展这段内存空间,realloc()函数返回原指针。
当前内存后空闲字节不够:使用堆中第一个能够满足这一要求的内存块,并将目前的数据复制到新位置,将原来的空间释放掉,返回新的内存块地址。
申请失败:返回NULL,此时,原来指针仍然有效。
注:当ptr为空指针时,realloc()函数作用等同于malloc()函数;
atoi
将数字字符的字符串转换为整型返回
格式
int atoi (const char * str)
atof(参数)
注:如果字符串从开头就有连续的空格字符,则跳过这些连续的空格字符,找到不是空格的字符。
注:如果跳过这些空格字符后的第一个字符不是数字字符,则直接返回0。
注:如果跳过这些空格字符后的第一个字符是数字字符,则从这个数字字符开始转换,并向后找连续的数字字符转换, 如果连续中断,找到不是数字字符的字符,则在此截断寻找,返回前面已经转换好的连续的数字字符字面整型值。 (这里截断向后寻找后,不管后面有没有数字字符函数都不管)
注:如果字符串全部为空格字符,返回0;如果为空字符串,返回0;
atof
把字符串转换成浮点数,直至遇到第一个空格。
格式
double atof(const char *nptr)
atof(参数)
itoa
将整数转换为字符串。
格式
char* itoa(int value,char* string,int radix)
itoa(数字,参数,数字)
value是要转换的整数值。
string是存储转换后值的字符数组。
radix代表进制,radix=10就是十进制,radix=2就是二进制。
注:第二个参数只能是char*,不能是string;
注:第二个参数在使用之前必须提前分配存储空间。
string.h字符串
提供了用于进行字符串操作(包括复制、拼接、比较及搜索)的函数以及对任意内存块进行操作的函数。
注:凡是字符串,结尾必须有终止符"/n"
strlen
计算字符串中字符的个数
格式
size_t strlen( const char *string )
strlen(参数)
注:strlen函数的返回值是size_t(unsigned int),是无符号的;
strcpy
将第二个字符串覆盖复制到第一个字符串。
格式
char *strcpy( char *strDestination,const char *strSource )
strcpy (参数1,参数2)
strncpy
将第二个字符串覆盖复制到第一个字符串,但它允许我们指定要覆盖复制的字符数量。
格式
char *strncpy(char *dest,const char *src,size_t n)
strncpy(参数1,参数2,数字)
strcat
将第二个字符串复制添加到第一个字符串末尾。
格式
char *strcat( char *strDestination,const char *strSource )
strcat (参数1,参数2)
注:不可自己追加自己,需要这样做则使用strncat
strncat
将第二个字符串复制添加到第一个字符串末尾,但它允许我们指定要添加的字符数量。
格式
char * strncat ( char * destination,const char * source,size_t num )
strncat(参数1,参数2,数字)
注:数字表明复制第二个字符串的前“数字”个字符到第一个字符串的末尾。
strcmp
比较字符串1与字符串2的大小
格式
int strcmp( const char *string1,const char *string2 )
strcmp(参数1,参数2 )
注:从字符串1和字符串2的首字符开始比较,比较它们的ASCII值, 如果相等就比较下一个字符的ASCII值(包括\0), 直到得出结果(两者比较到\0处后还相等,那就证明两字符串相等)。
注:如果字符串1大于字符串2,则返回大于0的值 ,如果字符串1小于字符串2,则返回小于0的值, 如果字符串1等于字符串2,则返回0。
strncmp
比较字符串1与字符串2前n个字符的大小
格式
int strncmp(const char* str1,const char* str2,size_t num)
strncmp(参数1,参数2,数字)
注:数字表明比较字符串1与字符串2前“数字”个字符的大小
注:从字符串1和字符串2的首字符开始比较,比较它们的ASCII值, 如果相等就比较下一个字符的ASCII值(包括\0), 直到得出结果(两者比较到\0处后还相等,那就证明两字符串相等)。
注:如果字符串1大于字符串2,则返回大于0的值,如果字符串1小于字符串2,则返回小于0的值, 如果字符串1等于字符串2,则返回0。
strchr
在一个字符串中查找给定字符的第一个匹配之处,并返回指向该字符的指针。
格式
char *strchr(const char *str,int c)
strchr(参数,字符)
str:要查找的字符串,必须是一个以空字符 ‘\0’ 结尾的字符数组,也就是 C 语言中的字符串类型。
c:要查找的字符,必须是一个整型值,通常是一个字符常量或变量,例如 ‘a’ 或 ch。 如果 c 是一个多字节字符,例如汉字,那么只会查找其第一个字节。
注:对于大小写敏感,会区分字符 ‘a’ 和 ‘A’。
注:对于多字节字符的支持不完善,也就是说,它只会查找多字节字符的第一个字节。
注:如果没有找到该字符,则返回 NULL。
strrchr
在给定的字符串中从末尾开始搜索指定的字符,返回一个指向该字符最后一次出现的指针。
格式
char *strrchr(const char *str,int c)
strrchr(参数,字符)
const char *str:这是一个指向字符串的指针,表示要搜索的字符串。该字符串以空字符(\0)结尾。
int c:这是要查找的字符的ASCII码值。函数会在字符串str中搜索与该ASCII码值对应的字符。
注:对于大小写敏感,会区分字符 ‘a’ 和 ‘A’。
注:对于多字节字符的支持不完善,也就是说,它只会查找多字节字符的第一个字节。
注:如果字符在字符串中不存在,则返回 NULL。
strpbrk
在目标字符串s1中查找任意一个包含在字符串s2中的字符首次出现的位置,并返回指向该位置的指针;
格式
char *strpbrk(const char *s1,const char *s2)
strpbrk(参数1,参数2)
注:如果没有找到,则返回空指针。
strspn
返回字符串中第一个不在指定字符串中出现的字符下标
格式
size_t strspn(char const *str,char const *grouo)
strspn(参数1,参数2)
注:从str的第一个元素开始往后数,看str中是不是连续往后每个字符都在group中可以找到。到第一个不在gruop的元素为止。
注:返回值类型为整型,大小为停止时在str中已对比过的元素个数。
strstr
用于查找子字符串在主字符串中的第一次出现
格式
char *strstr(const char *haystack,const char *needle)
strstr(参数1,参数2)
haystack:指向要搜索的主字符串的指针。
needle:指向要查找的子字符串的指针。
注:返回一个指向haystack中第一次出现needle的指针。如果未找到子字符串,则返回NULL。
strtok
分解长字符串
格式
char *strtok(char *str, const char *delim)
strtok(参数1,参数2)
str—要被分解的字符串
delim—用作分隔符的字符。 (可以是一个,也可以是集合)
strtok()的第二个参数delim可以是所有分隔符的集合,比如{aaa - bbb ; ccc | ddd},第二个参数delim可以是{-;|},用一个或多个分隔符去分解字符串都可以。
注:该函数返回被分解的第一个子字符串,若无可检索的字符串,则返回空指针。
注:第一次调用strtok(),传入的参数str是要被分割的字符串{aaa - bbb -ccc},而成功后返回的是第一个子字符串{aaa}。
而第二次调用strtok的时候,传入的参数应该为NULL,使得该函数默认使用上一次未分割完的字符串继续分割,就从上一次分割的位置{aaa-}作为本次分割的起始位置,直到分割结束。
注:在这个函数里strtok()在分解字符串的时候,第一个参数str是在不断变化的,这个函数是在改变原字符串, 把原字符串{aaa - bbb - ccc}通过第二个参数delim将所有的分割符{-}替换成字符串结束标志字符{\0},则原字符串变化为{aaa \0 bbb \0 ccc}。
注:当strtok分解的字符串首字符就是分隔符,那么strtok()会忽略首个分隔符,直接从第二个分隔符往下继续分解,例如:{- aaa - bbb - ccc} 那么strtok()会忽略第一个{-},还是以{aaa - bbb - ccc}的字符串形式继续分解。
memset
将已开辟内存空间 s 的首 n 个字节的值设为值 c。
格式
void *memset(void *s,int c,size_t n)
memset(参数,数字1,数字2)
memcpy
从源头指向的内存块拷贝固定字节数的数据到目标指向的内存块.
格式
void * memcpy ( void * destination,const void * source,size_t num )
memcpy(参数1,参数2,数字)
注:源头的内存块与目标内存块不可以重叠。
注:能够作用于任何类型的数据包括(浮点型,结构体等等)。
注:与strcpy()函数不同,不会检查任何终止字符(如'\0'),而总是精确的拷贝参数传入的字节数。
memmove
从源头指向的内存块拷贝固定字节数的数据到目标指向的内存块。
格式
void * memmove ( void * destination,const void * source,size_t num )
memmove(参数1,参数2,数字)
从参数2拷贝“数字”个字节的数据到参数1。
注:源头的内存块与目标内存块可以重叠。
memcmp
比较参数1和参数2前n个字节数据的大小
格式
int memcmp(const void* dest,const void* rsc,size_t count)
memcmp(参数1,参数2,数字)
注:从参数1和参数2的首个字节数据开始比较,比较它们的ASCII值, 如果相等就比较下一个字节数据的ASCII值(包括\0), 直到得出结果(两者比较到\0处后还相等,那就证明两参数相等)。
注:如果参数1大于参数2,则返回大于0的值,如果参数1小于参数2,则返回小于0的值, 如果参数1等于参数2,则返回0。
bzero
将字符串s的前n个字节置为0
格式
void bzero(void *s,int n)
bzero(参数,数字)
注:此函数为废弃函数,部分编译器不支持。
time.h系统时间
提供相应的函数来获取时间(和日期)、操纵时间,以及格式化时间的显示。
C99
complex.h复数运算
定义了一组用于复数操作的宏、类型和函数。
fenv.h浮点数环境
定义了浮点数环境控制函数、异常控制函数、舍入方式控制函数、浮点数异常码和舍入方式等。提供了对浮点状态标志和控制模式的访问。
inttypes.h整数类型
提供整数类型的宏定义,定义了可用于<stdint.h>中声明的整数类型输入/输出的格式化字符串的宏,还提供了处理最大宽度整数的函数。
iso646.h备选拼写
C99标准新增了可代替逻辑运算符的拼写,它们被定义在ios646.h头文件中。
传统写法
&&
&=
&
||
|
|
~
!
!=
^
^=
ios646.h
and
and_eq
bitor
or
or_eq
bitor
compel
not
not_eq
xor
xor_eq
stdbool.h布尔值
定义了bool代表_Bool,true代表1,false代表0。
stdint.h精确整数
声明了指定位宽的整数类型,并定义了相关的宏(例如指定每种类型的最大值和最小值的宏),同时也定义了用于构建具体类型的整型常量的带参数的宏。
tgmath.h
在C99中,<math.h>和<complex.h>头中的许多数学函数有多个版本。 <tgmath.h>头(27.5节)中的泛型宏可以检测传递给它们的参数类型, 并替代为相应的<math.h>或<complex.h>中函数的调用。
wchar.h
提供了一组函数和宏,用于处理宽字符和多字节字符。
wctype.h
提供了用于分类宽字符和在修改宽字符的函数和宏。
C11
stdalign.h
定义了四个宏
stdatomic.h
定义了现有数据类型的原子类型,并提供了大量的宏用于执行原子类型变量的初始化和读写操作。
stdnoreturn.h
定义了宏noreturn(被定义为_Noreturn)。
threads.h
提供了线程的创建和管理函数,以及互斥锁、条件变量和线程局部存储的功能。
uchar.h
定义了新的宽字符类型char16_t和char32_t,并提供了从多字节字符到这些宽字符类型的转换函数。
windows平台
C 运行时库(C Runtime Library)
包括 msvcrt.lib 和 msvcr*.dll(*代表版本号),提供了 C 语言的基本运行时支持,如内存管理、输入输出、字符串操作等。
Windows API
包括一系列的库文件和动态链接库(DLL),提供了与 Windows 操作系统交互的函数和数据结构。
其他库
除了 Windows API,还有许多其他的第三方库可以用于 Windows 平台的 C 语言开发,如开源的库、图形库、数据库访问库等。
Linux平台
C 运行时库(C Runtime Library)
Linux 上的 C 运行时库通常称为 GNU C 库(GNU C Library,简称 glibc)。它是标准的 C 库,提供了 C 语言的基本运行时支持。
POSIX 库
POSIX 是一个定义了操作系统接口标准的系列规范,其中包含了许多与操作系统交互的函数和数据结构。
动态链接库(Dynamic Linking Libraries)
Linux 上许多库以动态链接库的形式存在,
开源库
Linux 是开源操作系统,拥有丰富的开源库可以供开发者使用。
注:以下为Linux平台独有的库,但具体是哪一类的就不知道了。
Unix标准unistd.h
提供POSIX操作系统的API,提供了访问操作系统服务的函数,包括fork进程、创建管道、创建软链接、创建硬链接、系统级休眠、IO操作等。
fcntl.h
提供了对文件描述符的操作,如打开、关闭、读取和写入文件。
sys/types.h
定义了一些基本的系统数据类型,
sys/stat.h
文件状态的头文件,它提供了一组用于获取和修改文件或文件系统状态信息的接口。 允许程序查询文件或目录的状态信息,包括:设备id、文件大小、文件访问权限、文件修改时间、文件访问时间、序列号、文件链接的数量等。
sys/socket.h
用于网络编程,提供了与套接字相关的函数和数据结构。
sys/time.h
提供了时间和日期相关的函数和定义,如获取当前时间、计时器等。
sys/wait.h
用于进程间通信,提供了等待子进程状态变化的函数和宏。
pthread.h线程操作
POSIX提供的线程,包括线程、互斥锁和条件变量三个部分。
signal.h
用于信号处理,提供了处理进程间通信和异常处理的函数和定义。
dlfcn.h库操作
动态链接库函数库的头文件,它提供了一组用于在运行时动态加载和链接共享库(动态链接库或共享对象)的接口。 允许程序在运行时动态地加载库、获取库中的函数地址以及卸载库。
sys/mmap.h
内存映射的头文件,它提供了一组用于内存映射文件或设备的接口。 允许程序将文件或其他对象映射到进程的地址空间中,从而可以直接通过指针访问这些对象的内容。
语句
表达式语句
表达式语句就是在表达式的后边加上分号。
赋值语句
由一个赋值表达式加一个分号组成。
函数调用语句
函数调用的时候,也会加上分号,就是函数调用语句。
控制语句
控制语句用于控制程序的执行流程,以实现程序的各种结构方式,它们由特定的语句定义符组成。
条件判断语句(分支语句)
if语句
如图0-1-1_1、0-1-1_2、0-1-1_3
switch语句
如图0-1-2
循环执行语句
while语句
如图0-1-3
do while语句
如图0-1-4
for语句
如图0-1-5
注:入口条件循环
在循环的每次迭代之前检查测试条件
注:出口条件循环
在循环的每次迭代之后检查测试条件
转向语句
break语句
执行到此语句时,直接跳出循环,执行循环外的后续语句
goto语句
有,但在C语言中通常不使用
continue语句
执行到此语句时,忽略循环中的后续语句,并重新开始循环。
return语句
return语句的作用是终止一个函数的执行,结束当前代码块中return后的语句, 即return后的语句不再执行,从当前函数退出,为该函数返回一个指定的值。 如果值被省略, 或在函数内没有return语句被执行,则把值赋给调用当前函数的表达式。
复合语句
成对括号中的代码就构成一个代码块,也被称为复合语句。
空语句
本身只包含一个分号。空语句本身并不执行任何任务。它所使用的场合就是语法要求出现一条完整的语句, 但并不需要它执行任务。
语句(statement)是C程序的基本构建块。一条语句相当于一条完整的计算机指令。在C中,大部分语句都以分号结尾。
3-1
0-1-1_1
0-1-1_2
0-1-1_3
0-1-2
0-1-3
0-1-4
0-1-5
1-5-1
1-4
0-0-1
0-0-2
0-0-3