C_Language_11

C_Language_11

//int b1 = 5;  //定义在主函数main前的变量存放于静态区,静态变量,作用域为所有文件
void testMemory(){  //存储在代码区
    printf("代码区\n");
    //    printf("%d",b12);  //b12在本函数中没有定义
}

在计算机的内存中,可以分为5个区,每个区都有各自的操作以及管理内存的方式
栈、堆、静态(全局)、常量、代码区是按照内存地址从大到小分配
    //    打印各个存储区域
    //    栈区
        int a = 3;//3存放于常量区
    //    堆区
        int *p = malloc(10);
    //    静态(全局)
        static int b = 5;
    //    常量
        char *s = "iphone";
    //    函数存储在代码区
        printf("栈区:%p\n",&a);
        printf("堆区:%p\n",p);
        printf("静态:%p\n",&b);
        printf("常量:%p\n",s);
        printf("代码:%p\n",testMemory);
    
栈区:函数参数或者是全局变量存储的区域
栈区内存特点:
        1.局部变量的存储空间,基本都在栈区,局部变量在函数、循环、分支中定义
        2.栈区的存储空间由高到低分配,从低到高存储
        3.栈区内存有系统负责分配和回收,开发者没有管理权限。
          定义局部变量是由系统分配存储空间,局部变量被销毁时由系统回收存储空间,
          但是存储空间中的数据没有被清空
        4.当函数、循环、分支执行结束后,局部变量的生命周期结束,不能再被使用,由系统销毁并回收存储空间。
        5.栈底、栈顶。栈底是栈区的起始位置,先定义的变量所占用的内存从靠近栈底开始分配,后定义的变量所占用的内存逐渐向栈顶分配
        6.入栈、出栈。入栈:定义新的局部变量,分配存储空间;出栈:局部变量被销毁,存储空间被收回
        7.栈的特点:先进后出,后进先出
        8.栈区会存在安全问题:在函数中返回栈内存是不安全的
        int a = 10;//高地址
        char b = 'a';
        double c = 3.4;//低地址
        printf("a的地址:%p\n",&a);//a的地址:0x7fff5fbff7cc   高
        printf("b的地址:%p\n",&b);//b的地址:0x7fff5fbff7cb   |
        printf("c的地址:%p\n",&c);//c的地址:0x7fff5fbff7c0   低
示例:
        int a;
        printf("a = %d\n",(a=3*5,a*4,a+5));//运行结果20 // 15  60  20  20后存储,先出
        printf("a = %d\n",a=3*5,a*4,a+5);//运行结果15
    
常量区(文字常量区)
常量区的特点:
        1.常量存储在常量区。常量 字符串等等
        2.常量区存储空间是由系统分配和回收
        3.程序运行结束后,常量区的存储空间被收回
        4.常量区的数据只能被读取,不能被修改。修改会造成崩溃
        char *p = "iphone";
        p[0] = "a";//不能被修改,会崩溃
        printf("%s",p);
    
静态区:全局变量和静态变量存储的区域
静态区的特点:
        1.全局变量、使用static修饰的局部变量,都存储在静态区。
        2.静态区的存储空间由系统分配和回收。
        3.程序运行结束后,静态区的存储空间被回收。静态区变量的生命周期跟程序一样长。
        4.静态变量只能初始化一次,在编译时进行初始化,
          运行期可以修改。
        5.静态变量如果没有设置初始值,默认值为0
        static int b12 = 8;//静态变量,作用域是本文件,即本函数
    
代码区:所有语句编译的CPU指令存储的区域
代码区的特点:
        1.由系统分配和回收
        2.程序结束后,有系统回收分配过的存储空间
        3.只能读,不能修改
    
堆区:由开发工者自主管理的区域(手动开辟,手动释放)
堆区特点:
        1.由开发者负责分配和回收
        2.忘记回收内存会造成内存泄露
        3.程序结束后会回收堆区内存,但是如果不能及时回收堆内存,
          程序运行期间可能会因为内存泄露,造成堆内存被全部占用,程序无法运行。
内存分配函数
malloc:
        void *malloc(size)
        void * 表示的是无类型指针,可以转化为任意类型指针。
        函数的作用:在堆区开辟指定size个字节的空间,并把空间的首地址返回。
