鱼C论坛

 找回密码
 立即注册
查看: 2095|回复: 0

[学习笔记] 018-结构体再进阶及深浅拷贝

[复制链接]
发表于 2018-8-20 21:58:48 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1、结构体嵌套一级、二级指针
知识点:1.对于创建内存空间的指针,不能向他指向的内存空间写值。
             2.malloc申请的空间在结束时需要手工释放,malloc怎么申请的 就要怎么释放;即只能拿到malloc返回的地址才能去释放。
             3. malloc申请的内存空间只能够被释放一次,不允许多次释放
熟悉下面这个模型(内存的申请、建立和释放方法):
无标题.png

  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "string.h"

  4. // 结构体套一级、二级指针
  5. struct Teacher
  6. {
  7.         char name[64];
  8.         char *a_name;
  9.         int age;  
  10.         char **stuname;
  11. };

  12. //打印
  13. void printfArray(struct Teacher *pArray, int count)
  14. {
  15.         int i = 0, j = 0;
  16.         for (i = 0; i < count; i++)
  17.         {
  18.                 printf("\n%d  ", pArray[i].age);
  19.                 printf("%s  ", pArray[i].name);
  20.                 printf("%s  ", pArray[i].a_name);

  21.                 for (j = 0; j < 3; j++)
  22.                 {
  23.                         printf("%s  ", pArray[i].stuname[j]);
  24.                 }
  25.         }
  26. }

  27. //排序
  28. void sortArray(struct Teacher *pArray, int count)
  29. {
  30.         int i = 0, j = 0;
  31.         struct Teacher tmp;
  32.         for (i = 0; i < count; i++)
  33.         {
  34.                 for (j = i + 1; j < count; j++)
  35.                 {
  36.                         if (pArray[i].age < pArray[j].age)
  37.                         {
  38.                                 tmp = pArray[i];
  39.                                 pArray[i] = pArray[j];
  40.                                 pArray[j] = tmp;
  41.                         }
  42.                 }
  43.         }
  44. }

  45. // 手工创建结构体数组
  46. struct Teacher * createTArray1(int count)
  47. {
  48.         int i = 0, j = 0;
  49.         struct Teacher*p1 = (struct Teacher *)malloc(count * sizeof(struct Teacher));
  50.         if (p1 == NULL)
  51.         {
  52.                 return NULL;
  53.         }

  54.         for (i = 0; i < count; i++)
  55.         {
  56.                 memset(&p1[i], 0, sizeof(struct Teacher));  // 给申请的内存空间,每个字节赋0
  57.                 memset(p1+i, '0', sizeof(struct Teacher)); // 和上面等价
  58.                 p1[i].a_name = (char*)malloc(128 * sizeof(char));  // 开辟空间给a_name
  59.                 memset(p1[i].a_name, 0, 128 * sizeof(char));   //为自己开辟的空间赋初值
  60.                 //给stuname 手工打造一个二维内存空间
  61.                 {
  62.                         char **p2 = (char**)malloc(3 * sizeof(char*));
  63.                         for (j = 0; j < 3; j++)
  64.                         {
  65.                                 p2[j] = malloc(128 * sizeof(char));
  66.                                 memset(p2[j], 0, 128 * sizeof(char));
  67.                         }
  68.                         p1[i].stuname = p2;
  69.                 }

  70.         }
  71.         return p1;
  72. }

  73. // 释放创建的空间
  74. void freeTArray(struct Teacher * tArray, int num)
  75. {
  76.         int i = 0;
  77.         if (tArray == NULL)
  78.         {
  79.                 return;
  80.         }

  81.         // 释放 为*a_name申请的空间
  82.         for (i = 0; i < num; i++)
  83.         {
  84.                 if (tArray[i].a_name != NULL)   //为什么这里需要释放
  85.                 {
  86.                         free(tArray[i].a_name);
  87.                 }

  88.         // 释放 为**stuname申请 的手工二维空间
  89.                 if (tArray[i].stuname != NULL)
  90.                 {
  91.                         int i1 = 0, j1 = 0;
  92.                         for (i1 = 0; i1 < 3; i1++)
  93.                         {
  94.                                 if (tArray[i].stuname[i1] != NULL)
  95.                                 {
  96.                                         free(tArray[i].stuname[i1]);
  97.                                 }
  98.                         }
  99.                         free(tArray[i].stuname);
  100.                 }

  101. // malloc怎么申请的 就要怎么释放;只能拿到malloc返回的地址才能去释放啦

  102. /*                if (tArray[i].name != NULL)   //这个地方需要自己释放吗?(不需要,结构图是一块申请的,要一块释放)
  103.                 {
  104.                         free(tArray[i].name);
  105.                 }
  106. */               
  107.         }
  108.         if (tArray != NULL)
  109.         {
  110.                 free(tArray);
  111.                 tArray = NULL; //垃圾话语
  112.         }
  113. }

  114. void main()
  115. {
  116.         int i = 0, j = 0;
  117.         struct Teacher *pArray = createTArray1(3);
  118.         if (pArray == NULL)
  119.         {
  120.                 return;
  121.         }



  122.         //这里是结构体数组,tArray是首元素的地址,他的类型是首元素的类型,struct Teacher *;
  123.         //tArray[0]是第一个结构体的变量名
  124.         struct Teacher tArray[10];

  125.         for (i = 0; i < 3; i++)
  126.         {
  127.                 printf("\n请输入age:");
  128.                 scanf("%d", &pArray[i].age);
  129.                 printf("\n请输入name:");
  130.                 scanf("%s", pArray[i].name);
  131.                 printf("\n请输入a_name:");
  132.                 scanf("%s", pArray[i].a_name);

  133.                 char **p2 = pArray[i].stuname;
  134.                 for (j = 0; j < 3; j++)
  135.                 {                       
  136.                         printf("\n请输入学生的名字:");
  137.                         scanf("%s", p2[j]);
  138.                 }
  139.         }
  140.        
  141.         printf("排序之前:\n");
  142.         printfArray(pArray, 3);

  143.         sortArray(pArray, 3);

  144.         printf("\n排序之后:\n");
  145.         printfArray(pArray, 3);

  146.         freeTArray(pArray, 3);

  147.         system("pause");
  148. }
