前言
当我们要描述一个物体时,这时我们目前学到整形,浮点数之类的只能描述一种特征的数据类似已经不能够满足现状,这时我们就需要一个将它们整合起来的类型——结构体.
如果你学过结构体,不妨思考下列的问题,来考验一下你对结构体的了解程度;如果没学过,那就让我们带着这些问题,走入结构体的学习吧!
小小建议:手机/电脑 保存下来看,清晰度更高!
正文
一.结构体与数组
数组:有限个相同元素的集合,有序的元素序列。
结构体:可以是不同变量的集合,也可以是相同变量的集合,可以是结构体,指针,数组,整形,字符类型等。
结构体数组:是结构体还是数组?是数组,准确的说,是存放结构体的数组。
二.结构体变量的定义与初始化
法1:
#include<string.h>
struct BOOK
{
char name[20];
int price;
}stu;
int main()
{
strcpy(stu.name,"shun_hua");
stu.price = 8;
return 0;
}
stu是一个全局变量,因为定义在函数的外部。
图解:
法2:
struct BOOK
{
char name[20];
int price;
}stu = { "shun_hua",8 };
//在定义结构体的同时,同时定义与初始化结构体变量。
法3:
匿名结构体类型(即使匿名结构体的类型相同但还是两个不同的结构体)
struct
{
char name[20];
int price;
}stu;
struct
{
char name[20];
int price;
}*p;
int main()
{
strcpy(stu.name,"shun_hua");
stu.price = 8;
//*p=&stu;这个代码在编译器的角度来说就是错误的。
return 0;
}
缺点:这样的结构体定义过后只能用定义的那一个变量(stu)。
法4:
struct BOOK
{
char name[20];
int price;
};
int main()
{
struct BOOK author = { "shun_hua",18 };
//逆序初始化:struct BOOK author ={.price=18,.name="shunhua"};
return 0;
}
图解:
法5:
typedef struct BOOK
{
char name[20];
int price;
}stu;
int main()
{
stu author = { "shun_hua",18 };
return 0;
}
图解:
注意:
1.结构体成员的初始化,最好按照顺序来赋值。
2.结构体的定义是可以定义在函数内部的,不过不建议,全局变量方便函数之间使用。
3.结构体成员定义时,中文写分号不会报错,只会在你使用时,才会报错。
4.结构体定义时,成员只能声明,不能赋值。
三.结构体的访问
1.结构体变量访问成员用 .
2.结构体指针访问成员用 ->
注意:这两种符号只能访问结构体成员。没有结构体指针->结构体指针->结构体成员的用法。
1.变量访问
typedef struct MEN
{
char name[20];
float weight;
}men;
typedef struct BOOK
{
char name[20];
char author[20];
men man;
}stu;
int main()
{
stu book = { "c语言程序与设计","谭浩强",{"舜华",70} };
//scanf("%s %s", &book.author, &book.name);
printf("%s %s", book.author, book.name);
printf("%s %.1f", book.man.name, book.man.weight);
return 0;
}
2.指针访问
typedef struct MEN
{
char name[20];
float weight;
}men;
typedef struct BOOK
{
char name[20];
char author[20];
men man;
}stu;
int main()
{
stu book = { "c语言程序与设计","谭浩强",{"舜华",70} };
stu* p = &book;
//scanf("%s %s", &p->author, &p->name);
printf("%s %s", p->author, p->name);
printf("%s %.1f", p->man.name, p->man.weight);
return 0;
}
补充:结构体的自引用
注意:结构体自身是不能在结构体成员里面再出现,这样陷入了无限套娃的层次,不合法。但是结构体自身的指针是可以被直接引用的。
//第一种
struct Book
{
int book;
struct BOOK* next;
};
//第二种
typedef struct man
{
int age;
struct man* next;
}man;
下面的是错误的:
typedef struct
{
int age;
man* next;
}man;
可以这样理解编译器在扫描时是从上往下扫描的,里面的man在编译器的角度看是不符合语法规定的,所以不合法。
四.结构体传参
1.传值调用:函数接收的是结构体的值,是一份临时拷贝,并不是传入的的那个结构体变量本身。
2.传址调用:函数接收的结构体指针的值,是指针的一份临时拷贝,不是传入的结构体指针本身。
联想数组:数组传进去的本质是指针。数组名是数组首元素的地址。
1.传值
typedef struct MEN
{
char name[20];
float weight;
}men;
typedef struct BOOK
{
char name[20];
char author[20];
men man;
}stu;
stu print(stu book1)
{
scanf("%f", &book1.man.weight);
return book1;
}
int main()
{
stu book = { "c语言程序与设计","谭浩强",{"舜华",70} };
book=print(book);
printf("%f", book.man.weight);
return 0;
}
2.传址调用
typedef struct MEN
{
char name[20];
float weight;
}men;
typedef struct BOOK
{
char name[20];
char author[20];
men man;
}stu;
void print2(stu* p1)
{
scanf("%f", &p1->man.weight);
}
int main()
{
stu book = { "c语言程序与设计","谭浩强",{"舜华",70} };
stu* p = &book;
print2(p);
printf("%f", p->man.weight);
return 0;
}
联系两种调用:这里的两种代码都可以完成任务,但是由于内存中,拷贝地址(一个16进制的数)和拷贝整个结构体相比,传址调用明显更省内存空间,并且调用过程中的时间也会减少,性价比更高。
总结
在下的讲解到此就结束了,功非一日之成,勤非一时之恒。编程的世界细节满满,只怕有心人。希望你能有所收获。