[C指针]内存分配(malloc、calloc、realloc、alloca)、迷途指针、内存释放free、垃圾回收(RAII、异常处理函数)

学习笔记

《深入理解C指针》
http://www.ituring.com.cn/book/1147
第2章 C的动态内存管理

本文内容

内存分配 : malloc、calloc、realloc、alloca
迷途指针
内存释放 free
垃圾回收技术 : RAII、异常处理函数


一、分配内存

malloc

#include 
#include 

int main()
{
    int* pi = (int*)malloc(sizeof(int));
    if (pi != NULL) {
        *pi = 123;
        printf("*pi: %d\n", *pi);
    }
    else {

    }
    free(pi);
    return 0;
}
  • malloc 参数是 要分配的字节数

calloc

#include 
#include 
#include 

int main()
{
    /*   calloc  会将分配的内存空间清零 */
    int* pi = (int *) calloc(5, sizeof(int));
    
    /*  等价写法  */
    int* pi2 = (int*) malloc(5 * sizeof(int));
    memset(pi2, 0, 5 * sizeof(int));


    return 0;
}
  • calloc 会将分配的内存空间清零
  • calloc 参数是 ( 元素的个数 , 单个元素需要的字节数)

realloc

void *realloc(void *ptr, size_t size);
  • 第一个参数是指向原内存块的指针
  • 第二个参数是请求的大小(可以更大、也可以更小

https://www.tutorialspoint.com/compile_c_online.php

[C指针]内存分配(malloc、calloc、realloc、alloca)、迷途指针、内存释放free、垃圾回收(RAII、异常处理函数)_第1张图片
realloc

  • 申请更小内存空间时,原始内存块很明显被重用了 且内容没有修改
#include 
#include 
#include 

int main () {
    char * string1;
    char * string2;
    string1 = (char*) malloc(16);
    strcpy(string1, "0123456789AB");
    printf("string1 Value: %p [%s]\n", string1, string1);

    string2 = realloc(string1, 6);
    printf("string2 Value: %p [%s]\n", string2, string2);
    
    string2 = realloc(string1, 66);
    printf("string2 Value: %p [%s]\n", string2, string2);
    
   return(0);
}

alloca函数(微软为malloca)

  • 在函数的帧上分配内存
  • 函数返回后会自动释放内存

二、迷途指针

  • 如果内存已经释放,而指针还在引用原始内存,这样的指针就称为迷途指针

迷途指针三种情况

  • Case1free后继续使用指针
int *pi = (int*) malloc(sizeof(int));
*pi = 5;
printf("*pi: %d\n", *pi);
free(pi);

*pi = 10;
  • Case2 : 一个以上的指针引用同一内存区域而其中一个指针被释放。如下所示,p1p2都引用同一块内存区域(称为指针别名),不过p1被释放了
int *p1 = (int*) malloc(sizeof(int));
*p1 = 5;
...
int *p2;
p2 = p1;
...
free(p1);
...
*p2 = 10; // 迷途指针
  • Case3 : 使用块语句,变量pi可能是全局变量,也可能是局部变量。不过当包含tmp出栈之后,地址就不再有效(大部分编译器都把块语句当做一个栈帧tmp变量分配在栈帧上,之后在块语句退出时会出栈)
int *pi;
...
{
    int tmp = 5;
    pi = &tmp;
}
// 这里pi变成了迷途指针
foo();

三、内存释放

free

  • 如果是在函数内分配内存,那么就应该在同一个函数内释放它
    void free(void *ptr);
int *pi = (int*) malloc(sizeof(int));
...
free(pi);

四、垃圾回收技术

RAII

  • 资源获取即初始化(Resource Acquisition Is Initialization,RAII)
  • [C++] Vector Changing Size allocator 、RAII 、 unique_ptr https://www.jianshu.com/p/b60f4021027e
  • C中使用RAII
    [C指针]内存分配(malloc、calloc、realloc、alloca)、迷途指针、内存释放free、垃圾回收(RAII、异常处理函数)_第2张图片
    在C中使用RAII
#include 
#include 
#include 


#define RAII_VARIABLE(vartype,varname,initval,dtor) \
    void _dtor_ ## varname (vartype * v) { dtor(*v); } \
    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
    
void raiiExample() {
    RAII_VARIABLE(char*, name, (char*)malloc(32), free);
    strcpy(name,"RAII Example: HELLO");
    printf("%s\n",name);
}
    
int main () {
    
   raiiExample();
   return(0);
}

RAII_VARIABLE宏,一旦变量超出作用域会自动触发释放过程。

异常处理函数

  • Microsoft Visual Studio版的C语言 限定用法
[C指针]内存分配(malloc、calloc、realloc、alloca)、迷途指针、内存释放free、垃圾回收(RAII、异常处理函数)_第3张图片
image.png
#include 
#include 
#include 


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

int main() {

    exceptionExample();
    return(0);
}
  • Exceptions in C

This is a small page for my hack in plain C (not C++) --- Implementing Exceptions in C Programming language, written by Adomas Paltanavičius.
https://adom.as/excc/

五、参考资料

  • [Valgrind]检测动态分配的内存DAM(Dynamically Allocated Memory)
    https://www.jianshu.com/p/e3bb358ccc3f
  • 使用 CRT 库查找内存泄漏
    https://docs.microsoft.com/zh-cn/visualstudio/debugger/finding-memory-leaks-using-the-crt-library?view=vs-2015
  • Boehm-Weiser Collector(http://www.hpl.hp.com/personal/Hans_Boehm/gc/)可以作为手动内存管理的替换方法,不过它不属于语言的一部分。

你可能感兴趣的:([C指针]内存分配(malloc、calloc、realloc、alloca)、迷途指针、内存释放free、垃圾回收(RAII、异常处理函数))