今天我们来讲讲C语言基础的最后一个知识点了 —— 结构体。不知道大家对前面的C语言基础的知识点掌握的怎么样了呢?下面我们就开始讲解结构体的相关知识点吧!
什么是结构体呢?或者说结构体有什么作用呢?对于复杂对象来说,其不能通过内置类型来直接描述和表示,这时就有结构体来描述复杂类型。例如:如果我们想要描述学生的相关信息,包括学生的 名字 + 年龄 + 性别 + 学号 这几项信息,这时似乎通过我们之前所了解的变量、数组等类型并不能同时存储这些信息,那这时候采用结构体就能存储这些信息了。
1. 结构体类型的声明
在学习结构体的声明前,我们先来了解下面这几个词个概念:
1. 结构:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
2. 数组:一组相同类型元素的集合。
3. 结构体:一组不一定相同类型元素的集合。
正因为结构体可以存储不同类型的元素,所以当我们想要存储复杂对象信息的时候,首先想到的便是结构体。那结构体该怎么声明呢?
结构体的声明:
struct tag
{
member-list;
}variable-list;
其中,member-list 表示成员列表,可以是1个或多个;variable-list 表示结构体变量列表,也可以是1个或多个。
温馨提示:在结构体变量列表后的分号可不能丢了!!
当然,我们也可以用 typedef关键字 对结构体进行重命名,声明如下:
typedef struct tag
{
member-list;
}tag1,tag2;
其中,tag1,tag2 是 struct tag 的别名,可以是1个或多个。
学会了结构体的声明后,那么上述所谈到的学生信息就可以这样定义:
struct Stu
{
char name[20]; // 名字
int age; // 年龄
char sex[5]; // 性别
char id[15]; // 学号
};
而结构成员的类型可以是:变量、数组、指针、甚至是其他结构体。
2. 结构体初始化
对于结构体的初始化,我们结合 代码 进行讲解。
#include<stdio.h>
struct stu
{
char name[20];
int age;
char sex[10];
}s2,s3,s4;
typedef struct stu1
{
char name[20];
int age;
char sex[10]; // 男,女,保密
}stu1;
int main()
{
struct stu s1 = { "zhangsan",18,"male" };
stu1 s2 = { .age = 19, .name = "lisi", .sex = "female" };
return 0;
}
在上述代码中,我们采用两种方式定义了学生信息的结构体;其中stu1 是 struct stu1 的别名。这里先提醒大家:在C语言中,如果没有对结构体类型进行重命名(即没有使用 typedef 关键字),在初始化结构体时,struct关键字不能省略。(即如果没有重命名,则应该写 struct stu1 s2 而不是 stu1 s2)。
在对结构体成员变量进行初始化时,同样有两种方法初始化:(分别如 s1 和 s2)。
1. 如果我们想正常对结构体成员进行初始化,在初始化时要按照结构体中 成员的顺序在 {} 中依次对这些成员进行初始化,这样编译器在编译运行时才能对结构体成员的初始化一一对应。反之,如果不按顺序进行初始化,编译器则会报警告,如下图:
对于结构体变量s3,由于 未按顺序进行初始化,则编译器发出警告!
2. 那如果就是不想按顺序来对结构体成员进行初始化呢?当然可以不按顺序,此时初始化就如s2一样,通过 .结构体成员 的形式对想先初始化的成员进行初始化。
3. 结构体成员访问
对结构体成员进行初始化之后,那我们又该如何对这些成员进行访问呢?即 我们如何访问 s 中的成员?对于结构体来说,其也是有结构体变量和指针的,因此有以下2种方法:
1. 结构体变量访问成员:结构变量的成员是通过点操作符(.)访问的。点操作符接收两个操作数。(即 结构体变量.成员)
2. 结构体指针访问成员:结构指针的成员是通过操作符(->)访问的。操作符接收两个操作数。(即 结构体指针->成员)
代码如下:
#include<stdio.h>
struct stu
{
char name[20];
int age;
char sex[10];
};
int main()
{
//局部变量
struct stu s1 = { "zhangsan",18,"male" };
struct stu* ps = &s1; // 结构体指针
printf("%s %d %s\n", s1.name, s1.age, s1.sex);
printf("%s %d %s\n", ps->name, ps->age, ps->sex);
return 0;
}
4. 结构体传参
我们先来看看 代码:
#include<stdio.h>
struct S
{
int data[10];
int num;
};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
struct S s = { {1,2,3,4,5,6}, 99 };
print1(s); // 传结构体
print2(&s); //传地址
return 0;
}
在这段代码中,我们设置了两个输出函数 print1 和 print2;并通过不同的方式将 结构体变量s 传参给函数,代码都能正常运行并输出正确答案。
那么各位老铁们觉得上面的 print1 和 print2 函数哪一个好些呢?答案是:优先选择print2函数。
这是因为 在之前函数部分我们说过 形参是实参的一份临时拷贝,当我们传递一个结构体对象给函数的时候,形参就会在内存中开辟一份和结构体内存一样大的空间。这时如果传递的结构体过大,那么形参开辟的临时空间也会很大,这样就会导致系统开销比较大,从而使得程序性能的下降。
而如果我们传递的是结构体的地址时,这时形参就是一个指针,而指针要么 4字节大小,要么 8字节大小,并不会给操作系统的内存带来很大的压力,从而使得程序的性能较好!
至此,我们C语言基础的全部知识就讲解完啦!老铁们有没有对C语言更加感兴趣呢?这里提前剧透一下,小编后面会给大家讲讲C语言进阶的相关知识了,后续的内容也需要更强的理解能力呀!大家敬请期待一下吧!!