static关键词的作用
-
修饰局部变量:该变量被称为静态局部变量。静态局部变量在函数调用之间保持其值,并且仅初始化一次。
-
修饰全局变量:该变量被限制在当前源文件中使用,无法被其他源文件访问。
-
修饰函数:该函数被限制在当前源文件中使用,无法被其他源文件调用。
extern关键字
-
声明外部全局变量/函数:当在一个源文件中定义了一个全局变量/函数,希望在其他源文件中也能够访问该变量/函数时,可以使用extern关键字进行声明。这样其他源文件就可以引用该全局变量/函数而不需要重新定义。
volatile关键字的作用
-
防止编译器优化:编译器为了提高程序的性能,可能会对代码进行优化。在某些场景下,通过将变量声明为volatile,确保每次读取该变量都是最新值,不受编译器优化的影响。
-
多线程访问同一变量:当多个线程同时访问同一个共享变量时,使用volatile可以确保每次读取和写入该变量时都直接与内存交互,可以避免出现意外行为或数据不一致的情况。
sizeof与strlen
-
sizeof 是关键字,而 strlen 是库函数
-
sizeof 仅用于计算数据类型的大小或者变量的大小,而 strlen 只能以结尾为' \0 '的字符串作为参数
-
sizeof 计算数据类型或变量会占用内存的大小,strlen 计算字符串实际长度(不包括结尾的\0 )
-
编译器在编译时就计算出了 sizeof 的结果,而 strlen 必须在运行时才能计算出来
strcpy和memcpy
-
是C语言中用于复制内存内容的函数
-
参数类型不同
-
strcpy的参数是两个字符串(字符数组),用于将一个字符串复制到另一个字符串中
-
memcpy的参数是两个void指针和一个size_t类型的整数,可以用于任意类型的内存块复制
-
-
复制方式不同
-
strcpy会自动在源字符串末尾添加'\0'作为字符串结束标志,然后再进行复制
-
memcpy仅按字节进行逐一复制,没有对数据进行解释或处理
-
对变量的理解
-
变量是内存中一块特定的位置,用于保存数据值。通过给变量赋予一个唯一的标识符(变量名),可以在程序中引用这个位置,并对其中存储的数据进行操作。
-
在使用变量时,需要指定其类型以及初始值
数组和指针
-
数组
-
数组是相同类型数据元素的集合,在内存中是连续存储的
-
数组声明时需要指定元素类型和数组大小
-
使用索引来访问数组元素,索引从 0 开始
-
-
指针与数组
-
数组名代表了数组首元素的地址,也可以看作一个指向该数组的指针
-
可以使用指针访问和操作数组中的元素,通过递增指针来遍历整个数组
-
回调函数
-
允许将一个函数作为参数传递给另一个函数,并在需要时由另一个函数调用
-
回调函数通常在异步编程中使用,当某个操作完成或满足特定条件时,会调用预先定义好的回调函数来处理相应的结果或执行相关操作
函数指针和指针函数的区别
-
函数指针:一个指向函数的指针变量、存储函数的地址,可以用于调用该函数
-
指针函数:一个返回指针的函数
空指针(NULL)、void *
-
空指针(NULL)是一个特殊的指针值,表示指针不指向任何有效的内存地址
-
void * 可以表示任意类型的指针
结构体和联合体之间的区别
-
结构体
-
结构体将不同类型的数据组合成一个整体,每个成员都有自己独立的内存空间,所有成员的值可以同时存在
-
结构体的大小通常等于其所有成员大小的总和
-
使用 struct 关键字来声明结构体,然后定义结构体的成员
-
-
联合体
-
联合体将不同类型的数据放在同一块内存空间中,同一时刻只有一个成员可以被访问
-
联合体的大小则等于其最大成员的大小
-
使用 union 关键字来声明联合体,然后定义联合体的成员
-
-
结构体和联合体内都可以定义不同类型的数据
内存泄漏和内存溢出
-
内存泄漏:在程序运行过程中,动态分配的内存空间没有被正确回收。这种情况下,当不再需要使用这块内存时,无法再访问到它,导致这块内存变得无法被重新利用。
-
内存溢出:尝试向已经分配满了的内存区域写入数据,会覆盖到其他变量、代码和数据结构等
堆和栈的区别
-
堆和栈是计算机内存中用于管理变量和数据的两种不同的存储区域
-
内存分配方式
-
栈采用静态内存分配,由编译器自动管理。
-
堆采用动态内存分配,需要手动进行申请与放。
-
-
空间大小
-
栈空间通常较小,具有固定的大小,并且通过函数调用层级来管理变量的生命周期。
-
堆空间相对较大,没有固定大小限制,可以灵活地进行内存分配。
-
-
内存管理方式
-
栈由编译器自动进行变量的分配和释放,在函数结束时会自动回收局部变量所占用的栈空间。
-
堆则需要手动进行内存的申请(如malloc、new等)和释放(如free、delete等),否则会出现内存泄漏问题。
-
-
数据访问速度
-
栈上的数据访问速度较快,因为它使用了先进后出(LIFO)的原则,并且位于CPU高速缓存中。
-
堆上分配的数据访问速度较慢,因为它不是按照顺序进行分配。
-
分区
-
栈区
-
是编译器自动分配和释放
-
里面主要放函数的参数,普通的局部变量等
-
-
堆区
-
是程序员通过 new 和 molloc 函数去分配的,对应 delect 和 free 函数回收
-
里面具体放啥由程序员决定
-
-
常量区:放置常量,不允许更改
-
代码区:放代码块,在代码运行的时候不能更改
-
静态区
-
放全局变量和被 static 修饰的局部变量
-
根据是否初始化
-
Bss 区:表示编译器没有为其分配空间、没赋初值的
-
data 区:赋初值的
-
-
大小端模式
-
字节的顺序是从高位到低位(大端)还是从低位到高位(小端)
-
大端对齐:低地址存放高位、高地址存放低位
-
小端对齐:低地址存放低位、高地址存放高位
C语言的编译过程
-
预处理:对源代码进行处理,展开头文件、宏定义,并去除注释等。生成的纯C代码文件。
-
编译:编译器将预处理后的源代码转化为汇编语言(.s文件)
-
汇编:汇编器将汇编语言代码转化为机器码指令,即可执行的二进制文件(.o文件)。
-
链接:链接器将所有需要用到的函数库和对象文件合并成一个可执行文件(.exe文件)。