02.关于C语言的内存管理

本文详细介绍了C语言中的全局变量与局部变量、静态变量与非静态变量的区别,以及内存分区中的栈区、堆区、全局/静态区和字符串常量区。讲解了静态函数与非静态函数的访问范围,以及内存申请与管理,包括堆栈分配、动态内存malloc/free的使用。同时,通过示例展示了memset、memcpy和memmove等内存操作函数的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.全局变量与局部变量:

全局变量 :main函数执行之前创建,main函数执行结束,内存回收

局部变量:内存函数调用时,分配内存;函数调用结束,回收内存。

2.静态变量与非静态变量

区别:

void test() {
	int a = 10;
	++a;
	printf("%d\n", a);
}


int main()
{
	test();   //输出11
	test();   //输出11
	
}

 void test() {
	static int a = 10;
	++a;
	printf("%d\n", a);
}


int main()
{
	test();   //输出11
	test();   //输出12	
}

解释:非静态变量的空间在函数结束时销毁,静态变量的空间则不会,会在main函数执行结束之后销毁。

3.静态函数与非静态函数:

静态函数只能在当前文件中访问,而非静态函数可以在整个项目中任何的   .C 文件中访问。

以非静态函数为例:

在other.c类中:

void func() {
	printf("hello world!\n");
}

在主类中可以直接调用:

void func();   //此步骤为声明函数

int main()
{
	func();   //输出“hello world!”
}

PS.如果是 static void func():静态函数,则不可以跨文件访问。

4.内存分区

4.1内存分为代码区以及数据区。其中代码区用来放代码,剩下的变量放在数据区。

数据区分为:堆区,栈区,字符串常量区,全局/静态区:

(1)栈区:自动申请,自动释放。

1.函数的参数

2.函数内部定义的局部变量

3.可读可写 

(2)字符串常量区: 编译器在程序执行之前分配内存,程序结束之后回收内存

1.双引号括起来的字符串

2.只读,不能修改

(3)全局/静态区:编译器在程序执行之前分配内存,程序结束之后回收内存

1.全局变量

2.静态全局变量

3.静态局部变量

4.可读可写

(4)堆区:手动管理内存,释放内存

1.根据需要申请任意大小的内存

2.根据需要选择在合适的时间释放内存(如果申请了没有释放,会造成内存泄漏)

申请内存用malloc(),释放内存用free().

int main()
{   
    //1.给int类型分配内存
    int* p1 = (int*)malloc(4);   //在堆上申请了4个字节的内存
    *p1 = 30;  //给这块内存赋值
    printf("%d\n", *p1);  //输出30
    free(p1);  //手动释放内存(此时内存就不能再使用了)

    //2.给double类型分配内存
    double* p2 = (double*)malloc(sizeof(double));  //开辟8个字节
    *p2 = 3.14;
    printf("%f", *p2);   //输出3.140000
    free(p2);
}

5.内存申请与管理

5.1整形

int g_a = 100;  //全局区
void test01() {
    int a = 100;  //栈区
    static int b = 20;  //静态区

    int* p = (int*)malloc(sizeof(int));   //堆区
    *p = 30;
    free(p);

}

5.2字符串

//字符串在堆与栈上的表示
void test02() {
     char p1[] = "hello world!";  //字符串常量区
     char* s = "hello world!";    //在栈区分配字符串


    //在堆区分配内存
    int length = strlen(p1) + 1;  //考虑到结尾的/0
    char* str = (char*)malloc(length);
    strcpy(str, p1);  //将字符串拷贝到str空间中
    printf("%s", str);
    free(str);       //释放堆内存
}

5.3数组

//数组在堆与栈上的表示
void test03() {
    int arr[] = { 10,20,30 };  //栈区

    //堆区
    int length = sizeof(int) * 3;
    int* arr3 = (int*)malloc(length);  //根据大小开辟空间

    *arr3 = 100;
    *(arr3 + 1) = 200;
    *(arr3 + 2) = 300;

    //遍历输出
    for (int i = 0; i < 3; i++)
    {
        printf("%d", *(arr + i));
    }

    free(arr3);   //释放堆内存
}

