8.结构体

 一.结构体的定义

1.结构体的定义

struct _Teacher
{
    char name[62];
    char c;
    int age;
}

typedef sturct _Teacher
{
    char name[62];
    char c;
    int age;
    
} Teacher;

2.定义结构体变量的三种方法

a.第一种

Teacher t1;
Teacher *p = (Teacher *)malloc(sizeof(Teacher));

b.第二种

struct _Teacher2
{
    char name[62];
    char c;
    int age;
} t2,t3;

c.第三种

struct 
{
    char name[62];
    char c;
    int age;
} t4;

二.结构体元素作为函数参数

实例:有如下结构体,分别在堆区和栈区实现结构体元素的赋值,排序和打印。

typedef struct _Teacher
{
    char name[62];
    char c;
    int age;
}Teacher;

在栈区实现结构体元素的赋值,排序和打印

/*打印年龄*/
void printfTeacherInfo(Teacher *tArray, int num)
{
    int i = 0;
    for (i = 0; i < num; i++)
    {
        printf("第%d个老师的年龄为%d\n", i + 1, tArray[i].age);
    }
}


void sortTeacherArray(Teacher *tArray, int num)
{
    int i = 0,j = 0;
    Teacher tmp;
    if (tArray != NULL)
    {
        for (i = 0; i < num; i++)
        {
            for (j = i+1; j < num; j++)
            {
                if (tArray[j].age > tArray[i].age)
                {
                    tmp = tArray[i];
                    tArray[i] = tArray[j];
                    tArray[j] = tmp;
                }
            }
        }
    }
}



// 在栈区实现结构体元素的赋值,排序,打印
int main()
{

    Teacher tArray[3];
    int origin_age = 30;

    int i = 0,j = 0;
    Teacher tmp;

    for (i = 0; i < 3; i++)
    {
        printf("请输入第%d个老师的年龄:",i+1);
        scanf("%d", &tArray[i].age);
    }

    printf("排序之前.............................................\n");
    printfTeacherInfo(tArray,3);

    // 排序
    sortTeacherArray(tArray, 3);

    printf("排序之后.............................................\n");
    printfTeacherInfo(tArray, 3);

    system("pause");
    return 0;

}

运行:

在堆区实现结构体元素的赋值,排序和打印

/*打印年龄*/
void printfTeacherInfo(Teacher *tArray, int num)
{
    int i = 0;
    for (i = 0; i < num; i++)
    {
        printf("第%d个老师的年龄为%d\n", i + 1, tArray[i].age);
    }
}


void sortTeacherArray(Teacher *tArray, int num)
{
    int i = 0,j = 0;
    Teacher tmp;
    if (tArray != NULL)
    {
        for (i = 0; i < num; i++)
        {
            for (j = i+1; j < num; j++)
            {
                if (tArray[j].age > tArray[i].age)
                {
                    tmp = tArray[i];
                    tArray[i] = tArray[j];
                    tArray[j] = tmp;
                }
            }
        }
    }
}


Teacher* createTarray(int num)
{
    Teacher *tArray = (Teacher *)malloc(num * sizeof(Teacher));
    return tArray;
}


// 在堆区实现结构体元素的赋值,排序和打印
int main()
{
    Teacher *tArray = createTarray(3);
    int i = 0, j = 0;
    Teacher tmp;

    if (tArray != NULL)
    {
        for (i = 0; i < 3; i++)
        {
            printf("请输入第%d个老师的年龄:",i+1);
            scanf("%d", &tArray[i].age);
        }
    }

    printf("排序之前.............................................\n");
    printfTeacherInfo(tArray, 3);
    
    // 排序
    sortTeacherArray(tArray,3);

    printf("排序之后.............................................\n");
    printfTeacherInfo(tArray, 3);

    free(tArray);

    system("pause");

    return 0;
}

运行:

【重点!!!-在堆区实现结构体元素的赋值,排序和打印(结构体作为函数参数)】

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma warning(disable:4996)

typedef struct _Teacher
{
    char *name;
}Teacher;

int createTeacherArray(Teacher **myTeacher)
{
    *myTeacher = malloc(3 * sizeof(Teacher));
    return 0;
}


int freeTeacherArray(Teacher **myTeacher)
{
    free(*myTeacher);
}