示例:
        int *p = NULL;
        p = malloc(sizeof(int));
        *p = 4;
        printf("%d\n",*p);
示例:
        float *p = NULL;
        p = malloc(sizeof(float));
        *p = 5.4;
        printf("%.2f\n",*p);
    
分配存储空间存储数组元素,即分配多个连续的存储空间
示例:分配1个字符数组的内存,8个元素 ”iphone“
        char *p = NULL;
        p = malloc(8*sizeof(char));
        strcpy(p, "iphone");
        printf("%s\n",p);
示例:分配一个整形的数组内存,10个元素,随机产生10个30~60之间的数,存储在分配的内存空间
        int *p = NULL;
        p = malloc(sizeof(int)*10);
        for (int i = 0; i < 10; i++) {
            *p = arc4random()%(60-30+1)+30;
            printf("%d ",*p);
            p++;
        }
        printf("\n");
        typedef struct student{
            char name[20];
            int age;
        }Student;
        Student *p12 = malloc(sizeof(Student));
        strcpy(p12->name, "hanzheng");
        p12->age = 11;
        printf("%s %d\n",p12->name,p12->age);
    
        Student *p13 = malloc(sizeof(Student)*2);//结构体数组
    
释放开辟的空间:
        void free(void *):将指定的地址所对应的空间释放
        int *r = NULL;
        r = malloc(sizeof(int));  //这一块开辟的内存找不到,造成内存泄露
        r = malloc(sizeof(int));
        printf("%p\n",r);
        *r = 10;
        printf("%p %d\n",r,*r);
        free(r);//开辟空间记得释放,如果不释放,会出现内存问题,内存泄露
        r = NULL;//当空间回收之后,将指针置null安全,避免出现野指针,野指针:指针指向不属于自己控制的存储单元
        free(r);//内存问题:过度释放
calloc:
        void *calloc(int n ,size_t size);//在堆区开辟n*size个字节空间,并把空间地址返回,该函数将空间进行清0操作,在效率上比malloc低
        char *str = NULL;
        str = (char*)calloc(10,sizeof(char));
        strcpy(str, "hello");
        printf("string is :%s\n",str);
        free(str);
        str = NULL;
realloc:
        void *realloc(void*p,size_t newSize);在给定的地址空间基础上,如果当前指针空间足够,那么将地址扩大,如果空间不足,那么重新找一块新的地址按照newSize大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,然后自动释放原来指针指向的内存区域,不需要free
        int *p_old = malloc(10);
        int *p_new = realloc(p_old,150);
        printf("%p\n%p\n",p_old,p_new);
        如果返回的地址和新地址不一样。那么系统会将原来的地址进行一次free,对于realloc()操作,我们只需要释放我们新的地址空间即可
        free(p_old);//过度释放
        free(p_new);
内存操作函数:
memset(:
        void *memset(void *p,int c,size_t size)
        从给定地址开始size个字节直接重置为c,注意:该函数以字节单位进行操作。主要作用于清0
        int *array = malloc(12);
        for (int i = 0; i < 3; i++) {
            array[i] = i;
            printf("%d \n",array[i]);
        }
        全置为0
        memset(array, 0, 12);
        printf("\n");
        for (int i = 0; i < 3; i++) {
            printf("%d \n",array[i]);
        }
    
        char *p11 = malloc(10);
        memset(p11, 'a', 10);
        for (int i = 0; i < 10; i++) {
            printf("%c ",p11[i]);
        }
memcmp:
        int memcmp(void *p,void *q,size_t count);
        从给定的两个地址p和q开始比较count个字节,返回第一个不相等字节空间值的差值
        int num1[3] = {1,2,3};
        int num2[3] = {1,2,9};
        int result = memcmp(num1, num2, 9);//运行结果-6
        printf("%d\n",result);
memcpy:
        void *memcpy(void *dest,const void*source , size_t n);
        从指定scorce指向的地址向dest指向的地址单元拷贝n个字节
        char wrongName[] = "bJS141148";
        char rightName[] = "15";
        memcpy(wrongName, "B", 1);
        memcpy(wrongName+3, rightName, 2);
        printf("%s\n",wrongName);

posted @ 2015-12-03 19:46  DH_Fantasy  阅读(98)  评论(0)    收藏  举报