5.4按照需要来分配内存

//根据需要分配内存
void  test04() {
    int num = 0;
    printf("请输入数组的长度");
    scanf("%d",&num);

    int* arr = (int*)malloc(sizeof(int) * num);

    if (NULL == arr) {
        printf("内存申请失败");  //malloc可能内存申请失败,申请失败就返回null,申请成功就返回内存首元素地址
    }

    //给数组元素赋值
    for (int i = 0; i < num; i++)
    {
        *(arr + i) = 100 + 100 * i;
    }

    //遍历输出
    for (int i = 0; i < num; i++)
    {
        printf("%d\n", *(arr + i));
    }

    if(arr!=NULL){   //先判断是否为空,不为空的情况下,再调用free函数
        free(arr);
        arr=NULL;
    }
}

总结:

全局区:项目中所有的文件共享,变量或函数。

      extern 类型,变量名

      返回值类型,变量名

静态区:只要函数,变量加上static关键字,就只能在当前文件中访问。

字符串常量区:双引号括起来的字符串,不可修改

堆区与栈区:

堆区栈区
内存由开发人员自己申请,自己释放,忘记free会 导致内存泄漏内存由系统自动管理              
内存比较大,大量的数据需要放到堆区栈区比较小,大数据不要放上去                                                                  
内存管理效率比较低内存管理效率较高

ps.1.栈空间占用如果超过最大上限,会出现stack overflow

     2.有些数据,我们需要控制它的生命周期,将数据放到堆上

     3.堆区可以采用内存池进行优化,减少maollc和free的次数:

              1.程序一运行,一次性malloc一大块内存

              2.当程序需要运行时,找到自己的内存池使用

              3.用完之后 放回内存池

6. 内存操作

头文件:#include<memory.h>

memset: 初始化内存

memcopy:内存拷贝,将内存中的字节拷贝到另一个内存,不能出现内存重叠。(字符串拷贝还是建议strcopy)

memmove:内存移动,可以处理内存重叠,但是效率低于memcopy

memcmp:内存比较

1.memset:三个参数分别代表初始化内存的首地址,将内存初始化为什么值,从首地址开始多少个字节


int main()
{
	//1.以数组为例
    int arr[10];

    memset(arr, 0, sizeof(arr));  

	for (int i = 0; i < 10; i++)
	{
		printf("%d", *(arr + i));        //输出10个0
	}

	//2.以整形为例
	int a = 410;
	memset(&a, 0, sizeof(int));
	printf("%d", a);           //输出为0


	//3.以字符串为例
	char* s = (char*)malloc(sizeof(char) * 32);
	memset(s, 0, 32);            //输出为空
	printf(" %s", s);
	free(s);
}

2.memcopy与memmove

  2.1 memcpy的使用


void test01() {
	int a = 10;
	int b = 20;
	printf("%d %d\n", a, b);  //输出10  20
	memcpy(&a, &b, 4);
	printf("%d %d\n", a, b);  //输出20  20
}

2.2用memcpy交换两个变量的值

void test02() {
	int a = 10;
	int b = 20;
	int temp = 0;

	memcpy(&temp, &a,4);
	memcpy(&a, &b,4);
	memcpy(&b, &temp, 4);

	printf("%d %d", a, b);    //输出20 10
}

2.3理解内存,指针的类型

void test06() {
	int a = 10;
	const char* p = "abc";      //考虑到\0
	memmove(&a, p, 4);  
	printf("%s", (char*)&a);
}

2.4memmove的使用方法

void test03() {
	int arr[] = { 1,2,3,4,5 };

	//遍历输出
	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", arr[i]);   //输出1 2 3 4 5
	}

	//将后四位移动到前四位
	memmove(arr, arr + 1, 4);


	//遍历输出
	for (int i = 0; i < 5; i++)
	{
		printf("%d", arr[i]);     //输出2 2 3 4 5
	}

}

3.memcmp的使用

void test05() {
	int a = 10;
	int b = 10;
	if (memcmp(&a, &b, 4) == 0) {
		printf("相等");
	}
	else {
		printf("不相等");
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值