void main()
{
    Teacher *p2 = NULL;
    createTeacherArray(&p2);
    freeTeacherArray(&p2);
    system("pause");
}

三.结构体成员域中含有一级指针

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#pragma warning(disable:4996)


typedef struct _Teacher
{
    char name[62];
    char c;
    char *nickName;
    int age;
}Teacher;


/*打印年龄*/
void printfTeacherInfo(Teacher *tArray, int num)
{
    int i = 0;
    for (i = 0; i < num; i++)
    {
        printf("第%d个老师的年龄为%d\n", i + 1, tArray[i].age);
        printf("第%d个老师的昵称为%s\n", i + 1, tArray[i].nickName);
    }
}


void sortTeacherArray(Teacher *tArray, int num)
{
    int i = 0,j = 0;
    Teacher tmp;
    if (tArray != NULL)
    {
        for (i = 0; i < num; i++)
        {
            for (j = i+1; j < num; j++)
            {
                if (tArray[j].age > tArray[i].age)
                {
                    tmp = tArray[i];
                    tArray[i] = tArray[j];
                    tArray[j] = tmp;
                }
            }
        }
    }
}


Teacher* createTarray(int num)
{
    Teacher *tArray = (Teacher *)malloc(num * sizeof(Teacher));
    if (tArray != NULL)
    {
        for (int i = 0; i < num; i++)
        {
            tArray[i].nickName = (char *)malloc(100 * sizeof(char));
        }
    }
    return tArray;
}


// 在堆区实现结构体元素的赋值,排序和打印
int main()
{
    Teacher *tArray = createTarray(3);
    int i = 0, j = 0;
    Teacher tmp;

    if (tArray != NULL)
    {
        for (i = 0; i < 3; i++)
        {
            printf("请输入第%d个老师的年龄:",i+1);
            scanf("%d", &tArray[i].age);
            printf("请输入第%d个老师的昵称:",i+1);
            scanf("%s", tArray[i].nickName);
        }
    }

    printf("排序之前.............................................\n");
    printfTeacherInfo(tArray, 3);
    
    // 排序
    sortTeacherArray(tArray,3);

    printf("排序之后.............................................\n");
    printfTeacherInfo(tArray, 3);

    free(tArray);

    system("pause");

    return 0;
}

运行

注意:

1.只有分配内存块才可以使用指针!

2.buffer与指针的最大区别

 

typedef struct _Teacher
{
    char name[62];             //这里已经分配了62个字节的内存
    char c;
    char *nickName;            //这里只分配了4个字节的变量,还没有分配内存!
    int age;
}Teacher;

四.结构体成员域中含有二级指针

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#pragma warning(disable:4996)


typedef struct _Teacher
{
    char name[62];                           // <<< 老师名字
    char c;                                  // <<< 老师性别
    char *nickName;                          // <<< 老师真实姓名
    char **releStudent;                      // <<< 老师教的学生
    int age;                                 // <<< 老师年龄
}Teacher;



/*打印年龄*/
void printfTeacherInfo(Teacher *tArray, int num)
{
    int i = 0,j = 0;
    for (i = 0; i < num; i++)
    {
        printf("第%d个老师的年龄为%d\n", i + 1, tArray[i].age);
        printf("第%d个老师的昵称为%s\n", i + 1, tArray[i].nickName);
        
        for (j = 0; j < 3; j++)
        {
            printf("该老师所带的第%d个学生的名字为:%s\n",j+1,tArray[i].releStudent[j]);
        }

    }
}


void sortTeacherArray(Teacher *tArray, int num)
{
    int i = 0,j = 0;
    Teacher tmp;
    if (tArray != NULL)
    {
        for (i = 0; i < num; i++)
        {
            for (j = i+1; j < num; j++)
            {
                if (tArray[j].age > tArray[i].age)
                {
                    tmp = tArray[i];
                    tArray[i] = tArray[j];
                    tArray[j] = tmp;
                }
            }
        }
    }
}


