结构体
- 前言
- 一、结构体声明
- 1. 结构的声明
- 2. 结构成员类型
- 3. 结构体变量的定义和初始化
- 3.1 第一种方式
- 3.2 第二种方式
- 3.3 利用 typedef 简化结构体类型的名字
- 3.4 结构体嵌套
- 二、 结构体的访问
- 三、 结构体传参
前言
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
C语言所给的类型(字符类型、整型类型、浮点型类型)并不能表述生活中的所有类型,当我们想要描述一个复杂事物时,这个复杂的事物可能不只有一个变量并且变量的类型也可能是不同的。
那我们如何来表达这个复杂事物呢?
这就需要我们自己给这个事物定义一个类型 —— 自定义类型(结构体)
自己定义类型(结构体) —— 就是把复杂事物数字化 —— 比如书是具体的事物 —— 我们可以利用书的几个基本属性(比如:书名、作者、价格、书号)来表示书的这一具体的事物。
下面从结构体声明、结构体访问、结构体传参三个方面讲解结构体
一、结构体声明
1. 结构的声明
struct tag(结构体名字)
{
member-list(结构体成员);
}variable-list(结构体变量);
例如描述一本书:
struct Book //Book为结构体名称; struct Book为结构体类型
{
char name[20]; //中间为结构体的成员
char auther[20];
float price;
char id[20];
}b1; //b1为结构体变量
2. 结构成员类型
结构的成员可以是标量(整型、浮点型)、数组、指针,甚至是其他结构体。
3. 结构体变量的定义和初始化
3.1 第一种方式
这种方式是 —— 直接在结构体后面定义结构体变量和初始化
#include<stdio.h>
struct Book
{
char name[20];
char auther[20];
float price;
char id[20];
}b1 = { "cyuyan", "zhangsan", 40.0f, "1001010011" }; //结构体变量的定义和初始化
//b1为结构体变量
//b1为全局变量
int main()
{
; //这里面可以使用b1(结构体变量)
return 0;
}
3.2 第二种方式
这种方式是 —— 使用时再定义结构体变量和初始化
#include<stdio.h>
struct Book //结构体变量的声明
{
char name[20];
char auther[20];
float price;
char id[20];
};
int main()
{
struct Book b1 = { "cyuyan", "zhangsan", 40.0f, "1001010011" }; //结构体变量的定义和初始化
struct Book b2 = { "shujujiegou", "lisi", 50.0f, "1110001101" };
//struct Book —— 为结构体类型
//b1,b2 —— 为结构体变量
//b1,b2 —— 为局部变量
return 0;
}
我们一般使用的都是第二种方式 —— 结构体变量的定义和初始化。
因为:
第二种方式是:在使用的时候创建变量和初始化 —— 避免了创建变量但是不使用的情况
第二种方式是创建的变量是局部的,第一种方式创建的变量是全局的 —— 我们在创建变量的时候尽量做到不使用变量的时候把变量销毁。
3.3 利用 typedef 简化结构体类型的名字
#include<stdio.h>
typedef struct Book //利用 typedef 关键字把类型(struct book)重新定义一个名字(Book)
//Book和这个 struct book 拥有相同的功能
{
char name[20];
char auther[20];
float price;
char id[20];
}Book;
int main()
{
Book b1 = { "cyuyan", "zhangsan", 40.0f, "1001010011" }; //初始化
struct Book b2 = { "shujujiegou", "lisi", 50.0f, "1110001101" };
return 0;
}
typedef 关键字不仅仅只能改变结构体的名字,也可以改变其他任意类型的变量
3.4 结构体嵌套
#include<stdio.h>
struct Book //结构体描述书的基本性质
{
char name[20];
char auther[20];
float price;
char id[20];
};
struct Point //表示坐标点
{
int x;
int y;
struct Book; //结构体中嵌套一个结构体
};
int main()
{
struct Point p1 = { 10, 20, { "cyuyan", "zhangsan", 40.0f, "1001010011"} }; //结构体嵌套的初始化
return 0;
}
二、 结构体的访问
上面我们讲了怎么创建和初始化结构体,那么结构体创建过后要怎样访问其中的成员呢?
下面就解释结构体要怎样访问。
结构体变量访问成员
结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。
结构体指针访问指向变量的成员
结构体指针是通过点操作符(->)访问的。点操作符接受两个操作数。
举例:
#include<stdio.h>
struct Book
{
char name[20];
char auther[30];
float price;
char id[20];
};
struct Point
{
int x;
int y;
struct Book b1; //结构体中嵌套一个结构体
};
int main()
{
//结构体变量访问成员 —— 利用(.)操作符
struct Point p1 = { 10, 20, {"cyuyan", "lisi", 40.0f, "1110001011"} };
printf("%d %d %s %s %f %s\n", p1.x, p1.y, p1.b1.name, p1.b1.auther, p1.b1.price, p1.b1.id);
//结构体指针访问指向变量的成员 —— 利用(->)操作符
struct Point* pp1 = &p1;
printf("%d %d %s %s %f %s\n", (*pp1).x, (*pp1).y, (*pp1).b1.name, (*pp1).b1.auther, (*pp1).b1.price, (*pp1).b1.id);
printf("%d %d %s %s %f %s\n", pp1->x, pp1->y, pp1->b1.name, pp1->b1.auther, pp1->b1.price, pp1->b1.id );
return 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;
}
上面的 print1 (传值调用) 和 print2 (传址调用)函数哪个好些?
答案是:首选 print2 (传址调用)函数。
原因:
函数传参的时候,参数是需要压栈的。
(传值调用)如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
(传址调用)如果传递一个地址,地址的大小是固定的(4/8 字节)。
结论:
结构体传参的时候,要传结构体的地址。