- 结构体
今天呢,就来到了我们初入C语言板块的最后一篇知识类博客,我们来讲结构体,这个东西在C语言里也是很常用的东西,尤其到后面如果我有幸和各位一样学的都是C/C++方向,学到数据结构的时候结构体就会经常和我们见面了,那首先还是那些三板斧,也是我们研究问题会跳出来的常见问题,什么是,怎么用,有什么用,注意事项。
1.结构的基础知识:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
比如,现在有一个学生,他只是一个学生我要把他存入某些数据库系统里,那么学生这个东西都需要什么来定义呢?学号,char,姓名,char,性别,char,年龄,int,体重,double,大致就这些了,我们会定义变量,也会定义不同类型的变量,但是如果这些不同类型的变量现在要合成一个整体的话该如何定义呢?C语言规定我上面讲的这些就可以理解为是一个结构体,因为有不同类型的变量,在定义时只需要定义好这些类型的变量然后用一个结构体将它们结合成一个新的结构体变量,需要其中的哪些变量直接取出使用即可,明白了吗?
typedef struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
double weight//体重
}Stu;//分号不能丢
这样一个简单的学生结构体就定义好了,最下面的Stu是可以不写的,如果不写的话初始就是struct + 名字{};但是大家可以发现我加上了typedef,这叫类型重定义,意思就是我要对我定义的结构体类型重新定义,本来如果我要用原始的结构体定义一个学生变量时要这样:struct Stu s,s就是学生变量,你现在可以为它初始化,但是当我进行类型重定义时,现在的学生类型就变成了Stu,当定义学生变量时只需要写Stu s,是不是比起前者更加简易了呢?但是有一点要注意,结构体下面的分号是不可以丢掉的,当然这个问题其实不需要我们多操心,现在的编译器在我们定义完成一个结构体的时候应该都会帮我们加上。
2.结构成员的类型:结构的成员可以是标量、数组、指针,甚至是其他结构体。
那么,结构体里只能存入基本数据类型吗?如果我现在需要许多数字和一个字符该怎么办呢?可以用结构体存吗?如果我需要一个指针变量呢?如果我这个结构体内嵌在另一个结构体内可以吗?当然可以,C语言规定:见标题。
3.结构体变量的定义和初始化
说了半天不如写点代码,那么结构体就是这样定义和初始化的:
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
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};//结构体嵌套初始化
结构体在初始化时和基本类型定义的变量初始化方式其实是一样的对吧,一般我们还是为其初始化为0,当然你也可以不选择为其初始化,那么它的值还是随机值。还有如何定义一个结构体变量,直接拿你冲定义好的类型或者直接拿原始的结构体类型定义,定义好的变量它一定是含有你结构体内的那些类型。
4.结构体成员的访问:(.)(->)
当我定义好一个结构体的时候,如何访问到我想要访问的变量呢?C语言提供了两个操作符,我们前面讲操作符的时候一定讲过了,大家肯定也有印象,就是我们标题的那两个,当定义完结构体我们只需要用定义好的结构体名称来访问变量进行初始化和更改变量的值。
struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员
s.age = 20;//使用.访问age成员
第一个(.)是在结构体创建了一个普通变量时用的访问操作符,如果你用结构体创建了一个指针变量,就需要用到第二个操作符(->),代表指向结构体的某个元素。
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;
}
关于结构体的定义和初始化就讲完了,但是学了这么长时间的C语言,我们在学习一项新知识时总该考虑的那么几个问题,如何定义,如何初始化,如何书写,如何传参,如何使用,嗯我们接下来就来讲讲结构体是如何传参的。
5.结构体传参
直接通过代码来看:
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;
}
(注意我定义的结构体是在main函数外定义的,可不能定义到main函数里面,这样它就变成了一个局部变量,别的地方就不可以再使用)print1和print2就涉及到了结构体具体传参时的用法,可以直接传值也可以传址,如果传值就是实参的一个临时拷贝,如果传地址就可以通过指针里的地址改变实参里具体的值,是不是和基本类型定义的变量传参一样呢。
但是print1和print2也有优劣,print2明显要比print1更好,因为函数传参的时候,参数是需要压栈的。 如果传递一个结构体对象的时候,结构体过大,参数压栈 的的系统开销比较大,所以会导致性能的下降。
结论: 结构体传参的时候,要传结构体的地址。
好了,结构体在后面的使用会更更加详细的介绍和实战,所以今天的内容不算很多,大家就当放假了,下次再见。