递归
递归必须要有结束条件,否则程序将崩溃!
实现递归要满足两个基本条件:
- 调用函数本身
- 设置了正确的结束条件
快速排序
- 基本思想:通过一趟排序将待排序数据分割成独立的两部分,其中一部分的所有元素均比另一部分的元素小,然后分别对这两部分继续进行排序,重复上述步骤直到排序完成。
动态内存管理
malloc
- 函数原型:
-void *malloc(size_t size);
为什么用void类型?
因为void类型可以转化成任何一种类型 - malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这块空间的指针。
malloc申请的空间是位于内存的堆上
free
- 函数原型:
-void free(void *ptr); - free函数释放ptr参数指向的内存空间。该内存空间必须是由malloc、calloc或realloc函数申请的。否则,该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。
该函数并不会修改ptr参数的值,所以调用后它仍然指向原来的地方(变为非法空间)
内存泄漏
导致内存泄漏主要有两种情况:
- 隐式内存泄漏(即用完内存块没有及时使用free函数释放)
- 丢失内存块地址
初始化内存空间
- 以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个同文件中:
-memset – 使用一个常量字节填充内存空间
-memcpy – 拷贝内存空间
-memmove – 拷贝内存空间
-memcmp – 比较内存空间
-memchr – 在内存空间中搜索一个字符
calloc
- 函数原型:
-void *calloc(size_t nmemb, size_t size); - calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为nmemb *size),这些内存空间全部被初始化为0。
- calloc函数与malloc函数的一个重要区别是:
-calloc函数在申请完内存后,自动初始化该内存空间为零。
-malloc函数不进行初始化操作,里边数据是随机的。
realloc
-
函数原型:
-void *realloc(void *ptr, size_t size); -
以下几点是需要注意的:
-realloc函数修改ptr指向的内存空间大小为size字节
-如果新分配的内存空间比原来的大,则就内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失。慎用!
-该函数将移动内存空间的数据并返回新的指针
-如果ptr参数为NULL,那么调用该函数就相当于调用malloc(size)
-如果size参数为0,并且ptr参数不为NULL,那么调用该函数就相当于调用free(ptr)
-除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc、或realloc函数返回
C语言的内存布局规律
- 代码段:通常是指用来存放程序执行代码的一块内存区域。内存区域通常属于只读。例如:字符串常量等
- 数据段:通常用来存放已经初始化的全局变量和局部静态变量。
- BSS段:通常是指用来存放程序中未初始化的全局变量的一块内存区域。这个区域中的数据在程序运行前将被自动初始化为数字0
堆
- 用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩展或缩小。
栈
- 是函数执行的内存区域,通常和堆共享同一片区域。
堆和栈的区别
-
申请方式:
-堆由程序员手动申请
-栈由系统自动分配 -
释放方式:
-堆由程序员手动释放
-栈由系统自动释放 -
生存周期:
-堆的生存周期由动态申请到程序员主动释放为止,不同函数之间均可自由访问
-栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能相互访问 -
发展方向:
-堆和其它区段一样,都是从低地址向高地址发展
-栈则相反,是由高地址向低地址发展