C/C++基础
一、 静态变量、全局变量及extern关键字
1、代码块内部的静态变量只能由此代码块内部访问,代码块外的静态变量只能由定义这个变量的文件访问,静态函数只能被定义这个函数的文件访问。
2、全局变量的生存周期为整个程序的生存周期,可以为本文件中的其他函数公用,有效范围为从定义变量的开始位置到本源文件结束。
3、extern的作用是“外部变量声明”,用于拓展全局变量的定义域,如果想要在全局变量定义之前使用该变量,就应该在使用之前加extern声明变量,使作用于从生命开始到本文件结束。
4、如果工程由多个源文件组成,在一个源文件(max.c)中想引用另一个源文件(main.c)中已经定义的外部变量,只需要在引用变量的文件中(max.c)使用extern关键字声明即可。
二、内存
1、代码区
程序被操作系统加载到内存的时候,所有的可执行代码都会加载到代码区,这块内存在程序运行期间是不变的。“int a=0;”语句会被拆分成“int a;”和"a=0",定义变量的“int a” 并不是代码,它在程序编译时就已经被执行了,放到代码区的只有“a=0”语句。
2、静态区
静态区存放程序中所有的全局变量和静态变量。
3、栈区(stack)
栈是一种先进后出的内存结构,所有的自动变量、函数形参都存储在栈中,这个动作由编译器自动完成。栈区在程序运行期间是可以随时更改的。当一个自动变量超出作用域时,自动从栈中弹出。
(1)每个线程都有自己专属的栈。
(2)栈的最大尺寸是固定的,超出则会引起栈溢出。
(3)变量离开作用域后栈上的内存会自动释放。所以不能将一个栈变量的地址通过函数的返回值返回。
(4)栈是从高地址向低地址方向增长。
(5)在C语言中,函数参数的入栈顺序是从右到左。
4、堆区(heap)
堆和栈一样都是在程序运行时可以随时修改的内存区域,但是没有栈那样先进后出的顺序。堆是一个大容器,容量远大于栈。但是在C/C++语言中,堆内存空间的申请和释放需要手动通过代码完成.
malloc与free
malloc函数用于在堆中分配制定大小的内存,单位为字节(Byte),函数返回void * 指针。free负责在代码堆中释放malloc分配的内存。malloc和free一定要成对使用。
注意:如果需要返回一个函数内定义的变量的地址,可以通过函数返回一个堆地址{int *p = (int *)malloc(sizeof(int));},但是一定要记得通过free函数释放申请的内存空间。
最后:操作系统管理内存时,最小的单位不是字节,而是内存页。32位操作系统的内存页一般是4K,内存页越大,内存浪费越多,但是操作系统的内存调度效率越高,不用频繁分配和释放内存;内存页越小,内存浪费越少,但是操作系统内存调度效率低,需要频繁分配和释放内存。
三、大小端
大端存储:把一个数的低位字节序内容放到高地址处,高位字节序的内容放在低地址处。
小端存储:把一个数的低位字节序内容放到低地址处,高位字节序的内容放在高地址处。

如何检测电脑是按照哪种方式存储的?
1、利用共用体(union)来检测
union Un { char c; int i; }un;
共用体中char型变量和Int型变量共用同一块空间,把 i 赋值为1,那么整个空间都是1,然后获取 c 的值,如果返回的是1,那么当前模式是小端存储,反之为大端存储。

2、利用指针
整型指针每次偏移4个字节,字符类型指针每次偏移1个字节。
int a = 1;
char* p = (char*)&a;
return *p;
如果是大端存储返回0,小端存储返回1。
四、野指针
1、指针变量中的值是非法内存地址(指向的是不可用内存地址)。NULL指针并无危害,不是野指针。
2、野指针的由来
(1)局部指针变量未初始化。
(2)指针所指向的变量在指针之前被销毁。
(3)使用了已经释放过的指针。
(4)进行了错误的指针运算。
(5)进行了错误的强制类型转换。
3、如何避免野指针
(1)、决不返回局部变量和局部数组的地址。
(2)、任何变量定义后都进行初始化。
(3)、字符数组必须确认0结束符后才能成为字符串
(4)、任何使用与内存相关操作的函数必须指定长度信息。
4、常见内存错误
(1)、结构体成员指针未初始化。
(2)、结构体成员指针未分配足够用的内存。
(3)、内存分配成功但是并未初始化。
(4)、内存操作越界。
5、内存总结
(1)、内存错误的本质在于指针保存的地址为非法值。指针变量未初始化,保存的是随机值。进行指针运算时可能导致内存越界。
(2)、内存泄漏源于malloc与free不匹配。malloc次数多于free时,产生内存泄漏。malloc次数少于free时,程序可能会崩溃。

浙公网安备 33010602011771号