C指针(3):动态内存

动态内存

1.内存泄漏

如果不再使用已分配的内存却没有将其释放就会发生内存泄漏

  • 丢失内存地址: 同一个指针被malloc()函数多次赋值导致之前的赋值的内存地址丢失; 指针赋值为null导致内存地址丢失
  • 隐式内存泄漏

2.动态内存分配函数

//malloc函数原型
void* malloc(size_t);
//如果malloc的参数是0,其行为是实现相关的:可能返回NULL指针,也可能返回一个指向分配了0字节区域的指针。
//如果malloc函数的参数是NULL,那么一般会生成一个警告然后返回0字节

//当malloc无法分配内存时会返回NULL,在使用它返回的指针之前先检查NULL是不错的做法
int *pi = (int*) malloc(sizeof(int));
if(pi != NULL) {    
    // 指针没有问题
} else {   
    //无效指针
}

//初始化静态或全局变量时不能调用函数
static int *pi;
pi = malloc(sizeof(int));

//calloc在分配的同时清空内存将内容置为0
void *calloc(size_t numElements, size_t elementSize);

//用malloc函数和memset函数可以得到同样的结果
/*
memset函数会用某个值填充内存块。
第一个参数是指向要填充的缓冲区的指针,
第二个参数是填充缓冲区的值,
第三个参数是要填充的字节数
*/
int *pi = malloc(5 * sizeof(int));
memset(pi, 0, 5* sizeof(int))
    
//realloc函数会重新分配内存,第一个参数是指向原内存块的指针,第二个是请求的大小
void *realloc(void *ptr, size_t size);

//free函数
void free(void *ptr);

3.迷途指针

指针指向的地址已被释放,但指针仍在引用原始内存的指针,成为迷途指针

int *p1 = (int*) malloc(sizeof(int));
*p1 = 5;
int *p2;
p2 = p1;
free(p1);
//p1,p2成为迷途指针

int *pi;
...
{    
    int tmp = 5;
    pi = &tmp;
}// 这里pi变成了迷途指针
foo();

//处理方法
//释放指针后置为NULL,后续使用这个指针会终止程序.
//有些系统(运行时或调试系统)会在释放后覆写数据.在不抛出异常的情况下,如果程序员在预期之外的地方看到这些值,可以认为程序可能在访问已释放的内存
//用第三方工具检测迷途指针和其他问题

4.垃圾回收

  • 资源获取即初始化(Resource Acquisition Is Initialization,RAII): 即使有异常发生,这种技术也能保证资源的初始化和后续的释放。分配的资源最终总是会得到释放

  • 异常处理函数: try块包含任何可能在运行时抛出异常的语句。不管有没有异常抛出,都会执行finally块,因此也一定会执行free函数

    void exceptionExample() { 
        int *pi = NULL;
        __try {       
            pi = (int*)malloc(sizeof(int));
            *pi = 5;        
            printf("%d\n",*pi);
        }   
        __finally { 
            free(pi);   
        }
    

你可能感兴趣的:(C指针(3):动态内存)