动态内存开辟

【1】内存分配有三种方式:
1.从静态存储区分配,生命周期随程序的结束而结束,比如全局变量,static变量
2.从栈空间分配,函数调用完其被自动释放
3.从堆空间分配,即动态内存开辟,比如:malloc,calloc,realloc,何时申请何时释放
【2】malloc:
函数原型void* malloc (size_t size)
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针
- 如果开辟成功,则返回一个指向开辟好空间的指针
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
- 返回值的类型是 void* ,所以malloc函数并不不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准未定义的,取决于编译器。
- free前后不会修改指针的指向,指针地址仍然不变,free后目标指针会变为野指针,最好设置为NULL
- malloc申请的空间可以用memset函数进行初始化
【3】calloc:
函数原型:void* calloc (size_t num, size_t size)
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0
【4】realloc:
函数原型:void *realloc( void *memblock, size_t size )
对malloc申请的内存进行大小的调整
-realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变.对于缩小,则被缩小的那一部分的内容会丢失.realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址.相反,realloc返回的指针很可能指向一个新的地址
-realloc是从堆上分配内存的.当扩大一块内存空间时,当堆上内存足够大,可以满足扩大要求时,它就在原来基础上扩大字节数,返回原来内存空间的地址;当不满足扩大要求时,则realloc在堆上找一个有足够大小的新空间,将原来数据整体拷贝到新的位置,并且返回新地址,即realloc可能发生数据搬移。

void test()
{
    int* ptr = (int*)malloc(10);
    int* p = (int*)realloc(ptr, 40);
    int* pp = (int*)realloc(ptr, 200);
    if (p != NULL) {
        printf("%#p\n", ptr);//030B4BF8
        ptr = p;
        printf("%#p\n", ptr);//030B4BF8,地址相同
        ptr=pp;
        printf("%#p\n", ptr);//030BDD30,地址不同
    }
}

【5】常见的内存错误:
1.内存分配未成功,但是我们却使用了它。
如果是函数传参问题,则在函数内部用assert断言;如果是用malloc等申请内存,则应该用if语句进行判断
2.内存分配成功,但是没有初始化
3.忘记释放内存,造成内存泄露(动态内存的申请与释放必须配对)
4.释放了内存却依然继续使用它
-函数的 return 语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。
-使用 free释放了内存后,没有将指针设置为 NULL。导致产生“野指针
【6】几点建议:

1 用 malloc 等申请内存之后,应该立即检查指针值是否为 NULL。防止使用指针值为 NULL 的内存。 
2 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 
3 避免数组或指针的下标越界,特别要当心发生“多 1”或者“少 1” 操作。 
4 动态内存的申请与释放必须配对,防止内存泄漏。 
5 用 free 释放了内存之后,立即将指针设置为 NULL,防止产生“野指针

你可能感兴趣的:(c学习笔记)