1.结构体
#include <stdio.h>
#include <string.h>
#pragma warning (disable:4996)//消除scanf警告
struct man
{
char name[100];
int age;
int sex;
};//一定要有分号
struct man m = { "tom", 12 };
struct man m = { "tom"};//默认是0
struct man m = { .name = "tom", .age = 12 };
struct man m = { .age = 12,.name = "tom" };//指定值之后可以乱放!
void print_man(struct man m){
printf("name = %s\n",m.name);
printf("age = %d\n",m.age);
}
int main(){
struct man m;//定义了一个结构体变量,名字是m,m在栈里面
strcpy(m.name,"王大毛");
m.age = 20;
struct man m2 = {"Tom"};//不写默认是0
print_man(m);
print_man(m2);
return 0;
}
2.结构体的内存对齐模式
编译器在编译一个结构的时候采用内存对齐模式,结构体总是以最大的成员最为对齐单位,所以结构体成员顺序合理很重要!
struct A{
int a1;
int a2;//结构体重所有的成员在内存中都是连续存放的
}
struct B{
int a1;
char a2;//结构体成员是要对齐的!所以是8,上下交换顺序,也还是8
};//见下图a-b
struct C{
char a1;
char a2;
int a3;
};//寄存器没那么傻,两个char放在同一行,实际大小就8!见下图c-d
struct D{
char a1;
int a2;
char a3;
};//寄存器真的变傻了,见下图c-d
struct F{
char a1;
short a2;
char a3;
int a4;
};//12字节,分析看下图F
int main(){
struct A a = {1,2};//定义同时初始化
printf("%u\n",sizeof(a));//输出8
int *p = (int*)&a;
//*p的值是什么?
printf("%d\n",*p);//输出1
printf("%d\n",p[1]);//输出2
printf("------------------------\n");
struct B b = {1,2};
printf("%u\n",sizeof(b));//输出8
return 0;
}
结构a-b说明.png
structc-d.png
structF.png
如果结构体所有的成员都是同一种类型,那么这个结构体在内存中和数组的存放方式是一样的
struct A
{
int a1;
int a2;
int a3;
};
struct A a;
&a和&a.a1的地址是一样的,结构体变量的地址就是首元素的地址
等同于 int [3]这种类型
3.指定结构体元素的位字段
定义一个结构体的时候可以指定具体元素的位长(bit)
struct test{
char a:2;//指定元素为2位长,不是2个字节长,本来8bit长,现在只用2bit
};
4.结构体数组
struct student{
char name[20];//结构体不会以成员数组作为对齐单位,而是认为他有20个char而已!!
int age;
int sex;
int class_id;
};
void print_st(struct student *st){//因为数组,所以是*
//打印..
}
void swap_int(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void swap_str(char *a,char *b){
char tmp[100] = {0};
strcpy(tmp,a);
strcpy(a,b);
strcpy(b,tmp);
}
void sort_student(struct student *a,int n){
int ,i,j;
for(i = 0;i < n;i++){
for(j = 1;j<n-1;j++){
if(a[j].age < a[j-1].age){
swap_int(&a[j].age,&a[j-1].age);
swap_int(&a[j].class_id,&a[j-1].class.id);
swap_int(&a[j].sex,&a[j-1].sex);
swap_str(&a[j].name,&a[j-1].name);
}
}
}
int main(){
struct student st[5] = {0};//定义了一个结构体变量数组,所有成员都为0
struct student st2[5] = {{"刘德华",30,0,1},{"陈冠希",35,0,2},{"张学友",20,1,3},{"饭岛爱",40,1,2},{"苍老师",30,1,2}};
for(int i = 0 ;i < 5;i++){
print_st(st2[i]);
}
}
5.嵌套结构
一个结构的成员还可以是另一个结构类型
struct A
{
int a1;
};
struct B
{
int a1;
struct A a2;
};
int main(){
struct B b;
b.a1 = 10;
b.a2.a1 = 0;//用点来寻址
printf("%lu\n",sizeof(b));//8字节
return 0;
}
6.结构体赋值和结构体指针
struct name a = b;
结构体变量之间的赋值就是简单的结构体变量之间的内存拷贝。
struct man{
char name[20];
int age;
};
int main(){
struct man m1 = {"买买提",20};
struct man m2;
//m2 = m1;//结构体变量的赋值
//等价于
// memcpy(&m2,&m1,sizeof(m1));
//也等价于
m2.age = m1.age;
strcpy(m2.name,m1.name);
printf("%s\n",m2.name);
printf("%d\n",m2.age);
//指向结构体的指针!!
struct man *p = &m1;
(*p).age = 100;
//p->age = 100;等价
strcpy((*p).name,"阿里巴巴");
// strcpy(p->name,"阿里巴巴");
//–>操作符
//(*p).a 等同于p->a
printf("%s\n",m1.name);
printf("%d\n",m1.age);
//指针访问
struct man m[10] = {0};
struct man *p = m;
p[0].age = 1;
strcpy(p[0].name,"张三");
p++;
p->age = 100;
strcpy(p->name,"李四");
//以此类推
return 0;
}
6.1 指向结构体数组的指针
Struct man m[10];
Struct man *p = m;
P就是指向了数组的首元素地址
7.结构中的数组成员和指针成员
一个结构中可以有数组成员,也可以有指针成员,如果是指针成员结构体成员在初始化和赋值的时候就需要提前为指针成员分配内存。
struct worker
{
char *name;
int age;
};
int main(){
struct worker w;
strcpy(w.name,"张三");//绝对错!!
struct worker w = {0};//这些结构体都是在栈中
w.name = calloc(100,sizeof(char));
strcpy(w.name,"张三");//这样才对
w.age = 20;
free(w.name);
return 0;
}
8.在堆中创建的结构体
如果结构体有指针类型成员,同时结构体在堆中创建,那么释放堆中的结构体之前需要提前释放结构体中的指针成员指向的内存。
struct man//结构体未创建不在内存中
{
char *name;
int age;
};
struct man *s = malloc(sizeof(struct man) * 2);
s[0].name = malloc(10 * sizeof(char));
s[1].name = malloc(10 * sizeof(char));
int main(){
struct man m;//name在栈里面,age在栈里面
struct man *p = malloc(sizeof(struct man));//name在堆里面,age也在堆里面
memset(p,0,sizeof(struct man));
/*分配内存,下面才正确!*/p->name = calloc(100,sizeof(char));
strcpy(p->name,"刘德华");//这里会报错,因为p指向了堆首地址,但是name并没有空间,详细看下图!
p->age = 20;
free(p->name);//顺序要正确!
free(p);
return 0;
}
堆结构体变量的指针成员.png
将结构体作为函数参数
将结构体变量作为函数参数
将结构体指针作为函数参数
void print_man(struct man m)//把结构体变量作为函数的参数
//在栈中会有类似这样的代码m=a;
{
printf("%s, %d\n",m.name,m.age);
}
void print_man_new(const struct man *m)
{//new的效率比上面的高很多,栈里面有形参m,m=&a;
printf("%s, %d\n",m->name,m->age);
}
在定义一个和结构有关的函数,到底是使用结构,还是结构的指针?
指针作为参数,只需要传递一个地址,所以代码效率高
int main(){
struct man a = {"哈哈",30};
print_man(a);
print_man_new(&a);
return 0;
}
网友评论