c语言中结构体的声明与使用
一.结构体的声明
1.创建一个结构体
struct Student {
char * name;
int age;
};
2.匿名结构体
顾名思义,就是没有名字的结构体,一般用于固定的结构体的变量,因为没有名字的原因,所有不能创建新的结构体变量,当然,使用typedef
就另当别说了。
struct {
char *name;
int age;
}stu1,stu2;
// 这样我们就通过匿名结构体在程序运行时就只会创建stu1和stu2。
3.嵌套结构体
当我们需要表示比较复杂的数据结构的时候,这个时候我们就可以尝试使用嵌套结构体。
struct Birthday{
int year;
int month;
int day;
};
struct Student{
char *name;
int age;
struct Birthday birthday;
};
这样我们就可以避免让过多的成员变量在同一个结构体里,不仅利于代码的阅读,程序的复用率也大大提高了。
二.成员变量赋值
下面我们来看一下结构体怎么赋值。
1.在结构体变量被声明的时候赋值(整体赋值)
struct Student {
char *name;
int age;
}stu={"asdas",12};
struct Student {
char name[100];
int age;
}stu={"q2",123};
// ??? 为什么再次对stu = {"123",123} 会报错。
从上面的代码,我们需要注意两个问题:
1.整体赋值必须保证赋值的顺序必须与你声明的结构体一一对应,除非你使用指定成员变量的方式进行赋值,否则必须保证一一对应。
2.第二个就是关于上面代码中的
char *name
和char name[100]
,他们的作用都是储存一个字符串,我们来说一下他们之间的区别,char *name
,这是一个字符指针,存放的是一个地址。char name[100]
,这声明了一个字符数组,所能储存的字符长度已经固定了,不够灵活。
特别注意在对结构体变量进行初始化的时候,只有在初始化的时候可以使用{}
进行整体的初始化,也就是说。
typedef struct Student {
char *name;
int age;
}student;
// 第一种方式
student stu = {"aglorice",12}; // 正确
// 第二种方式
student stu;
stu = {"rose",123}; // 错误
通过这个例子我们需要知道在结构体中使用{}
这种方式进行赋值只能在结构体变量初始化的时候,如果需要修改结构体变量中的值,可以一个一个的对结构体变量中的成员赋值。
stu.name = "tom";
stu.age = 19;
指定成员变量赋值
Student stu = {.name = "123",.age= 123};
三.结构体指针
当我们想要对在函数内部使用结构体变量,我们当然可以直接传参,像这样。
struct Student {
char *name;
int age;
};
void print(struct Student stu){
printf("%s,%d",stu.name,stu.age);
}
int main(){
struct Student stu = {"aglorice",12};
print(stu);
return 0
}
通过这种方式,我们当然能完成结构体变量的传参操作,但是它实际上的操作其实是对结构体变量stu
拷贝了一份,这样无疑增加了程序对内存的开销,这个时候就可以用指针来完成这个操作,与其把数据给函数,不如告诉它的位置在哪里。
struct Student {
char *name;
int age;
};
void print(struct Student *stu){
printf("%s,%d",stu->name,stu->age);
// 等价于
printf("%s,%d",(*stu).name,(*name).age);
}
int main(){
struct Student stu = {"aglorice",12};
print(&stu);
return 0
}
四.typedef的使用
通过上面我们发现每次在声明或者函数形参都需要使用struct Student xxx
,这显然不够优雅。
tpyedef struct Studet{
char *name;
int age;
}student;
// 等价于
struct Student {
char *name;
int age;
};
typedef struct Student student;
// 如果我们再声明一个结构体变量,就可以直接使用`student stu;`
五.结构体数组
当我们需要创建和操作多个相同类型的结构体变量时,这个时候我很容易想到数组,在结构体中,当然也可以使用数组。
tpyedef struct Studet{
char *name;
int age;
}student;
// 创建一个结构体数组
student stu[100];
剩下的操作和数组都是基本一致的。
六.内存对齐
tpyedef struct Studet{
char *name;
int age;
}student;
studetn stu = {"123",123};
printf("%d",sizeof(stu)); // 16
我们使用sizeof
运算符输出结构体变量stu
的内存大小,按照我们自然的理解char *
一个指针变量,我这里是64位系统,所以一个指针的大小是8个字节,int类型是4个字节,一共有12个字节,可是输出的却是16个字节,这就是因为内存对齐造成的。
同样,我们可以看看如下的代码占用多少字节。
tpyedef struct Studet{
char *name;
int age;
char sex;
}student;
studetn stu = {"123",123,'M'};
printf("%d",sizeof(stu)); // 16
七.文件读写-结构体数据
如果我们实现一个比如一个学生管理系统,我们需要对所有的学生数据进行持久化,这里我们就可以使用fwrite()
和fread()
.
注意 : 我们这里应该使用二进制的读写方式,当然你使用正常的方式也可以,但是为了避免出现意想不到的情况,还是建议使用二进制的方式进行读写。