目录
结构体
1.结构体概述
如果我们现在想要将多种不同的数据类型混合存放到一个变量里面去。根据以前的知识,我们会想到运用数组来存多个数据,但此时是不能使用数组,因为数组是同一种数据类型变量的多个集合。
所以,我们希望能有一种变量,可以集合多种不同的数据类型。
C语言系统则提供了一种功能,可以自定义数据的类型,指定这种数据类型的变量由哪些小变量合成。这种功能,便叫做结构体。
2.结构体声明
2.1.结构体语法格式
(注意:最后的大括号之后一定要加上分号!!!)
struct 结构体名称
{
结构体成员1;
结构体成员2;
结构体成员3;
...
};
如上,我们使用的结构体仅仅是创建了1个新的类型而已,并没有声明变量。
结构体的作用是在指定新的数据类型是由一些小变量组合而成的。
例:
现在,我们以结构体的形式采集一本书的信息
struct Book
{
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
};
此时我们的结构体并未在内存中分配存储空间,直到我们去定义结构体类型变量。
2.2.定义结构体类型变量
声明结构体类型的变量———语法格式:
struct 新类型名称 变量名;
定义结构体的常规方式;
#include <stdio.h>
struct Book
{
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
};
int main(void)
{
struct Book book;
return 0;
}
另外还可以在声明结构体的时候就进行定义:
#include <stdio.h>
struct Book
{
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
}book;
int main(void)
{
return 0;
}
此时的book属于群聚变量,所有的函数都可以对它进行访问。(作用域不同,后文会提及)
2.3.点号运算符
要访问结构体成员,我们需要引入一个新的运算符—点号(.)运算符。比如book.title就是引用book结
构体的title成员,它是一个字符数组;而book. price则是引用book结构体的price成员,它是一个浮点型
的变量。
例:
#include <stdio.h>
struct Book
{
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
}book;
int main(void)
{
return 0;
}
int main(void)
{
printf("请输入书名:");
scanf( "%s", book.title) ;
printf("请输入作者:");
scanf("%s", book.author);
printf("请输入售价:");
scanf( "%f",&book. price);
printf("请输入出版日期: ");
scanf( "%d", &book.date) ;
printf("请输入出版社:");
scanf ( "%s", book. publisher) ;
printf( " \n====数据录入完毕====")
printf("书名:%s \n", book.title) ;
printf("作者: %s \n", book.author) ;
printf("售价:%.2f\n", book.price) ;
printf("出版日期:%d \n", book.date);
printf"出版社: %s\n" , book. publisher;
}
3. 结构体变量的初始化
3.1.类似于初始化数组
初始化一个变量和数组:
int a = 520;
int array[5] ={1,2,3,4, 5};
初始化一个结构体变量:
struct Book book =
{
"《三体》",
" 56.6 ",
" 20 "
};
到这里,总结一下什么时候要定义结构体。
当我们要保存一个数据,但是发现这个数据是一个大数据,这个数据是由多个小数据联合起来的,那么这个时候,先使用结构体自定义这个数据类型由哪些小变量合成的,然后再根据这个结构体类型声明变量来保存数据。
3.2.初始结构体的指定成员值
其语法和数组指定初始化元素类似,不过结构体指定初始
化成员使用点号(·)运算符和成员名。
· 比如我们可以让程序只初始化Book的price成员:
struct Book book = {price = 48.8};
· 还可以不按结构体声明的成员顺序进行初始化
struct Book book =
{
publisher ="清华大学出版社",
price =48.8,
date = 20171111
};
4.结构体类型的作用域
如果结构体类型是定义在函数的内部,那么这个结构体类型只能在这个函数中使用。
如果我们希望这个结构体类型可以用在所有函数中,那么就把这个结构体类型定义在函数的外面,也就是定义在最顶上。
一般情况下,结构体类型都是定义在函数外面的,以让所有函数可以使用。
5.结构体嵌套
回看上面的例子,如果我们要将书籍的日期分为年,月,日,显然,一个结构体是不够用的,因此,我们引入了结构体的嵌套功能。
例:
#include <stdio.h>
struct date
{
int year;
int month;
int day;
};
struct Book
{
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
}book = {
"<三体>",
"刘慈欣",
"45",
{2008,1,6};
"重庆出版社"
};
输出:
printf(“出版日期:%d年%d月%d日\n”,
book.date.year,
book.date.month,
book.date.day);
什么时候能用到结构体嵌套?
当我们在为结构体定义成员的时候,发现某个成员也是一个复杂的数据,需要几个小变量合起来描述,那么这个时候就可以再定义一个结构体类型来表示它。
6.结构体数组
假设有一个结构体类型,保存学生的信息:
struct Student
{
char* name;
int age;
int score;
};
假设我们有五个学生的信息需要输入,
struct Student stu1 = {“Jim”,18,100};
struct Student stu2 = {“Mary”,19,90};
struct Student stu3 = {“Ace”,18,88};
struct Student stu4 = {“Jack”,20,80};
struct Student stu5 = {“Bill”,22,20};
我们可以声明5个结构体变量,然后分别输入他们的信息,分别保存,这样虽然可以,但是管理起来比较麻烦。
于是,我们引入了结构体数组:
语法结构:struct+结构体类型名称+数组名称[数组长度];
例子:
struct Student students[5];
表示我们声明了1个长度为5的结构体数组,数组名为students,类型为struct Student。
例如:我们可以这么做
students[0] = stu1;
students[1] = stu2;
students[2] = stu3;
students[3] = stu4;
students[4] = stu5;
遍历的话可以使用循环结构:
for(int i = 0; i < 5; i++)
{
printf(“姓名:%s 年龄:%d 成绩:%d\n”,
students[i].name,
students[i].age,
students[i].score);
}
注意:
在赋值的时候不可以这样赋值:
students[0] = {“Jim”,18,100};
因为这种时候系统会将这种赋值方式和数组赋值的方式混在一起,所以无法使用这种形式赋值,如果非要用这种形式,应该如下操作:
students[0] = (struct Student){“Jim”,18,100};
结构体数组的初始化:
先声明结构体数组,然后用下标一个一个元素的赋值
在声明结构体数组的同时,给所有元素初始化
struct Student students[] =
{
{“Jim”,18,100},
{“Mary”,19,90},
{“Ace”,18,88},
{“Jack”,20,80},
{“Bill”,22,20}
};
结构体数组的长度计算:
也可以使用sizeof计算出数组占用的总字节数,再用这个总字节数除以每个元素占用的字节数。
例:
sizeof(students) / sizeof(struct Student);
7.结构体指针
每个结构体变量都有自己的存储空间和地址,因此指针也可以指向结构体变量
结构体指针变量的定义形式:struct 结构体名称 *指针变量名
有了指向结构体的指针,那么就有3种访问结构体成员的方式
1.结构体变量名.成员名
2.(*指针变量名).成员名
3.指针变量名→ 成员名
#include <stdio.h>
int main (int argc,conat char * argv[]) {
//定义一个结构体类型
struct student{
char *name;
int age;
};
//定义一个结构体变量
struct student stu ={"MJ",27};
//定义一个指向结构体的指针变量
struct student *p;
//指向结构体变量stu
p= &stu;
/*
这时候可以用3种方式访问结构体的成员
*/
//方式1:结构体变量名.成员名
printf ("name=%s, age = sd in", stu.name, stu.age);
//方式2∶(*指针变量名).成员名
printf ( "name=号B, age = sd ln",(*p).name,(*p).age )
//方式3:指针变量名->成员名
printf ( "name=%s, age = sd in", p->name, p->age) ;
return 0;
}
8.结构体与函数
结构体作为函数的参数
结构体是我们自定义的一种数据类型,所以当然可以作为函数的参数来使用
结构体作为参数的传递是值传递
如果希望函数的内部可以修改实参结构体变量的值,那么就需要使用指针
例子:
struct Student
{
char* name;
int age;
int score;
};
void test(struct Student stu)
{
if(stu.score >= 60)
{
printf(“恭喜%s,你及格了!\n”,stu.name);
}
else if(stu.score < 60)
{
printf(“对不起%s,你不及格!\n”,stu.name);
}
}
int main()
{
struct Student s1 = {“小明”,18,89};
test(s1);
return 0;
}
结构体作为函数的返回值
结构体类型完全可以作为函数的返回值
在返回的时候,直接将这个结构体变量的值返回即可。