zoukankan      html  css  js  c++  java
  • 2020.10.27 15课 内存区域划分与动态内存管理malloc calloc free

    一 内存区域划分

    一) 区域划分

    代码区 常量区 栈区 堆区 静态全局区

    1 代码区

    二进制代码

    2 常量区(文字常量区)

    字符串

    3 栈区

    由编译器自动分配和释放,存放函数的参数的值,局部变量等.

    4 堆区

    由程序员手动申请,手动释放.

    5 全局区(静态区)

    全局变量和静态变量的存储是在一起的

    #include <stdio.h>
    // 普通全局变量:定义在函数外
    int num;
    // 静态全局变量:定义在函数外 并且使用static进行修饰
    static int hp;
    int main()
    {
    	// 普通局部变量
    	int a;					// a	栈区
    	// 静态局部变量
    	static int mp;
        
    	char str[] = "abcd";	// str	栈区	abcd 常量区
    	float* p;				// p	栈区
    	char* pstr = "abcd";	// pstr	栈区	abcd 常量区
    							// 编译器可能将两个abcd优化为一份内存
    	return 0;
    }
    

    二) 生存周期,作用域

    普通全局变量(外部变量)

    作用域:从定义开始到(源)文件结束

    生存周期:从程序执行到程序结束

    普通局部变量

    作用域:函数(复合语句)内部==>当前大括号

    生存周期:从函数调用开始 到函数调用结束

    static局部变量

    作用域:同普通局部变量

    生存周期:同普通全局变量

    static全局变量

    作用域:被编译文件的剩余部分

    生存周期:同普通全局变量

    补充:

    1 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的.

    2 静态全局变量只在当前文件有效

    static

    #include <stdio.h>
    /*
    static:静态的
    特点:只会定义一次
    */
    
    int func1()
    {
    	int a = 0;
    	a++;
    	return a;
    }
    int func2()
    {
    	static int a = 0;		// 只会定义一次 
    	a++;
    	return a;
    }
    
    int main()
    {
    	func1();
    	func1();
    	printf("%d
    ", func1());		// 1
    
    	func2();
    	func2();
    	printf("%d
    ", func2());		// 3 
    
    	return 0;
    }
    
    
    

    二 动态内存管理

    使用一个头文件: #include <stdlib.h>

    使用三个函数: malloc calloc free 实现申请内存和释放内存

    一) malloc

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	// malloc
    	// 函数原型: void * __cdecl malloc(_In_ _CRT_GUARDOVERFLOW size_t _Size);
    	// 返回:void*	参数:size_t(unsigned int) 需要申请的字节数
    	// 1 使用malloc申请一个int类型大小的内存
    	int* p = (int*)malloc(1 * sizeof(int));	
    	*p = 10;
    	printf("*p = %d
    ", *p);
    /*
    int*p 指针p指向申请的内存
    (int*)  类型强转,原函数返回值是void*,所以需要强转
    1 * sizeof(int) 需要申请的字节数
    
    */
        
        
        
    	// 2 使用malloc申请八个int类型大小的内存
    	int* p1 = (int*)malloc(8 * sizeof(int));
    	*p1 = 66;
    	printf("*p1 = %d
    ", *p1);
    	*(p1 + 1) = 77;
    	printf("*(p1 + 1) = %d
    ", *(p1 + 1));
    	p1[2] = 88;
    	printf("p1[2] = %d
    ", p1[2]);
    
    	for (int i = 0; i < 8; i++)
    	{
    		p1[i] = i;
    	}
    	for (size_t i = 0; i < 8; i++)
    	{
    		printf("%3d", *(p1 + i));
    	}
    
    	return 0;
    }
    
    
    

    *(p+n)=str[n]

    二) calloc

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	// calloc
    	// 函数原型: void * __cdecl calloc(_In_ _CRT_GUARDOVERFLOW size_t _Count, _In_ _CRT_GUARDOVERFLOW size_t _Size);
    	// 返回:void*	参数: 申请的内存个数,单个内存的大小
    	// 1 使用calloc申请一个int类型大小的内存
    	int* p = (int*)calloc(1, sizeof(int));
    
    	// 2 使用calloc申10个int类型大小的内存
    	int* p1 = (int*)calloc(10, sizeof(int));
    	for (size_t i = 0; i < 10; i++)
    	{
    		p1[i] = i * 10;
    	}
    	for (size_t i = 0; i < 10; i++)
    	{
    		printf("%3d", *(p1 + i));
    	}
    
    	return 0;
    }
    

    三)free

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	// calloc
    	// 函数原型: void * __cdecl calloc(_In_ _CRT_GUARDOVERFLOW size_t _Count, _In_ _CRT_GUARDOVERFLOW size_t _Size);
    	// 返回:void*	参数: 申请的内存个数,单个内存的大小
    	// 1 使用calloc申请一个int类型大小的内存
    	int* p = (int*)calloc(1, sizeof(int));
    	free(p);		// 释放申请的内存
    	p = NULL;		// 指针置空
    
    
    	// 2 使用calloc申10个int类型大小的内存
    	int* p1 = (int*)calloc(10, sizeof(int));
    	for (size_t i = 0; i < 10; i++)
    	{
    		p1[i] = i * 10;
    	}
    	for (size_t i = 0; i < 10; i++)
    	{
    		printf("%3d", *(p1 + i));
    	}C
    	free(p1);		// 释放一段内存
    	p1 = NULL;		// 指针置空
    
    	return 0;
    }
    

    思考:

    连续申请一段内存,类似于一维数组,那么二维数组呢?

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	/*int* p0 = (int*)calloc(5, sizeof(int));
    	int* p1 = (int*)calloc(5, sizeof(int));
    	int* p2 = (int*)calloc(5, sizeof(int));
    
    	int** pp = (int**)calloc(3, sizeof(int*));
    	pp[0] = p0;
    	pp[1] = p1;
    	pp[2] = p2;
    
    	for (size_t i = 0; i < 3; i++)
    	{
    		for (size_t j = 0; j < 5; j++)
    		{
    			printf("%2d", pp[i][j]);
    		}
    		printf("
    ");
    	}*/
    
    	int lin, row;
    	printf("input line and row:");
    	scanf("%d %d", &lin, &row);
    
    	// 申请
    	int** pp = (int**)calloc(lin, sizeof(int*));
    	for (size_t i = 0; i < lin; i++)
    	{
    		pp[i] = (int*)calloc(row, sizeof(int));
    	}
    
    	// 使用
    	for (size_t i = 0; i < lin; i++)
    	{
    		for (size_t j = 0; j < row; j++)
    		{
    			printf("%2d", pp[i][j]);
    		}
    		printf("
    ");
    	}
    
    	// 释放
    	for (int i = 0; i < lin; i++)
    	{
    		free(pp[i]);
    		pp[i] = NULL;		// 可以省略
    	}
    	free(pp);
    	pp = NULL;
    	return 0;
    }
    

    注意:

    二维数组的内存是连续的 但是 像这样申请的内存 不一定连续(%99申请的列不连续,极小可能申请的列连续)
    1.如果 malloc之后没有及时的free,则内存泄漏(memory leak)
     malloc的内存free一次就可以,重复free也是未定义行为

     如果申请了两次malloc但是free一次情况:
       第一次申请的内存使用p进行了保存,接下来修改p的内存后,在也没法找到第一次申请内存的地址,有就无从释放。

      2.free只是将内存释放,并不会设为NULL, //此刻应该手动将str设为NULL,这样才不会存在隐患

    作业:

    动态数组(自动扩容)

    扩容规则:变为原来的两倍

    三 指针与函数

    四 指针小结

    一)使用指针的注意事项

    二)指针与引用对比

    	int a = 10;
    	int& b = a;
    	printf("b = %d", b);
    	// 引用:给变量取别名
    
    typedef _W64 unsigned int   size_t; 给类型取别名
    
  • 相关阅读:
    CCF201612-2 工资计算(100分)
    CCF201612-2 工资计算(100分)
    CCF201609-2 火车购票(100分)
    CCF201609-2 火车购票(100分)
    CCF201604-2 俄罗斯方块(100分)
    CCF201604-2 俄罗斯方块(100分)
    CCF201312-2 ISBN号码(100分)
    CCF201312-2 ISBN号码(100分)
    JSP---Sql Jdbc和MySql Jdbc
    JS---正则表达式验证
  • 原文地址:https://www.cnblogs.com/heerha/p/13961684.html
Copyright © 2011-2022 走看看