1. static作用
- 限制作用域
static修饰的全局变量或函数 ,仅在当前文件内可用,其他文件不能引用
static修饰的局部变量只能在本函数中使用。
- 延长生命周期
static修饰的变量生命周期为整个程序
- 存放位置
static修饰的变量存放在静态区
- 初始化
static变量未赋初值时初值为0,且只初始化一次
2. const的作用
const 含义是常量化
可以修饰变量,可以修饰指针。
当修饰变量时,在定义时需要赋初值,定义后不能再修改其值;
当修饰指针时,const位置不同,修饰的指针指向或内容不能改变。
char *const a 指向不可修改,内容可以修改
char const *a 内容不可以修改,指向可以修改
const char *const a 内容和指向都不可以修改
3. typedef和define的区别
- 原理不同:
define是预处理指令,在预处理时进行简单的字符串替换,不进行类型检查。
typedef是关键字,在编译时处理,具有类型检查功能。
- 功能不同:
define不仅可以为类型取别名,还可以定义常量、变量、编译开关等。
typedef主要用于定义类型的别名,增加代码的可读性和类型安全性。
- 作用域不同:
define没有作用域的限制,只要之前预定义过的宏,在以后的程序中都可以使用。
typedef有自己的作用域,不会影响到其他作用域的定义。
- 对指针的操作不同:
define定义的宏在处理指针时需要进行特殊的处理,否则可能会导致错误。
typedef定义的类型别名在处理指针时更加方便和安全。
- 内存占用不同:
define定义的宏在预处理阶段进行文本替换,可能会产生额外的代码和内存占用。
typedef定义的类型别名不会产生额外的内存占用,只是为已有类型赋予新的名称。
4. define和枚举的区别
- #define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。
- 一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
- 枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。
枚举是一种用户自定义的数据类型,它为一组相关的整数常量赋予了有意义的名称,枚举里成员系统会自动赋初值,第一个成员为0,依次类推;如果程序员想赋值的,假设第一个成员赋值为1,那么第二个成员系统会赋值为2,依次类推
5. volatile作用
volatile是一个关键字,用于在 C 和 C++ 中修饰变量,它主要用于告诉编译器该变量的值可能在程序执行期间发生变化,从而禁止编译器对该变量进行优化。
- 告知编译器不要优化: 优化代码时,会对变量进行优化,如寄存器优化、常量传播等,以提高执行效率。但对于被 volatile 修饰的变量,编译器会认为其值可能在程序执行期间被意外地更改,因此不会进行优化,确保变量的值每次都从内存中读取。
- 防止可能会存在多个线程或处理器同时访问同一个变量时出现问题:如果该变量不使用 volatile 修饰,编译器可能会将其缓存到寄存器或者优化编译器缓存变量值,这样可能导致线程间不同步或者中断处理程序无法正确获取最新的变量值。而使用 volatile 修饰后,编译器每次都会从内存中读取变量的值,确保变量的值始终是最新的。
- 与外部设备的交互: 当程序与外部设备进行交互时,如硬件寄存器或存储映射 I/O 等,外部设备可能会在任何时候更改这些变量的值。在这种情况下,使用 volatile 修饰这些变量可以确保程序正确读取设备的状态,而不会受到编译器的优化干扰。
到底是怎么优化的?可以看下面的例子
volatile关键字的作用:防止变量被编译器优化_volatile关键字的作用怎么不让编译器不被优化-优快云博客
6. Extern作用
外部引用,引用其他文件中定义的全局变量或函数。
7. sizeof和strlen区别
strlen是库函数,用于计算字符串的长度;当计算字符串长度时不包含`\0`;
sizeof是关键字,用于计算变量、数组、数据类型等所占内存空间的大小;
8.三目运算符,逗号运算符
单运算符 ++ -- ~ !
双目运算符 + - * /
三目运算符:有三个表达式 (表达式1?表达式2:表达式3)
补充:逗号运算符:用小括号括起来,逗号分割多个表达式,结果为最后一个表达式的结果 a=1; c=(a+2, 4+5) //c=9
局部变量、全局变量
类别 | 定义位置 | 作用域 | 生命周期 | 存储位置 | 默认初始值 | 能否被修改 | 示例 |
局部变量 | 函数或代码块 {} 内部 | 仅在定义它的函数/块内有效 | 函数调用时创建,返回时销毁 | 栈(Stack) | 未初始化是随机值 | ✔️ 可修改 | int x = 10; |
静态局部变量 | 函数内部 + static | 仅在定义它的函数内有效 | 程序启动时初始化,结束时销毁 | 全局区(静态存储区) | 0(自动初始化) | ✔️ 可修改 | static int y = 20; |
全局变量 | 所有函数外部 | 整个文件(可被 extern 跨文件访问) | 程序启动时创建,结束时销毁 | 全局区(静态存储区) | 0(自动初始化) | ✔️ 可修改 | int global = 30; |
静态全局变量 | 文件内部 + static | 仅在当前文件内有效 | 程序启动时创建,结束时销毁 | 全局区(静态存储区) | 0(自动初始化) | ✔️ 可修改 | static int file_scope = 40; |
常量(const) | 任意位置 + const | 遵循变量作用域规则 | 同变量规则 | 常量区(或栈/全局区) | 必须显式初始化 | ❌ 不可修改 | const int MAX = 100; |
字符串常量 | 直接写字符串字面量 | 全局可见 | 程序运行期间 | 常量区(只读) | 自动初始化 | ❌ 不可修改 | char* s = "hello"; |
内存管理:栈、堆、全局区、常量区、内存泄漏
内存区域 | 存储内容 | 生命周期 | 管理方式 | 特点 |
栈(Stack) | 局部变量、函数参数、返回地址 | 函数调用时分配,函数返回时释放 | 自动管理(编译器) | 速度快,大小有限 |
堆(Heap) | 动态分配的内存(malloc/new) | 手动分配,手动释放(free/delete) | 手动管理(程序员) | 灵活,可能内存泄漏 |
全局区(静态存储区) | 全局变量、静态变量(static) | 程序启动时分配,程序结束时释放 | 自动管理 | 整个程序生命周期有效 |
常量区 | 字符串常量、const 变量 | 程序启动时分配,程序结束时释放 | 只读,不可修改 | 存储常量数据 |
代码区 | 程序二进制代码(机器指令) | 程序加载时分配 | 只读 | 存储可执行代码 |
内存泄漏(Memory Leak)
- 是程序运行中出现的一种错误情况,指已动态分配的堆内存(或其他需手动管理的内存区域),在不再需要使用时,未被正确释放,导致这部分内存无法被程序后续复用,进而使程序占用的内存不断增加。比如在C++中,用`new`分配了内存,却忘记用`delete`释放,随着程序持续运行、多次这样的操作,可用内存会逐渐被“泄漏”掉。长期运行的程序(如服务器程序)若存在内存泄漏,可能引发内存耗尽,导致程序崩溃等严重问题。