结构体类型的声明
结构的基础知识
结构是一种复合数据类型,它允许将不同类型的数据组合在一起形成一个新的自定义类型。结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
数组:一组相同类型的元素集合
结构体:一组奴役的相同类型元素的集合
结构的声明
struct tag
{
member-list;//成员列表
}variable-list;//变量列表
//描述一个学生 - 声明一个结构体类型 struct Stu { //成员变量,是用来描述结构体对象的相关属性的 char name[20]; int age; char sex[3];//汉字占两个字节 };
结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其他结构体。
结构体初始化
结构体变量的定义和初始化
//描述一个学生 - 声明一个结构体类型 struct Stu { //成员变量,是用来描述结构体对象的相关属性的 char name[20]; int age; char sex[3];//汉字占两个字节 }p1;//全局变量 - 声明类型的同时定义变量p1 int main() { struct Stu p2;//局部变量 - //定义结构体变量p2 //初始化:定义变量的同时赋初值 struct Stu p3 = { "zhangsan",20,"男" }; }
这段代码定义了一个名为 `Stu` 的结构体类型,它有三个成员变量:`name`、`age` 和 `sex`,用于描述一个学生对象的相关属性。
接着,定义了一个全局变量 `p1`,它是 `Stu` 类型的变量,这里在声明结构体类型的同时定义了变量 `p1`。
`main` 函数中,定义了一个局部变量 `p2`,它也是 `Stu` 类型的变量。
在定义变量的同时,可以使用结构体初始化语法来为结构体的成员变量赋初值。例如,`p3` 变量的初始化语法为 `{ "zhangsan",20,"男" }`,它依次初始化了 `name`、`age` 和 `sex` 三个成员变量的初始值。
结构体的嵌套初始化
struct Point { int x; int y; }p1; //声明类型的同时定义变量p1 struct Point p2; //定义结构体变量p2 //初始化:定义变量的同时赋初值。 struct Point p3 = { 1,2 }; struct Stu //类型声明 { char name[15];//名字 int age; //年龄 }; struct Stu s = { "zhangsan", 20 };//初始化 struct Node { int data; struct Point p; struct Node* next; }n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化 struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化 //不按照顺序初始化 struct Node n3 = { .next = NULL,.data = 18,.p.x = 1,.p.y = 2 };
结构体成员访问
#include<stdio.h> struct Stu { char name[20]; int age; }; void print(struct Stu* ps) { //使用.操作符访问 printf("name = %s age = %d\n", (*ps).name, (*ps).age); //使用->操作符访问 //使用结构体指针访问指向对象的成员 printf("name = %s age = %d\n", ps->name, ps->age); } int main() { struct Stu s = { "zhangsan", 20 }; print(&s);//结构体地址传参 return 0; }
这段代码定义了一个结构体 `Stu`,包含了字符串类型的姓名和整型的年龄。接下来定义了一个名为 `print` 的函数,它的参数是一个指向结构体 `Stu` 的指针 `ps`。
在函数中,首先使用 `.` 操作符访问结构体指针 `ps` 指向的对象的成员变量 `name` 和 `age`,并使用 `printf` 函数输出这两个变量的值。其中要使用 `(*ps)` 操作符来访问指针所指向的结构体变量的成员。
接下来,使用 `->` 操作符访问结构体指针 `ps` 指向的对象的成员变量 `name` 和 `age`,并使用 `printf` 函数输出这两个变量的值。由于 `ps` 已经是一个指向结构体 `Stu` 的指针,因此可以直接使用 `ps->name` 和 `ps->age` 来访问结构体中的成员变量。
在 `main` 函数中,定义了一个结构体变量 `s`,并初始化了它的姓名和年龄。接着调用 `print` 函数,并将指向 `s` 的地址作为参数传递给它。最后返回 0。
结构体传参
struct S { int data[1000]; int num; }; struct S s = {{1,2,3,4}, 1000}; //结构体传参 void print1(struct S s) { printf("%d\n", s.num); } //结构体地址传参 void print2(struct S* ps) { printf("%d\n", ps->num); } int main() { print1(s); //传结构体 print2(&s); //传地址 return 0; }
这段代码定义了一个结构体 `S`,其中包含一个长度为1000的整型数组和一个表示数组元素个数的整型变量 `num`。接下来定义了两个函数 `print1` 和 `print2`,用于输出结构体变量 `s` 中的成员变量 `num`。
在 `main` 函数中,定义了结构体变量 `s`,并初始化了它的数据和元素个数。接着调用了 `print1` 函数和 `print2` 函数,分别传递了结构体变量 `s` 和它的地址 `&s` 作为参数。最后返回 0。
`print1` 函数使用了结构体传参的方式,将整个结构体变量 `s` 拷贝到函数的栈空间中。这种方式的好处是在函数执行时,对结构体的修改不会影响到原结构体变量的值,因此更加安全。但是缺点是在函数调用时需要进行结构体的拷贝,函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
`print2` 函数使用了结构体指针的方式,将结构体变量 `s` 的地址作为参数传递给了函数。这种方式的好处是在函数执行时,如果需要修改结构体的值,可以直接通过指针来访问结构体的成员变量,不需要进行结构体的拷贝操作,同时由于指针变量的空间大小是4/8个字节,对系统的开销较小。
结论: 结构体传参的时候,要传结构体的地址。