1,040
社区成员




这是我参加朝闻道知识分享大赛的第十篇文章
目录
C语言内存四驱模型是C语言学习过程中一个重要的概念,它帮助程序员理解程序在内存中的布局和分配情况。通过理解内存四驱模型,可以更好地掌握C语言指针、变量作用域和内存管理等方面的知识。内存四驱模型将内存划分为四个区域:栈区、堆区、数据区和代码区。
栈区是内存中的一个重要区域,用于存放函数的参数值、局部变量的值等。栈区的操作方式类似于数据结构中的栈,具有先进后出的特性。栈区由编译器自动分配和释放内存,当函数执行完毕后,栈区中的内存会自动被回收。
栈区的特性
栈区的示例
#include <stdio.h>
void change1(int a) {
a = 200;
}
void change2(int *a) {
*a = 200;
}
int main() {
int a = 100;
int b = 10;
change1(b);
change2(&a);
printf("change1 = %d, change2 = %d\n", b, a);
return 0;
}
在上面的示例中,a
和 b
是局部变量,存放在栈区。change1
函数中的参数 a
也是局部变量,存放在栈区。由于 change1
函数中的 a
是值传递,因此不会改变 main
函数中的 b
的值。而 change2
函数中的参数是 a
的地址,通过地址修改 a
的值,因此 main
函数中的 a
的值被改变。
当函数被调用时,编译器会在栈区分配内存给函数的局部变量和参数。当函数执行完毕后,这些内存会自动被释放。因此,栈区中的内存不需要程序员手动管理,也不会出现内存泄漏的问题。
堆区是内存中的另一个重要区域,用于动态分配内存。堆区的内存由程序员手动分配和释放,如果没有正确释放,可能会导致内存泄漏。
堆区的特性
malloc
、calloc
、realloc
和 free
等函数。堆区的示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getMem() {
char *p1 = NULL;
p1 = (char*)malloc(sizeof(char) * 10); // 申请内存空间
return p1;
}
int main() {
char *tmp = NULL;
tmp = getMem();
strcpy(tmp, "aaabbb"); // 向 tmp 指向的内存空间中拷贝数据
printf("hello..tmp: %s.\n", tmp);
free(tmp); // 释放内存
return 0;
}
在上面的示例中,getMem
函数使用 malloc
函数在堆区分配了 10 个字节的内存,并返回这块内存的指针。在 main
函数中,使用 strcpy
函数将字符串 "aaabbb" 拷贝到这块内存中,并打印出来。最后,使用 free
函数释放这块内存,以避免内存泄漏。
在堆区分配内存时,通常使用 malloc
、calloc
或 realloc
函数。malloc
函数用于分配指定大小的内存块,并返回一个指向该内存块的指针。calloc
函数用于分配内存并初始化所有位为 0。realloc
函数用于调整已分配内存块的大小。
释放堆区内存时,使用 free
函数。free
函数接受一个指向已分配内存块的指针,并释放这块内存。如果忘记释放堆区内存,可能会导致内存泄漏,即这块内存将永远无法被回收。
数据区用于存放全局变量、静态变量和常量字符串等。数据区通常分为常量区和全局区/静态区。
常量区用于存放常量,通常是字符串常量。在 C 语言中,字符串常量在编译时会被存储在常量区,并且编译器会对相同的字符串常量进行优化,使它们共享同一块内存。
#include <stdio.h>
char* getStr1() {
char *p1 = "aaaaa";
return p1;
}
char* getStr2() {
char *p2 = "aaaaa";
return p2;
}
int main() {
char *p1 = NULL;
char *p2 = NULL;
p1 = getStr1();
p2 = getStr2();
printf("p1: %s , p2: %s\n", p1, p2);
printf("p1: %p , p2: %p\n", (void*)p1, (void*)p2);
return 0;
}
全局区/静态区在上面的示例中,getStr1
和 getStr2
函数都返回指向字符串 "aaaaa" 的指针。由于字符串 "aaaaa" 是常量,编译器会对其进行优化,使 p1
和 p2
指向同一块内存。因此,打印出的地址是相同的。
全局区/静态区用于存放全局变量和静态变量。全局变量是在函数外部声明的变量,它们在程序的整个生命周期内都存在。静态变量是在函数内部使用 static
关键字声明的变量,它们在函数调用之间保持其值。
#include <stdio.h>
int globalVar = 100; // 全局变量
void func() {
static int staticVar = 200; // 静态变量
printf("globalVar = %d, staticVar = %d\n", globalVar, staticVar);
staticVar++;
}
int main() {
func();
func();
return 0;
}
在上面的示例中,globalVar
是一个全局变量,它在程序的整个生命周期内都存在。staticVar
是一个静态变量,它在 func
函数调用之间保持其值。因此,每次调用 func
函数时,staticVar
的值都会递增。
代码区用于存放程序的二进制代码,即机器指令。代码区在程序加载到内存时由操作系统创建,并且在程序运行期间不可修改。
代码区的特性
代码区的示例
#include <stdio.h>
void hello() {
printf("Hello, World!\n");
}
在上面的示例中,hello
函数和 main
函数的二进制代码都被存储在代码区中。当程序运行时,操作系统将代码区加载到内存中,并跳转到 main
函数的入口点开始执行。
C语言内存四驱模型将内存划分为栈区、堆区、数据区和代码区四个区域。每个区域都有其特定的用途和特性。栈区用于存放函数的参数和局部变量,由编译器自动分配和释放内存。堆区用于动态分配内存,需要程序员手动管理。数据区用于存放全局变量、静态变量和常量字符串等。代码区用于存放程序的二进制代码,是只读且固定大小的。
通过理解内存四驱模型,可以更好地掌握C语言中的内存管理、变量作用域和指针等方面的知识。这对于编写高效、可靠的C程序具有重要意义。同时,也有助于理解C语言程序在内存中的布局和运行过程,从而能够更好地进行程序调试和优化。