导图社区 C 语言知识点思维导图
期末复习必备!一张思维导图带你复习C语言知识点,期末考试拿下高分!按照各个章节的内容总结整门课程的重点内容,让你期末复习更轻松!喜欢请点赞收藏!关注我,能持续获取优质导图哦。
编辑于2019-05-03 08:09:10C 语言
数据类型:
整数类型(signed & unsigned)
char (字符型)
1 字节(32&64)
有符号范围: -2^7 ~ 2^7-1 (-128 ~ 127)
无符号范围:0 ~ 2^8 - 1 (0~255)
short (短整型)
2 字节(32&64)
有符号范围: -2^15 ~ 2^15-1 (-32768 ~ 32767)
无符号范围:0 ~ 2^16 - 1 (0~65535)
int (整型)
4 字节(32&64)
有符号范围: -2^31 ~ 2^31-1
无符号范围:0 ~ 2^32 - 1
long int
32位:4
64位:8
long long
8 字节(32&64)
有符号范围: -2^63 ~ 2^63-1
无符号范围:0 ~ 2^64 - 1
浮点类型
float
存储大小:4 字节
值范围:1.2E-38 到 3.4E+38
精度:6 位小数
double
存储大小:8 字节
值范围:2.3E-308 到 1.7E+308
精度:15 位小数
long double
存储大小:16 字节
值范围:3.4E-4932 到 1.1E+4932
精度:19 位小数
指针类型
bool (布尔类型)
void 类型
函数返回为空
C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);
函数参数为空
C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void);
指针指向 void
类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。
构造类型
数组类型
eg: int arr[]
结构体类型(struct)
struct 语句的格式
struct tag { member-list member-list member-list ... } variable-list ;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
成员:
C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
标量、数组、指针、或者其他结构体
访问结构成员
成员访问运算符(.)
枚举类型(enum)
枚举语法定义格式为
enum 枚举名 {枚举元素1,枚举元素2,……};
特点:
{}中变量取值默认从0开始,依次加1(如果变量中有赋值,则按照该值,依次增加,之前的不变)
结构体内存对齐规则:
1、第一个成员在结构体偏移量为0的位置
2、其他成员需要对齐到自身对齐数的整数倍地址处(对齐数 = 编译器默认值(32&64)与该成员大小的较小值)
3、结构体总大小是所有成员最大对齐数的整数倍(eg: double 对齐数为8,总大小就是8的倍数)
4、如果嵌套结构体,嵌套结构体对齐到自己最大对齐整数倍处(结构体整体大小是(两个结构体成员)最大对齐数的整数倍)
对齐的原因和作用:
不同硬件平台对存储空间的处理上存在很大的不同。某些平台对特定类型的数据只能从特定地址开始存取,而不允许其在内存中任意存放
如果不按照平台要求对数据存放进行对齐,会带来存取效率上的损失。
比如32位的Intel处理器通过总线访问(包括读和写)内存数据。每个总线周期从偶地址开始访问32位内存数据,内存数据以字节为单位存放。如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。
更多对齐问题详解可参考:
https://www.cnblogs.com/clover-toeic/p/3853132.html
联合类型(union)
union 语句的格式
union [union tag] { member definition; member definition; ... member definition; } [one or more union variables];
union 与 struct的区别:
联合(union):共用体变量所占的内存长度等于最长的成员变量的长度。成员共用一块空间
结构体(struct):结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。
特点:
1、联合体的大小至少是最大成员的大小
2、当最大成员大小不是最大对齐数整数倍时,要对齐到对齐的整数倍
3、联合的成员在某一时刻只有当前的成员是有效的
4、可用于判断大小端
操作符和表达式:
算术运算符:
( + - * / % ++ -- )
% 两个操作数必须为整数
关系运算符:
( == != > < >= <= )
逻辑运算符:
( && || ! )
位运算符:
( & (按位与) |(按位或) ^(按位异或) ~(按位取反))
>> :二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
赋值运算符:
( = += -= *= /= %= <<= >>= &= ^= |= )
条件运算符:
exp1 ? exp2 : exp3 (如果exp1成了,则执行exp2,否则执行exp3)
逗号表达式:
又称为“顺序求值运算符”一般形式为 表达式1,表达式2
逗号表达式的求解过程是:先求解表达式1,再求解表达式2。整个逗号表达式的值是表达式2的值。
指针运算符(* &)
不能对空指针进行 解引用 ++ -- 操作
表达式求值:
1、隐式类型转换
2、算术转换
操作符的属性:
1、操作符的优先级
2、操作符的结合性
3、是否控制求值顺序
32个关键字:
关于数据类型的关键字
char int long short double float signed unsigned struct enum union void
关于控制语句的关键字
循环语句
for do while
条件判断语句
if else switch case default
跳转语句
goto continue break return
关于存储类型的关键字
auto extern register static
其它一些关键字
const sizeof typedef volatile
部分关键字说明
const :
可参看:C语言中const关键字的用法
https://blog.csdn.net/xingjiarong/article/details/47282255
优点
1、预编译指令只是对值进行简单的替换,不能进行类型检查
2、可以保护被修饰的东西,防止意外修改,增强程序的健壮性
3、编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
用法
1、修饰局部变量
2、常量指针与指针常量
3、修饰函数的参数
4、修饰函数的返回值
5、修饰全局变量
extern
声明变量是在其他文件正声明(也可以看做是引用变量),一般也需要经常使用,因为在C语言里面,全局变量和函数都是默认extern的属性
extern "C"{}修饰
static
a、当我们把一个全局变量声明为static时:只有它的作用范围变为本源文件,也就是属性由external变为internal,其它不变;
b、当我们把函数声明为static时:它的作用范围变为本源文件,也就是属性由external变为internal;
c、当我们把局部变量声明为static时:默认初始化值为0,并且只在第一次定义时初始化;内存存储区域不再是栈,而是在静态存储区;生命周期不再是所在函数,而是整个进程;其它不变。
更多关键字说明参看:
https://www.cnblogs.com/whc-uestc/p/4694223.html
语句:
分支语句
if 语句
else与最近邻的if相匹配
switch 语句
每一个case语句后面的break不能省(除非特殊情况)
如果case都不满足,则执行default语句
goto语句
break 只能从内层循环中跳出到上一层循环
goto 可以跳转一层或者多层循环
循环语句
for 循环
注意边界问题(通常 左闭右开)
while 循环
while()括号中的条件是:满足条件则执行,不满足退出循环
do...while 循环
与while 语句相同)(但 先执行语句,再判断,循环必定会被执行一次)
内存分配:
更多参看 :
https://www.jianshu.com/p/b2380e47d005
https://www.jianshu.com/p/ccb337572498
推荐看下 作者写了两篇 内存管理基础 和 内存管理深入
https://blog.csdn.net/chenyiming_1990/article/details/9476181
1、栈区(stack)
特点:
一种线性结构 先进后出的特点(简称FILO)
包含:
局部变量 形式参数 返回数据 返回地址等
释放:
由编译器自动释放
2、堆区(heap)
特点:
堆是低地址向高地址扩展的数据结构,是一块不连续的内存区域。
包含:
存放程序运行中动态分配的存储空间
释放:
由程序员分配释放(程序结束时可能由OS回收)
3、静态区(static)
包含:
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域
释放:
程序结束后由系统释放
4、文字常量区
包含:
常量字符串
释放:
程序结束后由系统释放
5、程序代码区
包含:
存放函数体的二进制代码
数据在内存中的存储方式:
在计算机内部存储的带符号数都是以补码形式存储,用补码形式进行运算的
原码:直接将二进制按照正负数的形式翻译成二进制就可以了
反码:将原码的符号位不变,其他位依次按位取反就可以得到
补码:
对于正数:补码与原码相同
对于负数:符号位不变,其数值位X的绝对值取反后在最低位加1
大小端字节序存储
大端模式
数据的低位保存在内存的高地址中,而数据的高位保存在内存的低地址中
小端模式
数据的高位保存在内存的高地址中,而数据的低位保存在内存的低地址中
各自的优势
小端模式:强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式:符号位的判定固定为第一个字节,容易判断正负。
可以通过联合体union来判断电脑是大端还是小端模式
动态内存管理:
malloc:
函数原型
void *malloc(size_t __size)
参数说明
size 需要分配的内存空间的大小,单位是字节。
返回值类型
void * 表示未确定类型的指针,分配成功返回指向该内存的地址,失败则返回NULL。
void * 类型可以强制转换为任何其它类型的指针
函数功能
表示向系统申请分配指定 size 个字节的内存空间。
calloc
函数原型
void *calloc(size_t __count, size_t __size)
参数说明
count 表示个数,size 单位个需要分配的内存空间的大小,单位是字节。
返回值类型
void * 表示未确定类型的指针。
函数功能
表示向系统申请分配 count 个长度为 size 一共为 count 乘以 size 个字节长度的连续内存空间,并将每一个字节都初始化为 0。
realloc
函数原型
void *realloc(void *__ptr, size_t __size)
参数说明
ptr 表示需要修改的内存空间的地址,size 表示需要重写分配的内存空间的大小,单位是字节。
返回值类型
void * 表示未确定类型的指针。
函数功能
表示更改已经配置好的内存空间到指定的大小。
free
函数原型
void free(void *)
参数说明
void * 表示需要释放的内存空间对应的内存地址。
返回值类型
返回值为空。
函数功能
表示用来释放已经动态分配的内存空间。free() 可以释放由 malloc()、calloc()、realloc() 分配的内存空间,以便其他程序再次使用。
需要注意的是:free() 不会改变 传入的指针的值,调用 free() 后它仍然会指向相同的内存空间,但是此时该内存已无效,不能被使用。所以建议将释放完的指针设置为 NULL。
动态开辟空间的四大步
1、动态申请空间
2、判空(可能申请失败)
3、释放空间free(释放掉后,ptr为野指针)
4、将ptr指向NULL
编译过程:
预处理(.i)
展开头文件 宏替换 去掉注释 条件编译
gcc -E hello.c -o hello.i
将hello.c预处理输出hello.i文件。
编译(.s)
检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,把代码翻译成汇编语言
语义分析 语法分析 词法分析 符号汇总
gcc –S hello.i –o hello.s
将预处理输出文件hello.i汇编成hello.s文件
汇编(.o)
编译阶段生成的”.s”文件转成二进制目标代码
形成符号表,转为机器语言
gcc –c hello.s –o hello.o
将汇编输出文件test.s编译输出test.o文件。
链(.exe)
1、合并段表 2、符号表的合并和符号表的重定位
gcc hello.o –o hello.exe
将编译输出文件hello.o链接成最终可执行文件hello.exe。
扩展阅读课参看
编译过程
https://www.cnblogs.com/mickole/articles/3659112.html
预处理与预处理器
https://www.cnblogs.com/clover-toeic/p/3851102.html
https://zh.wikipedia.org/wiki/C%E9%A2%84%E5%A4%84%E7%90%86%E5%99%A8
函数:
函数的定义和声明:
声明
函数使用一般先在头文件中声明再使用,声明是告诉编译器有个函数叫什么,返回类型和参数是什么
定义
定义是函数的具体实现,交代函数的功能
库函数
string.h stdlib.h stdarg.h windows.h stdio.h errno.h ...
自定义函数
迭代
递归
回调函数
函数的参数:
实参
真实传递给被调用函数的值
形参
定义函数名和函数体时需要用的参数,目的是用来接收调用该函数时传递的参数。
形参变量在未出现函数调用时,并不占用内存,只在调用时才占用。调用结束后,将释放内存。
形参只是实参的一份临时拷贝
函数的调用:
传值调用
把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
引用调用
通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
main函数
参数
参数个数-int argc
argc,指明有多少个参数将被传递给主函数main(),真正的参数以字符串数组(即第2个参数argv[])的形式来传递。
命令行参数-char *argv[]
argv(第二个形参)必须是指向字符串的指针数组
第一个字符串argv[0]是程序的名称,包含路径,如果这个名称不可用,则argv[0]必须是 '\0',字符串arav[i](i=1,...argc-1)表式第 i 个程序参数
环境变量-char *envp[]
存放指向环境变量的字符串指针数组
调用main函数的函数
__tmainCRTstartup()
可变参数:
可变参数列表的实现是由几个宏组成的,在头文件#include<stdarg.h>
一个可变参数表函数void func(int a, ...)
va_list
创建一个va_list类型变量
一个char*类型的变量, 它用于访问参数列表未确定的部分。
va_start(v,l)
使va_list指向起始的参数
第一个参数是va_list 的变量名, 第二个参数是省略号前最后一个有名字的参数
va_arg(v,l)
依次检索参数
这个宏接受两个参数, va_list 变量和参数列表中下一个参数的类型
va_end(v,l)
释放va_list
当访问完最后一个参数后要调用va_end,将指针清空
va_copy(v,s)
拷贝va_list的内容
可参看:
https://blog.csdn.net/A__B__C__/article/details/80240736
https://blog.csdn.net/mr_bean_1031/article/details/75912050
输入/输出函数:
错误报告函数:
perror
void perror(const char *str)
把一个描述性错误消息输出到标准错误 stderr。
程序终止:
void exit(int status)
0正常退出,非0异常退出
标准输入输出:
C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。
标准文件
标准输入 stdin 键盘
标准输出 stdout 屏幕
标准错误 stderr 屏幕
相关函数:
getchar() & putchar() 函数
int getchar(void)
函数从屏幕读取下一个可用的字符,并把它返回为一个整数。
函数在同一个时间内只会读取一个单一的字符。
int putchar(int c)
函数把字符输出到屏幕上,并返回相同的字符。
函数在同一个时间内只会输出一个单一的字符。
gets() & puts() 函数
char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。
scanf() 和 printf() 函数
int scanf(const char *format, ...) 函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。
int printf(const char *format, ...) 函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。
文件读写:
一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节。
可参看:
http://www.runoob.com/cprogramming/c-file-io.html
打开文件:
fopen( )
FILE *fopen( const char * filename, const char * mode );
创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE 包含了所有用来控制流的必要的信息。
filename 是字符串,用来命名文件, mode 为访问模式
关闭文件:
fclose( )
int fclose( FILE *fp );
如果成功关闭文件,fclose( ) 函数返回零,如果关闭文件时发生错误,函数返回 EOF。
写入文件:
fputc()
int fputc( int c, FILE *fp );
函数 fputc() 把参数 c 的字符值写入到 fp 所指向的输出流中。如果写入成功,它会返回写入的字符,如果发生错误,则会返回 EOF。
fputs()
int fputs( const char *s, FILE *fp );
函数 fputs() 把字符串 s 写入到 fp 所指向的输出流中。如果写入成功,它会返回一个非负值,如果发生错误,则会返回 EOF。
fprintf
int fprintf(FILE *fp,const char *format, ...)
fprintf()函数来写把一个字符串写入到文件中。
读取文件:
fgetc()
int fgetc( FILE * fp );
fgetc() 函数从 fp 所指向的输入文件中读取一个字符。返回值是读取的字符,如果发生错误则返回 EOF。
fgets()
char *fgets( char *buf, int n, FILE *fp );
函数 fgets() 从 fp 所指向的输入流中读取 n - 1 个字符。它会把读取的字符串复制到缓冲区 buf,并在最后追加一个 null 字符来终止字符串。
fscanf()
int fscanf(FILE *fp, const char *format, ...)
fscanf()函数来从文件中读取字符串,但是在遇到第一个空格字符时,它会停止读取。
二进制 I/O 函数:
读取二进制
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
写入二进制
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
fseek
可以移动文件指针到指定位置读,或插入写:
int fseek(FILE *stream, long offset, int whence);
stream 为已打开的文件指针 ;fseek 设置当前读写点到 offset 处, whence 可以是 SEEK_SET,SEEK_CUR,SEEK_END 这些值决定是从文件头、当前点和文件尾计算偏移量 offset。
数组:
一维数组
type arrayName [ arraySize ]
arraySize 必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。
数组中的元素占用连续的存储空间,并且根据每个元素所占存储空间来进行内存分配。
多维数组
type name[size1][size2]...[sizeN];
二维数组
type arrayName [ x ][ y ];
type 可以是任意有效的 C 数据类型,arrayName 是一个有效的 C 标识符。一个二维数组可以被认为是一个带有 x 行和 y 列的表格。
指针数组
一个数组,存放指针的数组
eg: int *arr[] char * arr[]
函数指针数组
eg: int (*p[5])()
p是一个数组存放的是:函数指针
p先与[]结合,表示指针数组([]优先级大于*)
int (*)():表示一个函数指针
指针:
指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。
指针 + 整数:
表示:指针的类型决定了指针向前或向后走几步
eg: int *p, p+1(表示指针p向后走了4个字符 char *p, p+1(表示指针向后走了1个字符))
指针 + 解引用:
表示:指针的类型决定了指针的解引用能够访问几个字节
eg: char* 的指针解引用只能访问一个字符;int *的指针解引用能访问4个字符
指针 - 指针:
表示:两个指针之间有几个元素(两个指针必须是同一个类型)
指向指针的指针:
可参看:
http://www.runoob.com/cprogramming/c-pointer-to-pointer.html
int **var
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
数组指针:
含义:一个指向数组的指针
eg:int (*arr)[] (整型数组指针) char (*arr)[] (字符型数组指针)
指针数组:
含义:一个数组,存放指针的数组
eg:int *arr[] (整型指针数组) char *arr[] (字符型指针数组)
函数指针:
void (*fun)():指针和fun指向函数,函数无参数,返回值为void
回调函数:
函数数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
可参看 http://www.runoob.com/cprogramming/c-fun-pointer-callback.html
函数指针数组的指针:
void (*(*pfunArr)[10])(const char *); pfunArr 是一个指针
指针指向的是一个数组,而这个数组存放的内容是函数指针
Author
leacoder
知乎:
https://www.zhihu.com/people/lichangke/activities
简书:
https://www.jianshu.com/u/3e95c7555dc7
GitHub:
https://github.com/lichangke