1、什么是结构体
结构体可以存放不同类型的变量或数组,类似于数据类型:可以将结构体看似于数据类型,调用结构体时需要定义一个变量,用来使用结构体内的变量。
struct 结构体名
{
数据类型 变量名1;
数据类型 变量名2;
数据类型 变量名3;
};
2、创建结构体及调用结构体方式
1.1.1 struct创建结构体+声明调用
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
}; //创建结构体
struct Books book[2]; //声明结构体
int main()
{
book[0].title ...... //调用结构体
}
先创建一个结构体,在外部或者main函数内声明结构体。
1.1.1struct创建结构体后声明变量
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
}book; //创建结构体后声明结构体
int main()
{
book.title ...... //调用结构体
}
3、调用结构体数据
两种方法,举例说明区别:
int compar_sno(const void *a,const void *b)
{
const struct student *p1 = a;
const struct student *p2 = b;
return p1->sno - p2->sno;
return (*p1).score - (*p2).score;
}
在上面代码中,两次return返回值等效:即p1->sno - p2->sno;
和(*p1).score - (*p2).score;
是一个意思
.
:结构体成员运算符
-
直接通过结构体变量访问成员
-
比如上面的
(*p1).score - (*p2).score;
,因为形参中a,b表示的是指向常量数据的指针,如果没有*,则表示p1等于a 的地址,有*后,(*p1)现在是对指针p1
进行解引用,得到指针所指向的结构体对象。所以(*p1)相当于变量,可以使用.
直接访问对象
->
:用指向结构体成员运算符
-
用于通过指向结构体的指针访问成员。
-
比如上面的
p1->sno - p2->sno;
,在上面解释中,p1表示指针访问地址,因此可以使用->
来实现通过指针访问结构体的成员。
4、作为参数传递函数
4.1 函数形参使用结构体(声明变量)传参
在编写函数时想要调用结构体变量作为形参,有两种写法,但都是等价的,都可以实现目标
-
使用指针调用:要求将变量的地址填入进去,因此在下面调用函数时需要使用地址符&
-
使用变量调用:直接将变量填入进去。
void scanf_stu(struct student *stu,int len) //第一种:使用指针调用形参结构体
{
puts("-------------------------------");
}
void printf_stu(struct student stu,int len) //第二种:直接将变量进行传参
{
puts("-------------------------------");
}
int main()
{
struct student stu;//定义变量
scanf_stu(&stu,3); //因为stu是个变量,根据所写的函数使用指针,所以传地
//址 & 进去
printf_stu(stu,3);
}
4.2 函数形参使用结构体(声明数组)传参
在编写函数时想要调用结构体数组作为形参,有两种写法,但以下两种方式是等价的:
- 使用指针传递结构体数组:要求将数组的首地址填入进去
void printArray(int *arr, int size);
-
直接传递结构体数组:直接将数组名填入进去。
void printArray(int arr[], int size);
解释一下为什么是 arr[] :
数组名本身就是数组的地址,即数组首元素的地址。将数组传递给函数时,实际上传递的是数组的地址(首元素的地址),即使在函数声明中没有显式使用地址符(&)。
这是因为数组名在大多数情况下会隐式转换为指向数组首元素的指针。
在函数声明中,
int arr[]
实际上等同于int *arr
,因为数组名被隐式转换为指向数组首元素的指针。因此,
arr
在函数内部被当作指针来使用,指向传递给函数的数组的首元素。
下面举一个例子可以直观看到:
void scanf_stu(struct student *stu,int len)// 数组指针形参
{
for(int i =0;i<3;++i)
{
printf("input a name:");
scanf("%s",stu[i].name);
printf("input a sno:");
scanf("%d",&stu[i].sno);
printf("input a score:");
scanf("%f",&stu[i].score);
puts("-------------------------------");
}
}
void printf_stu(struct student stu[],int len) //数组名形参
{
printf("--sno--|-name--|--score-\n");
for(int i =0;i<len;++i)
{
printf("%s\t%d\t%.2f\n",stu[i].name,stu[i].sno,stu[i].score);
puts("-------------------------------");
}
}
int main()
{
struct student stu[3];
scanf_stu(stu,3); //在填参数时,因为数组名本身就是数组首元素的地址,所以填数组本身,没有&
printf_stu(stu,3);
}