WHCSRL 技术网

C语言之结构体初阶_qq

c语言结构体内存问题

1.什么是结构体?

结构体是一些值的集合,这些值成为成员变量。结构体的每个成员变量可以是不同类型的变量。结构体一般是某类事物其属性的集合。例如,学生这个类型,通常会有,名字,学号,性别,年龄等。

2.结构体的声明

结构声明

struct tag{
     member-list;
}variable-list;
  • 1
  • 2
  • 3

结构体成员类型:
结构体的成员可以是标量,数组,指针,甚至是其他结构体
例如一个学生:

struct Stu{
     char name[20];
     int age;
     char sex;                //代码1
     char id[10];
 };

typedef struct Stu{
     char name[20];
     int age;               //代码2
     char sex;
     char id[10];
 }Stu;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

代码1和代码2区别:
代码1声明结构体类型 struct Stu
代码2 typedef将声明的结构体类型struct Stu重定义为 Stu
特殊的声明
匿名结构体类型:在声明的时候省略了结构体标签(tag)

struct 
{
     char name[20];
     int age;
     char sex;                //代码1
     char id[10];
 }x;

struct 
{
     char name[20];
     int age;               //代码2
     char sex;
     char id[10];
 }a[20],*p;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

问题:下述代码对吗?

p=&x;
  • 1

答案:错误,只要是两个结构体类型,即便是里面元素完全一样,也是两种类型。

p=&a;
  • 1

答案:正确,指向同一个结构体。

3.结构体的自引用

在结构体中包含一个类型为该结构体本身的成员是否可以呢?

struct Point {
		int x;                 代码1   
		struct Point p;
	};
  • 1
  • 2
  • 3
  • 4
struct Point {
		int x;                 代码2  
		struct Point* p;
	};
  • 1
  • 2
  • 3
  • 4

代码1,无法确定struct Point p的大小,错误
代码2,struct Point* p指针大小确定, 正确

typedef struct Point {
		int x;
	    Point* p;              代码3 
	}Point;
  • 1
  • 2
  • 3
  • 4
typedef struct Point {
		int x;                 代码4
	    struct Point* p;
	}Point;
  • 1
  • 2
  • 3
  • 4

代码3:错误
代码4:正确

4.结构体定义和初始化

struct Student {        结构体类型声明
		char name;
		int age;
}s1;    声明类型同时定义变量
struct Student s2;    定义结构体变量
struct Student s3 = { "zhangsan",20 };
	    初始化, 定义变量同时赋值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通过上述代码,则定义了3个结构体类型变量 s1, 声明类型同时定义变量。s2,定义结构体变量。 s3.初始化, 定义变量同时赋值

typedef struct Stu{
     char name[20];
     int age;               //代码2
     char sex;
     char id[10];
 }Stu;
 Stu s1;   //Stu  ==   struct Stu
 Stu s2={"lisi",18,m,20200114};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

上述代码是关于重新定义结构体类型的结构体变量的定义和初始化。

struct Point {
		int x;
		int y;
 };

struct Node {
		int data;
		struct Point p;
		struct Node*  n;
 }n1 = { 10,{3,4},NULL };  结构体嵌套初始化
	struct Node n2;
	struct Node n3 = { 20,{5,6},NULL }; 结构体嵌套初始化
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

上述代码是关于结构体嵌套的初始化用法

5.结构体成员访问

1.结构体变量访问成员:通过使用点操作符(.)访问。

struct Stu {     //结构体类型声明
		char name[10];
		int age;
 };    
   struct Stu s;
	strcpy(s.name, "zhangsan");
	s.age = 20;
	printf("%%s %%d
", s.name, s.age);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.结构体指针访问其指向变量的成员 (->)操作符

struct Stu {     //结构体类型声明
		char name[10];
		int age;
	};    
	struct Stu s = {"zhangsan",20};
	struct Stu *p = &s;
	printf("%%s  %%d
", s.name, s.age);
	printf("%%s  %%d
", (*p).name, (*p).age);
	printf("%%s  %%d
", p->name, p->age);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
上述代码中:
1.(*p).name 等价于 s.name 。p是一个结构体指针,指向s变量,指针解引用代表其所指向的元素s。
2. 使用结构体指针访问指向变量的成员 p->name

6.结构体传参

结构体传参会不会发生降维问题?不会
使用print1还是print2?

struct Student {
	char  name[10];
	int   age;
};
struct Student s = { "xiaoming",10 };


void print1(struct Student s) {
	printf("%%s  %%d
", s.name,s.age);
}
void print2(struct Student *p) {
	printf("%%s  %%d
", p->name,p->age);
}


int main() {
	print1(s);    传结构体
	print2(&s);    传地址
	return 0;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

函数传参时,参数是需要压栈,会有时间和空间的开销。
如果传入一个结构体对象时,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。
结论:结构体传参时,要传结构体的地址。

推荐阅读