zoukankan      html  css  js  c++  java
  • C语言学习笔记之 内存管理

    内存管理

    内存分区

    普通局部变量

    定义

    // 局部变量
    // 在{}里面定义的不加任何修饰的变量 就是局部变量
    // 作用范围:离它最近的{}之间
    // 生命周期:离它最近的{}结束,局部变量就释放
    // 储存空间:栈区
    // 注意事项:
        // 局部变量 不初始化 内容随机
        // 不同范围局部变量同名 就近原则
    
    // 例
    #include <stdio.h>
    
    void test()
    {
        int num;
        printf("%d
    ",num); // 局部变量,作用域:test函数
    }
    int main()
    {
        test();
    
        return 0;
    }
    
    // 运行结果:
    4200363
    

    普通全局变量

    // 全局变量
    // 定义:在函数外定义的变量 就是普通全局变量
    // 作用范围:当前源文件和其他源文件(加extern修饰)
    // 生命周期:整个进程
    // 存储空间:全局区
    // 注意事项:
        // 普通全局变量不初始化 内容为0
        // 普通全局变量和普通局部变量同名 就近原则
    
    // 例
    #include <stdio.h>
    
    int num; // 普通全局变量
    
    int main()
    {
        printf("%d",num);
    
        return 0;
    }
    
    // 运行结果
    0
    

    静态局部变量(static修饰)

    // 静态局部变量
    // 在{}里面定义的 用static修饰 的变量 就是静态局部变量
    // 作用范围:离它最近的{}之间
    // 生命周期:整个进程
    // 储存空间:全局区
    // 注意事项:
        // 静态局部变量不初始化 内容为0
        // 静态局部变量多次初始化 只有第一次有效
    
    // 例
    #include <stdio.h>
    
    int test()
    {
        static int num = 10; // 静态局部变量
        ++num;
        printf("%d
    ",num);
    }
    
    int main()
    {
        test();
        test();
        test();
    
        return 0;
    }
    
    // 运行结果
    11
    12
    13
    

    静态全局变量

    // 静态全局变量
    // 定义:在函数外定义的 被static修饰 的变量 就是普通全局变量
    // 作用范围:只在当前源文件有效
    // 生命周期:整个进程
    // 存储空间:全局区
    // 注意事项:
        // 普通全局变量不初始化 内容为0
    

    静态函数与普通函数的区别

    // 普通函数
    int test1(){;}
    
    // 静态函数
    static int test2(){;}
    
    // 普通函数:当前源文件和其他源文件(加extern修饰)都可以使用
    // 静态函数:只可以在当前源文件使用
    

    内存分区详解

    • 代码区:存放程序的代码,即CPU执行的机器指令,并且是只读的。
    • 常量区:存放常量
    • 静态区(全局区):静态变量和全局变量的存储区域是一起的,静态区的内存直到程序全部结束之后才会被释放
    • 堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存
    • 栈区:存放函数内的局部变量,形参和函数返回值。栈区之中的数据的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理

    内存操作函数

    以mem开头

    memset内存填充函数

    #include <string.h>
    
    void *memset(void *s,int c,size_t n);
    功能:将s内存区域的前n个字节以参数c填入
    
    参数:
        s:需要操作内存的首地址
        c:需填充的字符,为unsigned char
        n:需要设置的大小
    
    返回值:s的首地址
    注意:memset遇到''不会停止
    

    memset常用来清空内存

    例:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        char s[32] = "Hello world";
    
        memset(s,'a',32); // 一般不用,没什么意义
        printf("s = %s
    ",s);
    
        // 清空s
        memset(s,0,32);
    
        return 0;
    }
    
    s = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # 由于没有''会出现乱码
    

    memcpy内存拷贝

    #include <string.h>
    
    void *memcpy(void *dest, const void *src, size_t n);
    功能:拷贝src所指的内存的前n个字节到dest所指的内存中
    
    参数:
        dest:目的内存地址
        src:源内存地址 // dest和src所指的内存不可重叠
        n:需要拷贝的字节数
    返回值:dest首地址
    

    例:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        char s[32] = "";
        char s2[32] = "Helloworld";
    
        memset(s,0,32);
        memcpy(s,s2,sizeof(s2));
    
        for (size_t i = 0; i < sizeof(s); ++i)
        {
            printf("%c",s[i]);
        }
        printf("
    ");
    
        int a[5] = {0};
        int a2[5] = {1,2,3,4,5};
    
        memcpy(a,a2,sizeof(a2));
    
        for (size_t i = 0; i < 5; ++i)
        {
            printf("%d ",a[i]);
        }
        printf("
    ");
    
        return 0;
    }
    
    Hello world
    1 2 3 4 5
    

    注意:memcpy拷贝的内存不要重叠,重叠用memmove

    memmove

    memcmp内存比较

    #include <string.h>
    
    int memcmp(const void *s1, const void *s2, size_t n);
    功能:比较s1和s2内存空间的前n个字节
    
    返回:
        相等:0
        大于:>0
        小于:<0
    

    例:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    	char s[] = "Hello world";
    	char s2[] = "hello world";
    
    	printf("%d
    ",memcmp(s,s2,sizeof(s2)));
    
    	return 0;
    }
    
    -32
    

    动态内存管理

    堆空间动态申请malloc

    malloc申请的空间需要用free手动释放
    malloc申请的地址需强制类型转换才能使用

    #include <stdlib.h>
    
    void *malloc(size_t n);
    功能:在内存的动态储存区(堆区)申请一块
    连续的长度为n字节的空间,内容不确定,一般用memset初始化
    
    返回:
        成功:分配空间的首地址
        失败:NULL
    
    void free(void *ptr);
    功能:释放ptr所指的内存空间,多次释放会出错
    
    参数:空间的首地址
    返回:无
    注意:ptr必须是由malloc分配的空间
    

    例:

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    	int *arr = NULL;
    	arr = (int*)malloc(sizeof(int));
    	if (arr == NULL)
    	{
    		printf("申请失败
    ");
    		exit(1);
    	}
    	*arr = 100;
    	printf("*arr = %d
    arr = %#x
    ",*arr,arr);
    	free(arr);
    	arr = NULL;
    
    	return 0;
    }
    
    *arr = 100
    arr = 0x4f5372a0
    

    realloc重新分配内存

    #include <stdlib.h>
    
    void *realloc(void *ptr, size_t size);
    功能:修改 ptr 指向的内存空间大小为 size 字节
    参数:
        ptr:1. 指向由先前调用 malloc、calloc 或 realloc 函数返回的内存空间
             2. 如果该参数为 NULL,相当于调用 malloc(size) 函数
        size:指定新的内存块空间大小,以字节为单位
    返回:
        1. 如果函数调用成功,返回值是指向新的内存空间的指针,由于返回类型是 void 指针(void *),所以它可以被转换成任何类型的数据。
        2. 如果函数调用失败,返回值是 NULL。
        3. 如果 realloc 函数调用失败,
        那么原始内存空间的数据并不会修改,也不会被释放或移动。
    注意:
        如果新分配的内存空间比原来的大,
        则旧内存块的数据不会发生改变;
        如果新的内存空间大小小于旧的内存空间,
        可能会导致数据丢失
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    	int num;
    	int *ptr = NULL; // 注意:这里必须初始化为NULL
    	int count = 0;
    	printf("请输入整数(0表示结束):
    ");
    	do {
    		printf(">");
    		scanf("%d",&num);
    		++count;
    
    		ptr = (int *)realloc(ptr,count*sizeof(int));
    		if (ptr == NULL) {
    			printf("内存不足
    ");
    			exit(1);
    		}
    
    		ptr[count - 1] = num;
    	} while (num != 0);
    	printf("你输入的是:
    ");
    	for (size_t i = 0; i < count; ++i) {
    		printf("%d
    ",ptr[i]);
    	}
    
    	if (ptr != NULL) {
    		free(ptr);
    	}
    
    	return 0;
    }
    
    请输入整数(0表示结束):
    >1
    >3
    >45
    >33
    >55
    >0
    你输入的是:
    1
    3
    45
    33
    55
    0
    

    calloc申请并初始化内存空间

    用法同malloc,calloc申请后会自动初始化为0

    内存操作注意事项

    1. 不要返回局部变量地址,可以返回静态局部变量地址
    2. 不要操作已被释放的堆区
    3. 不要多次释放同一个堆区

  • 相关阅读:
    阿里云ecs服务器wamp内网可以访问,外网ip、域名无法访问
    python- 粘包 struct,socketserver
    python-网络编程
    python-模块-包
    python- 异常
    python-模块 time, os, sys
    python_模块 collections,random
    python_模块 hashlib ,configparser, logging
    python_ 模块 json pickle shelve
    python-面向对象中的特殊方法 ,反射,与单例模式
  • 原文地址:https://www.cnblogs.com/zhujiangyu/p/13697932.html
Copyright © 2011-2022 走看看