复制代码

2、深浅copy
        浅拷贝:指的是在进行结构体的拷贝时,由于结构体中有带内存块的指针变量,而拷贝时只是进行单纯的赋值操作,导致被复制的结构体所挂内存的丢失或没被创建。
        深拷贝:即在拷贝时避免的结构体内指针所挂内存块旳丢失或未创建。
浅拷贝容易造成内存的多次释放和内存的泄露。
代码示例:
  1. #include "stdio.h"
  2. #include "stdlib.h"
  3. #include "string.h"

  4. struct AdTeacher
  5. {
  6.         char name[64];
  7.         char *a_name;
  8.         int age;
  9. };

  10. // 手工创建结构体数组
  11. struct AdTeacher * createTArray2(int count)
  12. {
  13.         int i = 0, j = 0;
  14.         struct AdTeacher*p1 = (struct AdTeacher *)malloc(count * sizeof(struct AdTeacher));
  15.         if (p1 == NULL)
  16.         {
  17.                 return NULL;
  18.         }

  19.         for (i = 0; i < count; i++)
  20.         {
  21.                 memset(&p1[i], 0, sizeof(struct AdTeacher));
  22.                 memset(p1 + i, '0', sizeof(struct AdTeacher)); // 和上面等价
  23.                 p1[i].a_name = (char*)malloc(128 * sizeof(char));  // 开辟空间给a_name
  24.                 memset(p1[i].a_name, 0, 128 * sizeof(char));   //为自己开辟的空间赋初值
  25.         }
  26.         return p1;
  27. }

  28. // 释放创建的空间
  29. void freeTArray2(struct AdTeacher * tArray, int num)
  30. {
  31.         int i = 0;
  32.         if (tArray == NULL)
  33.         {
  34.                 return;
  35.         }

  36.         // 释放 为*a_name申请的空间
  37.         for (i = 0; i < num; i++)
  38.         {
  39.                 if (tArray[i].a_name != NULL)   //为什么这里需要释放
  40.                 {
  41.                         free(tArray[i].a_name);
  42.                 }
  43.         }

  44.         if (tArray != NULL)
  45.         {
  46.                 free(tArray);
  47.                 tArray = NULL; //垃圾话语
  48.         }
  49. }

  50. // 深拷贝
  51. void deepCopy(struct AdTeacher *from, struct AdTeacher *to)
  52. {
  53.         memcpy(to, from, sizeof(struct AdTeacher));
  54.         to->a_name = (char *)malloc(128);
  55.         strcpy(to->a_name, from->a_name);
  56. }

  57. void main()
  58. {
  59.         int i = 0;
  60.         //struct AdTeacher t1;
  61.         //struct AdTeacher t2;
  62.         struct AdTeacher* p1 = createTArray2(1);
  63.         struct AdTeacher* p2 = createTArray2(1);



  64.         printf("\n请输入age:");
  65.         scanf("%d", &(p1[0].age));

  66.         printf("\n请输入name:");
  67.         scanf("%s", p1->name);

  68.         printf("\n请输入a_name:");
  69.         scanf("%s", p1[0].a_name);

  70.         //浅拷贝
  71. //        (*p2) = (*p1);  
  72.         //编译器机械的=赋值,浅拷贝, 会导致p2和p1中的*a_name同时都指向p1中*a_name申请的内存空间
  73.         //导致p1中*a_name在释放时释放两次,而p2中*a_name没有被释放。

  74.         //自建函数来实现深拷贝
  75.         deepCopy(p1, p2);

  76.         freeTArray2(p1, 1);
  77.         freeTArray2(p2, 1);
  78.         system("pause");
  79. }
复制代码



本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-22 03:54

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表