[C]第七章--结构体

什么是结构体?

  • 当单独的几个数据类型不足以表达用户需求时,这时候就需要构建比较复杂的结构体变量.
  • 结构体(struct)指的是一种数据结构,是C语言中聚合数据类型的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。
    结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型,成员一般用名字访问。
  • 结构,是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同的类型.

结构的声明

struct tag{
	member-list;
}variable-list;

struct是自定制的类型,用这个类型来抽象信息.
什么又是抽象?

  • 是在具体事物的基础上,提取出一些需要的核心信息,再表达出来
  • 抽象相对于具体,少了很多"信息"

这里定义好了结构体变量Student,但是在实际使用中都是以struct Student xx 的 形式出现,十分麻烦,所以我们通常在定义时加上关键词typedef:

例如描述一个学生,他有名字,年龄,性别,学号:

typedef struct Student{
	char name[20];	//名字
	int age;		//年龄
	char sex[5];	//性别
	char id[20];	//学号
}Stu;	
//注意 这里最后的分号不能省略

通过typedef关键词的使用,之后结构体变量的使用就简化为Student xx
最后一行的Stu,与typedef相结合就可以理解为重命名,所以之后就可以使用Stu xx,并且将变量扩展为全局变量.
同样这一全局变量的设定也可以单独语句实现:

typedef struct Student Stu;
  • 全局变量的设定会少写很多struct,但是会有重名问题的风险.

      结构的成员可以是标量,数组,指针,甚至是其他结构体.
    

结构体变量的定义和初始化

定义

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 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;
}

从二者相同的结果中分析我们可以得到结论:

  • a -> b等效于(*a).b

结构体传参

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;
}

我们可以想想上面代码中print1print2那个函数更好?
答案是: print2函数
原因比较复杂,简单总结为一下一段话:

讲解函数栈帧的时候,我们讲过函数传参的时候,参数是需要压栈的.如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降.

  • 结论:
    结构体传参的时候,推荐传递结构体地址,这样可以降低开销.

结构体的嵌套

typedef struct School{
	Student students[1000];	//之前定义过的结构体变量
	int size;
}School;
  • 这样的话不能直接嵌套自身这个结构体,如果嵌套了运行结果为使用了未定义的结构体.
  • 而且也无法对这个结构体函数的变量进行sizeof操作,因为不知道结构体的大小(内存占存大小)
    如果想要嵌套,可以用指针来实现:
typedef struct Student{
	char name[1024];
	int score;
	struct Student* s;	//指针 ,嵌套了自身结构体
}student;
  • 这样的话,如果执行sizeof这个结构体函数定义的变量,就会有明确的占存大小
    例如上面这个程序:
    sizeof的结果为: 1024 + 4 + 4 = 1032;

嵌套也可能很复杂,多个结构体变量可以互相传参,这就会产生占存动辄上G的结构体,所以谨慎使用嵌套.

猜你喜欢

转载自blog.csdn.net/qq_42351880/article/details/84958577
今日推荐