moc 发表于 2018-8-20 21:58:48

018-结构体再进阶及深浅拷贝

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

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

// 结构体套一级、二级指针
struct Teacher
{
        char name;
        char *a_name;
        int age;
        char **stuname;
};

//打印
void printfArray(struct Teacher *pArray, int count)
{
        int i = 0, j = 0;
        for (i = 0; i < count; i++)
        {
                printf("\n%d", pArray.age);
                printf("%s", pArray.name);
                printf("%s", pArray.a_name);

                for (j = 0; j < 3; j++)
                {
                        printf("%s", pArray.stuname);
                }
        }
}

//排序
void sortArray(struct Teacher *pArray, int count)
{
        int i = 0, j = 0;
        struct Teacher tmp;
        for (i = 0; i < count; i++)
        {
                for (j = i + 1; j < count; j++)
                {
                        if (pArray.age < pArray.age)
                        {
                                tmp = pArray;
                                pArray = pArray;
                                pArray = tmp;
                        }
                }
        }
}

// 手工创建结构体数组
struct Teacher * createTArray1(int count)
{
        int i = 0, j = 0;
        struct Teacher*p1 = (struct Teacher *)malloc(count * sizeof(struct Teacher));
        if (p1 == NULL)
        {
                return NULL;
        }

        for (i = 0; i < count; i++)
        {
                memset(&p1, 0, sizeof(struct Teacher));// 给申请的内存空间,每个字节赋0
                memset(p1+i, '0', sizeof(struct Teacher)); // 和上面等价
                p1.a_name = (char*)malloc(128 * sizeof(char));// 开辟空间给a_name
                memset(p1.a_name, 0, 128 * sizeof(char));   //为自己开辟的空间赋初值
                //给stuname 手工打造一个二维内存空间
                {
                        char **p2 = (char**)malloc(3 * sizeof(char*));
                        for (j = 0; j < 3; j++)
                        {
                                p2 = malloc(128 * sizeof(char));
                                memset(p2, 0, 128 * sizeof(char));
                        }
                        p1.stuname = p2;
                }

        }
        return p1;
}

// 释放创建的空间
void freeTArray(struct Teacher * tArray, int num)
{
        int i = 0;
        if (tArray == NULL)
        {
                return;
        }

        // 释放 为*a_name申请的空间
        for (i = 0; i < num; i++)
        {
                if (tArray.a_name != NULL)   //为什么这里需要释放
                {
                        free(tArray.a_name);
                }

        // 释放 为**stuname申请 的手工二维空间
                if (tArray.stuname != NULL)
                {
                        int i1 = 0, j1 = 0;
                        for (i1 = 0; i1 < 3; i1++)
                        {
                                if (tArray.stuname != NULL)
                                {
                                        free(tArray.stuname);
                                }
                        }
                        free(tArray.stuname);
                }

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

/*                if (tArray.name != NULL)   //这个地方需要自己释放吗?(不需要,结构图是一块申请的,要一块释放)
                {
                        free(tArray.name);
                }
*/               
        }
        if (tArray != NULL)
        {
                free(tArray);
                tArray = NULL; //垃圾话语
        }
}

void main()
{
        int i = 0, j = 0;
        struct Teacher *pArray = createTArray1(3);
        if (pArray == NULL)
        {
                return;
        }



        //这里是结构体数组,tArray是首元素的地址,他的类型是首元素的类型,struct Teacher *;
        //tArray是第一个结构体的变量名
        struct Teacher tArray;

        for (i = 0; i < 3; i++)
        {
                printf("\n请输入age:");
                scanf("%d", &pArray.age);
                printf("\n请输入name:");
                scanf("%s", pArray.name);
                printf("\n请输入a_name:");
                scanf("%s", pArray.a_name);

                char **p2 = pArray.stuname;
                for (j = 0; j < 3; j++)
                {                       
                        printf("\n请输入学生的名字:");
                        scanf("%s", p2);
                }
        }
       
        printf("排序之前:\n");
        printfArray(pArray, 3);

        sortArray(pArray, 3);

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

        freeTArray(pArray, 3);

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

struct AdTeacher
{
        char name;
        char *a_name;
        int age;
};

// 手工创建结构体数组
struct AdTeacher * createTArray2(int count)
{
        int i = 0, j = 0;
        struct AdTeacher*p1 = (struct AdTeacher *)malloc(count * sizeof(struct AdTeacher));
        if (p1 == NULL)
        {
                return NULL;
        }

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

// 释放创建的空间
void freeTArray2(struct AdTeacher * tArray, int num)
{
        int i = 0;
        if (tArray == NULL)
        {
                return;
        }

        // 释放 为*a_name申请的空间
        for (i = 0; i < num; i++)
        {
                if (tArray.a_name != NULL)   //为什么这里需要释放
                {
                        free(tArray.a_name);
                }
        }

        if (tArray != NULL)
        {
                free(tArray);
                tArray = NULL; //垃圾话语
        }
}

// 深拷贝
void deepCopy(struct AdTeacher *from, struct AdTeacher *to)
{
        memcpy(to, from, sizeof(struct AdTeacher));
        to->a_name = (char *)malloc(128);
        strcpy(to->a_name, from->a_name);
}

void main()
{
        int i = 0;
        //struct AdTeacher t1;
        //struct AdTeacher t2;
        struct AdTeacher* p1 = createTArray2(1);
        struct AdTeacher* p2 = createTArray2(1);



        printf("\n请输入age:");
        scanf("%d", &(p1.age));

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

        printf("\n请输入a_name:");
        scanf("%s", p1.a_name);

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

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

        freeTArray2(p1, 1);
        freeTArray2(p2, 1);
        system("pause");
}


页: [1]
查看完整版本: 018-结构体再进阶及深浅拷贝