// 在堆区创建老师数组
Teacher* createTarray(int num)
{
    Teacher *tArray = (Teacher *)malloc(num * sizeof(Teacher));
    int i = 0,j = 0;

    if (tArray != NULL)
    {
        for (i = 0; i < num; i++)
        {
            tArray[i].nickName = (char *)malloc(100 * sizeof(char));

            char **pReleStudent = (char **)malloc(3 * sizeof(char *));
            for (j = 0; j < num; j++)
            {
                pReleStudent[j] = (char *)malloc(50 * sizeof(char));
            }

            tArray[i].releStudent = pReleStudent;

        }
    }
    return tArray;
}


// 释放老师数组
void freeTarray(Teacher *tArray, int num)
{
    if (tArray != NULL)
    {
        int i = 0,j = 0;
        // free 真实姓名
        for (i = 0; i < num; i++)
        {
            char *pNickName = tArray[i].nickName;
            if (pNickName != NULL) free(pNickName);

            // free 老师教的学生&每个学生的名字
            char **pReleStudent = tArray[i].releStudent;
            if (pReleStudent != NULL)
            {
                for (j = 0; j < 3; j++)
                {
                    char *student = pReleStudent[j];
                    if (student != NULL) free(student);
                }
                free(pReleStudent);
            }

        }
        free(tArray);
    }

}




// 在堆区实现结构体元素的赋值,排序和打印
int main()
{
    Teacher *tArray = createTarray(3);
    int i = 0, j = 0;
    Teacher tmp;

    printf("*******************木叶师生关系*******************\n");
    printf("\n");
    if (tArray != NULL)
    {
        for (i = 0; i < 3; i++)
        {
            printf("请输入第%d个老师的昵称:", i + 1);
            scanf("%s", tArray[i].nickName);

            printf("请输入第%d个老师的年龄:",i+1);
            scanf("%d", &tArray[i].age);
            
            for (j = 0; j < 3; j++)
            {
                printf("请录入该老师所带的第%d个学生的姓名:",j+1);
                scanf("%s",tArray[i].releStudent[j]);
            }

        }
    }

    printf("排序之前.............................................\n");
    printfTeacherInfo(tArray, 3);
    
    // 排序
    sortTeacherArray(tArray,3);

    printf("排序之后.............................................\n");
    printfTeacherInfo(tArray, 3);

    // 释放内存
    freeTarray(tArray,3);

    system("pause");

    return 0;
}

运行:

五.结构体中的浅拷贝和深拷贝

先看下面的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma warning(disable:4996)


typedef struct _Teacher
{
    char *name;
    int age;
}Teacher;




void main()
{

    Teacher t1, t2;
    t1.name = (char *)malloc(100);
    t1.age = 10;

    t2 = t1;
    
    if (t1.name != NULL)
    {
        free(t1.name);
    }

    if (t2.name != NULL)
    {
        free(t2.name);
    }

    system("pause");
}

运行,发现程序crach掉了,crash的位置在free(t2.name)这里,crach的原因在t2=t1这一行,因为普通的C++编译器提供的拷贝行为,只是一个简单的复制(浅拷贝,指针变量的拷贝)。当结构体成员中含有buf的时候也是没有问题的,但是当结构体成员中含有指针的时候,C++编译器只会进行指针变量的拷贝,却不会拷贝指针变量所指向的内存空间,这就是编译器的浅拷贝行为。

在本例中,将t1的值拷贝给t2的话,只会将t1.name所保存的指针地址拷贝给t2.name,却不会再额外再开辟新的内存空间,因此当t1.name所指向的内存空间free掉了之后,t2.name再去free,程序就crash掉了。下面给出一种简单的深拷贝方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma warning(disable:4996)


typedef struct _Teacher
{
    char *name;
    int age;
}Teacher;



void copyT1T2(Teacher *from, Teacher *to)
{

    memcpy(to, from, sizeof(Teacher));
    to->name = (char *)malloc(100);
    strcpy(to->name, from->name);

}

void main()
{

    Teacher t1, t2;
    t1.name = (char *)malloc(100);
    t1.age = 10;

    copyT1T2(&t1, &t2);
    
    if (t1.name != NULL)
    {
        free(t1.name);
    }

    if (t2.name != NULL)
    {
        free(t2.name);
    }

    system("pause");
}

即自己编写拷贝行为,这样t1.name和t2.name都有独立的内存空间,再次运行,程序就不会再crach了。

 

posted @ 2017-05-15 21:12  夜行过客  阅读(266)  评论(0编辑  收藏  举报