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

    本次主要学习和理解C语言中的内存管理

    1、存储区划分

     按照地址从高到低的顺序:栈区堆区静态区常量区代码区

     1> 栈区局部变量的存储区域

      局部变量基本都在函数循环分支中定义

      栈区的内存空间由系统自动分配和回收

      栈顶,栈底:先定义的局部变量存储区域从栈底开始分配,后定义的局部变量向栈顶分配

      特点:先进后出,后进先出

      当函数循环分支结束后,局部变量的生命周期结束,不能被使用,由系统自动回收内存空间 

     1 void test1() {
     2     int a = 100;
     3 }
     4 
     5 void test2() {
     6     int a;  // 栈区不会将数据清空,故输出为上个变量的值
     7     printf("a = %d
    ", a);
     8 }
     9 int main(int argc, const char * argv[]) {
    10      test1();
    11      test2(); 
    12 }

    运行结果

      运行的结果a = 100函数test1()中的值,只是当函数test1()运行结束后,栈区内存被自动回收,但是栈区不会数据清空,当函数test2()再定义一个变量且不进行初始化时,输出就是上个变量的值。 

      栈区的内存安全问题:在函数中返回栈区的地址是不安全的!

     2> 静态区静态变量全局变量的存储区域

      静态区的内存空间由系统自动分配回收

      生命周期和整个程序一样长

    1 int test3(int num) {
    2     static int s = 5;
    3     s++;
    4     return num += s;
    5 }
    6 int main(int argc, const char * argv[]) {
    7   printf("%d
    ", test3(5));
    8   printf("%d
    ", test3(5));
    9 }

    运行结果

      为什么第二次的运行结果是12呢?

      因为用static修饰的变量称为静态变量,它只能初始化一次,第二次函数调用时,static int s = 5; 没有执行,故 s 的值为6,最后的结果是12

     3> 常量区:常量的存储区域

      常量区的内存空间由系统自动分配回收

      常量区的内容只能读取不能修改

     4> 代码区:所有的语句编译二进制指令存放在代码区

      代码区的内存空间由系统自动分配回收

      代码区的内容只能读取不能修改

      程序结束后,代码区的内存空间由系统回收

     5> 堆区:由编程人员手动管理的区域(手动申请,手动释放)

    2、内存分配函数

     1> void *malloc(size)

      void *任意类型的指针

      函数的作用:在堆区申请size个字节的存储空间,然后把存储空间的首地址返回

       在堆区申请一块内存空间存放字符串

    1     char str[] = "zifuchuan";
    2     char *p = malloc(strlen(str) + 1);
    3     
    4     strcpy(p, str);
    5     printf("%s
    ", str);

       在堆区申请一块内存空间存放结构体变量

    1     Student stu = {"xiaoming", 16, 'm'};
    2     
    3     Student *p = malloc(sizeof(Student));
    4     
    5     *p = stu;

       *p是结构体指针,结构体指针访问结构体成员变量的两种方法如下:

       第一种:(*p).成员变量名

     1 printf("第一种:(*p).成员变量名:name = %s, age = %d, gender = %c ", (*p).name, (*p).age, (*p).gender); 

       第二种:使用指向运算符:-> ,格式:结构体指针变量(p) -> 成员变量

     1 printf("第二种:使用指向运算符:->:name = %s, age = %d, gender = %c ", p->name, p->age, p->gender); 

     2> void free(void *)

      释放开辟的存储空间

      完整的管理堆区内存代码

    1     int *p = malloc(sizeof(int));
    2     *p = 10;
    3     printf("%d
    ", *p);
    4     free(p);
    5     p = NULL;

      在C语言中访问空地址的存储空间会发生崩溃

    1  int *p = malloc(sizeof(int));
    2  *p = 10;
    3   printf("%d
    ", *p);
    4   free(p);
    5   p = NULL;
    6     
    7   printf("%d
    ", *p);//访问空地址

    运行结果

      野指针异常

      野指针:指针指向了不属于自己管理的存储区域

    1     int *p = malloc(sizeof(int));
    2     *p = 10;
    3     printf("%d
    ", *p);
    4     free(p);
    5     printf("%d
    ", *p); // 野指针异常

    练习输入3个单词,动态分配内存保存单词,并在最后输出。

    提示:定义一个指针数组 char * words[3] = {0}; 保存堆区空间的地址,堆区空间存储数据。

     1     char *words[3] = {0};
     2     char string[30] = {0};
     3     for (int i = 0; i < 3; i++) {
     4         printf("请输入一个单词:
    ");
     5         scanf("%s", string);
     6         getchar();
     7         
     8         // 根据单词的长度,在堆区开辟存储空间
     9         words[i] = malloc(strlen(string) + 1);
    10         // 把输入的字符串拷贝到堆区内存中
    11         strcpy(words[i], string);
    12     }
    13     printf("输出:
    ");
    14     for (int i = 0; i < 3; i++) {
    15         printf("%s
    ", words[i]);
    16         free(words[i]);
    17     }

    3、其他的内存操作函数

     1> void *calloc(int n, unsigned size)

      在堆区申请n * size 个字节的存储空间,并把存储空间的首地址返回

      会将存储空间做清0操作效率比malloc低

    1     int *p = malloc(sizeof(int) * 4);
    2     printf("%d %d %d %d
    ", *p, *(p + 1), *(p + 2), *(p + 3));
    3     int *q = calloc(4, sizeof(int));
    4     printf("%d %d %d %d
    ", *q, *(q + 1), *(q + 2), *(q + 3));

    运行结果

     2> void *realloc(void *, size)

      在给定的地址空间的基础上,如果当前指针的地址足够大,那么将地址扩大,如果空间不足,那么重新找一块新的存储空间,然后释放原来指针指向的存储空间,把新的地址返回

    1     int *p_old = malloc(sizeof(int));
    2     printf("%p
    ", p_old);
    3     
    4     int *p_new = realloc(p_old, 12);
    5     printf("%p
    ", p_new);

     3> void *memset(void *, int, size)

      在给定的地址空间开始,将 int 型的数值拷贝 size

    1     int *p = malloc(sizeof(int));
    2     memset(p, 0, 4); // 将p指向的存储空间的数据置为0

     4> void *memcpy(void *p, const void *q, unsigned long size)

      从q指向的存储空间开始拷贝size个字节的数据到p指向的存储空间

    1     char name[] = "hello";
    2     memcpy(name, "hi", 2);
    3     printf("%s
    ", name);

     5>int memcmp(const void *p, const void *q, size)

      从p,q指向的地址开始比较size个字节的数据,相等为0,不等为-1

    1     int num1[] = {1, 2, 3};
    2     int num2[] = {1, 3, 3};
    3     
    4     int result = memcmp(num1, num2, sizeof(num1));// 相等为0,不等为-1
    5     printf("result = %d
    ", result);
  • 相关阅读:
    卫星列表
    常见28个问题处理方法
    Dr.COM EPortal 认证
    Linux命令--chroot
    2020 最好的Linux网络监控工具
    auditctl(8)
    ElasticSearch 7.1.1 集群环境搭建
    ElasticSearch 常用 curl 命令
    利用Java的动态编译、动态加载结合EasyRules实现业务规则的动态性
    java根据数据库自动生成JavaBean或pojo
  • 原文地址:https://www.cnblogs.com/gfxxbk/p/5278752.html
Copyright © 2011-2022 走看看