diff --git "a/data/blog/c\350\257\255\350\250\200/\345\206\205\345\255\230\347\256\241\347\220\206.mdx" "b/data/blog/c\350\257\255\350\250\200/\345\206\205\345\255\230\347\256\241\347\220\206.mdx" index f2ac026..9476c96 100644 --- "a/data/blog/c\350\257\255\350\250\200/\345\206\205\345\255\230\347\256\241\347\220\206.mdx" +++ "b/data/blog/c\350\257\255\350\250\200/\345\206\205\345\255\230\347\256\241\347\220\206.mdx" @@ -20,6 +20,17 @@ summary: 内存管理 这些变量所在的内存称为`”堆“(heap)`,`”堆“所在的内存是用户手动管理的`。 +## 栈内存 vs 堆内存 +C/C++ 中有两种主要的内存分配方式:栈内存和堆内存。 + + - 栈内存:当你在函数中声明局部变量时,编译器会自动在栈上为这些变量分配内存。这种分配是自动的,且非常高效,因为栈内存的分配和释放是由编译器管理的,分配和释放的时间非常短(通过调整栈指针)。然而,栈内存有以下限制: + + 1. 栈的大小是有限的,通常只有几 MB。因此,不能在栈上分配大量内存。 + 2. 栈上的变量的生命周期是有限的,它们在函数结束时自动销毁,无法跨函数使用。 + + - 堆内存:堆内存是程序运行时的动态内存,程序员可以通过 malloc/free 或 new/delete 来手动管理堆内存。堆内存的优点是可以分配更大的内存块,且内存的生命周期由程序员控制。缺点是堆内存的分配和释放速度比栈慢,且需要程序员手动管理内存,防止内存泄漏。 + + # void指针 前面章节已经说过了,每一块内存都有地址,通过指针变量可以获取指定地址的内存块。 `指针变量必须有类型,否则编译器无法知道,如何解读内存块保存的二进制数据。` @@ -47,4 +58,25 @@ void* p = &a; printf("%c\n", *p); // 报错 ``` -上面示例中,p是一个 void 指针,所以这时无法用*p取出指针指向的值。 \ No newline at end of file +上面示例中,p是一个 void 指针,所以这时无法用*p取出指针指向的值。 + + + +# restrict 说明符 +声明指针变量时,可以使用restrict说明符,告诉编译器,该块内存区域只有当前指针一种访问方式,其他指针不能读写该块内存。这种指针称为`“受限指针”(restrict pointer)`。 + +```C +int* restrict p; +p = malloc(sizeof(int)); +``` +上面示例中,声明指针变量p时,加入了restrict说明符,使得p变成了受限指针。 +后面,当p指向malloc()函数返回的一块内存区域,就意味着,该区域只有通过p来访问,不存在其他访问方式。 + +```C +int* restrict p; +p = malloc(sizeof(int)); + +int* q = p; +*q = 0; // 未定义行为 +``` +上面示例中,另一个指针q与受限指针p指向同一块内存,现在该内存有p和q两种访问方式。这就违反了对编译器的承诺,后面通过*q对该内存区域赋值,会导致未定义行为。 \ No newline at end of file