一.结构体的定义
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 ", 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("排序之前............................................. "); printfTeacherInfo(tArray,3); // 排序 sortTeacherArray(tArray, 3); printf("排序之后............................................. "); 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 ", 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("排序之前............................................. "); printfTeacherInfo(tArray, 3); // 排序 sortTeacherArray(tArray,3); printf("排序之后............................................. "); 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 ", i + 1, tArray[i].age); printf("第%d个老师的昵称为%s ", 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("排序之前............................................. "); printfTeacherInfo(tArray, 3); // 排序 sortTeacherArray(tArray,3); printf("排序之后............................................. "); 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 ", i + 1, tArray[i].age); printf("第%d个老师的昵称为%s ", i + 1, tArray[i].nickName); for (j = 0; j < 3; j++) { printf("该老师所带的第%d个学生的名字为:%s ",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("*******************木叶师生关系******************* "); printf(" "); 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("排序之前............................................. "); printfTeacherInfo(tArray, 3); // 排序 sortTeacherArray(tArray,3); printf("排序之后............................................. "); 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了。