https://www.bilibili.com/video/BV1vb411m7JV 文章目录 第5天 合并排序两个数组 结构体变量定义 结构体变量初始化 typedef 改类型名 点运
https://www.bilibili.com/video/BV1vb411m7JV
文章目录
- 第5天
- 合并排序两个数组
- 结构体变量定义
- 结构体变量初始化
- typedef 改类型名
- 点运算符和指针法操作结构体
- 结构体内存四区
- 结构体变量的互相赋值
- 结构体静态数组
- 结构体动态数组
- 结构体嵌套一级指针二级指针
- 结构体深拷贝浅拷贝
- 浅拷贝
- 深拷贝
- 二者总结
- 结构体偏移量
- 结构体内存对齐
第5天
合并排序两个数组
// 将 p1 和 buf2 中的内容取出来,放到 p3,并排序返回
int sort(char **array1, int num1,
char (*array2)[30], int num2,
char ***myp3, int *num3)
{
if(array1 == NULL || array2 == NULL || myp3 == NULL || num3 == NULL)
{
return -1;
}
// 打造一个指针数组
char **tmp = (char**)malloc(sizeof(char*)*(num1 + num2));
if(tmp == NULL)
{
return -2;
}
// 给每个指针分配内存
int i, j;
for(i = 0; i < num1; i++)
{
tmp[i] = (char*)malloc(sizeof(char)*(strlen(array1[i]) + 1));
strcpy(tmp[i], array1[i]);
}
for(i = num1, j = 0; i < num1 + num2; i++, j++)
{
tmp[i] = (char*)malloc(sizeof(char)*(strlen(array2[j]) + 1));
strcpy(tmp[i], array2[j]);
}
// 间接赋值
*myp3 = tmp;
*num3 = num1 + num2;
// 排序
char *p = NULL;
for(i = 0; i < *num3 - 1; i++)
{
for(j = i + 1; j < *num3; j++)
{
if(strcmp(tmp[i], tmp[j]) > 0)
{
p = tmp[i];
tmp[i] = tmp[j];
tmp[j] = p;
}
}
}
return 0;
}
void free_buf(char ***p3, int n)
{
if (p3 == NULL)
{
return;
}
int i, j;
char **tmp = *p3;
for(i = 0; i < n; i++)
{
if(tmp[i] != NULL)
{
free(tmp[i]);
tmp[i] = NULL;
}
}
if(tmp != NULL)
{
free(tmp);
*p3 = NULL;
}
}
int main()
{
int ret = 0;
char *p1[] = {"aa", "ccccc", "bbbb"}; // 指针数组
char buf2[][30] = {"1111", "333333", "222222", "6666"}; // 二维数组
char **p3 = NULL;
int len1, len2, len3, i = 0;
len1 = sizeof(p1) / sizeof(char *);
len2 = sizeof(buf2) / sizeof(buf2[0]);
// printf("%d %d", len1, len2);
for(i = 0; i < len1; i++)
{
printf("%s ", p1[i]);
}
printf("\n");
for(i = 0; i < len2; i++)
{
printf("%s ", buf2[i]);
}
printf("\n");
ret = sort(p1, len1, buf2, len2, &p3, &len3);
if(ret != 0)
{
printf("ret: %d", ret);
return ret;
}
for(i = 0; i < len3; i++)
{
printf("%s ", p3[i]);
}
printf("\n");
free_buf(&p3, len3);
return 0;
}
结构体变量定义
// 定义类型的同时定义变量struct Teacher
{
char name[50];
int age;
}t1, t2;
// 先定义类型,再定义变量
struct Teacher t3;
// 不建议这么书写,容易与下方写法混淆
typedef struct Teacher
{
char name[50];
int age;
}T;
T t1;
结构体变量初始化
struct Teacher t4 = {"Tom", 24};printf("%s %d\n", t4.name, t4.age);
typedef 改类型名
typedef struct Teacher{
char name[50];
int age;
}Teacher;
struct Teacher t;
Teacher t;
点运算符和指针法操作结构体
struct Teacher t4;strcpy(t4.name, "Lily");
t4.age = 25;
printf("%s %d\n", t4.name, t4.age); // 非指针结构体对象,使用.访问结构体中内容
struct Teacher *t5 = NULL; // 结构体变量,没有指向空间,不能给其它成员赋值
t5 = &t4; // 为结构体指针赋予意义
strcpy(t5->name, "Lily Hee"); // 使用箭头方式访问结构体中内容,或者(*t5).name方式
t5->age = 37;
printf("%s %d\n", t5->name, t5->age);
结构体内存四区
结构体变量的互相赋值
typedef struct Teacher{
char name[50];
int age; // int age=15;err; 结构体只是一个类型,没有分配空间,只有根据其类型定义变量时,才分配空间,有空间后才能赋值
};
int main()
{
struct Teacher t1 = {"Tom", 12};
struct Teacher t2 = t1; // 相同类型的结构体可以互相赋值,把t1变量内存中的内容拷贝给t2内存中对应变量 深拷贝
}void copyTeacher(Teacher *to, Teacher *from)
{
*to = *from;
}
struct Teacher t3;
memset(&t3, 0, sizeof(t3));
copyTeacher(&t3, &t1);
结构体静态数组
typedef struct Teacher{
char name[50];
int age;
};
int main()
{
struct Teacher a[3] = {
{"abc", 10},
{"def", 11},
{"ghi", 12},
};
for(int i = 0; i < 3; i++)
{
printf("%s %d\n", a[i].name, a[i].age);
}
}
结构体动态数组
typedef struct Teacher{
char name[50];
int age;
}Teacher;
int main()
{
Teacher *p = (Teacher*) malloc(3*sizeof(Teacher));
if(p == NULL)
{
return -1;
}
char buf[50];
for(int i = 0; i < 3; i++)
{
sprintf(buf, "name%d%d%d", i, i, i);
strcpy(p[i].name, buf);
p[i].age = 20 + i;
}
for(int i = 0; i < 3; i++)
{
printf("%s %d\n", p[i].name, p[i].age);
}
if(p != NULL)
{
free(p);
p = NULL;
}
}
name000 20
name111 21
name222 22
结构体嵌套一级指针二级指针
typedef struct Teacher{
char* name;
int age;
}Teacher;
int main()
{
Teacher* p = (Teacher*)malloc(3 * sizeof(Teacher));
char buf[30];
for(int i = 0; i < 3; i++)
{
p[i].name = (char*)malloc(30);
sprintf(buf, "name%d%d%d", i, i, i);
strcpy(p[i].name, buf);
p[i].age = 20 + 2*i;
}
for(int i = 0; i < 3; i++)
{
printf("%s %d\n", p[i].name, p[i].age);
}
for(int i = 0; i < 3; i++)
{
if(p[i].name != NULL)
{
free(p[i].name);
p[i].name = NULL;
}
}
if(p != NULL)
{
free(p);
p = NULL;
}
}
typedef struct Teacher
{
char* name;
int age;
}Teacher;
int getMem(Teacher **tmp, int n)
{
if(tmp == NULL)
{
return -1;
}
Teacher *p = (Teacher*)malloc(sizeof(Teacher) * n);
char buf[30];
for(int i = 0; i < n; i++)
{
p[i].name = (char*)malloc(30);
sprintf(buf, "name%d%d%d", i, i, i);
strcpy(p[i].name, buf);
p[i].age = 20 + 2*i;
}
*tmp = p;
return 0;
}
void showTeacher(Teacher* p, int n)
{
for(int i = 0; i < 3; i++)
{
printf("%s %d\n", p[i].name, p[i].age);
}
}
void freeTeacher(Teacher* p, int n)
{
for(int i = 0; i < 3; i++)
{
if(p[i].name != NULL)
{
free(p[i].name);
p[i].name = NULL;
}
}
if(p != NULL)
{
free(p);
p = NULL;
}
}
int main()
{
Teacher* p = (Teacher*)malloc(3 * sizeof(Teacher));
getMem(&p, 3);
showTeacher(p, 3);
freeTeacher(p, 3);
p = NULL;
}p = (Teacher*)malloc(sizeof(Teacher)*3)
// p[i].name
// (p+i)->name
typedef struct Teacher
{
char** stu;
}Teacher;
int createTeacher(Teacher **tmp, int n)
{
if(tmp == NULL)
{
return -1;
}
Teacher *q = (Teacher*)malloc(sizeof(Teacher)*n);
for(int i = 0; i < n;i++)
{
q[i].stu = (char**)malloc(sizeof(char*) * n);
for(int j = 0; j < n;j++)
{
q[i].stu[j] = (char*)malloc(30);
char buf[30];
sprintf(buf, "name%d%d", i, j);
strcpy(q[i].stu[j], buf);
}
}
*tmp = q;
return 0;
}
void showTeacher(Teacher* p, int n)
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
printf("%s ", p[i].stu[j]);
}
printf("\n");
}
}
void freeTeacher(Teacher** tmp, int n)
{
Teacher* q = *tmp;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(q[i].stu[j] != NULL)
{
free(q[i].stu[j]);
q[i].stu[j] = NULL;
}
}
if(q[i].stu != NULL)
{
free(q[i].stu);
q[i].stu = NULL;
}
}
if (q != NULL)
{
free(q);
q = NULL;
*tmp = NULL;
}
}
int main()
{
Teacher* p;
createTeacher(&p, 3);
showTeacher(p, 3);
freeTeacher(&p, 3);
}
结构体深拷贝浅拷贝
浅拷贝
typedef struct Teacher{
char* name;
int age;
}Teacher;
int main()
{
Teacher t1;
t1.name = (char*)malloc(sizeof(30));
strcpy(t1.name, "Tom");
t1.age = 20;
Teacher t2;
t2 = t1;
printf("t1:%s %d\nt2:%s %d\n", t1.name, t1.age, t2.name, t2.age);
// t1:Tom 20
// t2:Tom 20
}
只能释放一次,指向同一块内存区域。
深拷贝
typedef struct Teacher{
char* name;
int age;
}Teacher;
int main()
{
Teacher t1;
t1.name = (char*)malloc(sizeof(30));
strcpy(t1.name, "Tom");
t1.age = 20;
Teacher t2;
t2 = t1;
t2.name = (char*)malloc(sizeof(30));
strcpy(t2.name, t1.name);
printf("t1:%s %d\nt2:%s %d\n", t1.name, t1.age, t2.name, t2.age);
// t1:Tom 20
// t2:Tom 20
}
对于 C 语言,申请一次内存,释放一次内存即可,深拷贝浅拷贝的区别对于C语言影响不大,下图深拷贝时需要释放两次空间。
二者总结
结构体中嵌套指针(意味着动态分配空间),同类型结构体变量赋值,不同结构体成员变量指向同一块内存。
结构体偏移量
// 偏移量,结构体类型内部变量的内存布局typedef struct Teacher
{
char name[64]; // 64
int age; // 4
int id;// 4
}Teacher;
int main()
{
Teacher t1;
Teacher *p = NULL;
p = &t1;
int n1 = (int)(&(p->age)) - (int)p; // name 空间,相对于结构体首地址
printf("n1=%d\n", n1); // 64
int n2 = (int)&(((Teacher*) 0)->age); // 绝对0地址的偏移量
printf("n2=%d", n2); // 64
}
结构体内存对齐
空间换时间,在结构体中规范每个变量的首地址。
默认以结构体中所占内存空间最大的数据类型为标准进行对齐。
在计算结构体的sizeof值时需要注意内存对齐问题,还有成员顺序问题。
int main(){
struct
{
int a; // 4
short b; // 2
}A;
printf("%d",sizeof(A)); // 8
}int main()
{
struct
{
double c;
int a;
short b;
}A;
printf("%d",sizeof(A)); // 16
}int main()
{
struct
{
int a;
double c;
short b;
}A;
printf("%d",sizeof(A)); // 24
}
嵌套结构体时,也看最长的成员是谁。
#pragma pack(8) // 指定对齐的字节数,如果超过结构体中最长的成员,仍以最长成员为准