笔记16 (C语言 结构体初识)

笔记16 (C语言 结构体初识),第1张

注:

 本笔记参考B站up鹏哥C语言的视频

目录

结构体的声明

结构的基本知识

结构的声明

结构成员的类型

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

结构体的初始化

各种结构体初始化的总结

结构体成员的访问

点 *** 作符( . )

->的使用

结构体传参

知识点 - 压栈

解释

例如


结构体的声明 结构的基本知识

||| 就如同数组是相同类型的元素的集合,结构也是一些值的集合,这些值称为成员变量。


结构的每个成员可以是不同类型的变量。


(方便描述复杂对象)

结构的声明

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

如:描述一个学生

struct  Stu
{
	//成员变量
	char name[20];//描述名字
	int age;//描述年龄
	char id[20];//描述学号
}s1, s2;

int main()
{
	struct Stu s;//对象
	return 0;
}

ps:

  • 当输入[struct stu 变量名;]时,就(用类型)创建了一个对象


  • s1和s2也是结构体变量
  • s1和s2是全局变量,而s是局部变量
结构成员的类型

结构成员可以是标量、数组、指针,甚至是其它结构体。


如:

struct B
{
	char c;
	short s;
	double d;
};

struct  Stu
{
	char name[20];
	int age;
	char id[20];
	struct B a;
}s1, s2;

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

引用前述例子:

int main()
{
	struct Stu s = { {'w', 20,3.14},"名字",30,"20202020" };//对象
	return 0;
}

这就是结构体的初始化。


(因为结构体内还有一个结构体,所以再使用一个{ })

各种结构体初始化的总结
struct Point
{
	int x;
	int y;
}p1;				//声明类型的同时定义变量p1
struct Point p2;	//定义结构体变量p2

//初始化:定义变量的同时赋初值
struct Point p3 = { 2, 3 };

struct Stu
{
	char name[15];
	int age;
};
struct Stu s = { "名字",20 };//初始化

struct Node
{
	int data;
	struct Point p;
	struct Node* next;//结构体指针
}n1 = { 10,{4,10},NULL };//结构体嵌套初始化

struct Node n2 = { 20,{5,6},NULL };//结构体嵌套初始化

结构体成员的访问 点 *** 作符( . )

结构体变量的成员是通过点 *** 作符( . )访问的。


点 *** 作符接受两个 *** 作数。


如:

struct B
{
	char a;
	int b;
};

struct Stu
{
	struct B b1;
	char name[20];
	int age;
};

int main()
{
	struct Stu s1 = { {'w',2},"name",10 };
	printf("%c\n", s1.b1.a);
	printf("%d\n", s1.age);
	printf("%s\n", s1.name);
	return 0;
}

->的使用

如果想要通过指针访问结构体成员,要怎么做?

解引用的方式

struct Stu* ps = &s1;
printf("%c", (*ps).b1.a);

->的使用方式

printf("%c\n", ps->b1.a);

这种方法也可以访问到a,打印结果为:w

结构体传参

引用[->的使用]中使用的结构体及其变量。


void print1(struct Stu t)
{
	printf("%c %d %s %d", t.b1.a, t.b1.b, t.name, t.age);
}

void print2(struct Stu* ps)
{
	printf("%c %d %s %d", ps->b1.a, ps->b1.b, ps->name, ps->age);
}

int main()
{
	struct Stu s1 = { {'w',2},"name",10 };
	//写一个函数打印s的内容
	print1(s1);
	printf("\n");
	print2(&s1);

	return 0;
}

    [print1(s1);]          传值调用
    [print2(&s1);]        传址调用

[print2]的优点:

  1. 可以改变原变量s1 - 功能更丰富
  2. 初始传参时,参数是需要压栈的。


    如果传递一个结构体对象时,结构体过大,参数压栈的开销比较大,会导致性能的下降。


    (浪费时间和空间)

知识点 - 压栈

推荐了解:函数栈帧的创建和销毁

函数调用的参数压栈:

栈,是一种数据结构:先进的后出,后进的先出。


解释

当输入数据时:

       1. 当放入 1 这个数字时,1 是从顶部放入,放到底部向上的第一个位置上

顶部
1底部

      2.当放入 2 这个数字时, 2 从顶部放入,放到底部向上的第一个位置上

顶部
2
1底部

      ……

5顶部
4
3
2
1底部

从顶部放入数据的这种 *** 作就叫做压栈。


当删除数据时:

底部的 1 够不到,要删除数据,得先删除 5

        1.删除5

5顶部
4
3
2
1底部

                                                                  ↓

顶部
4
3
2
1底部

        2.删除4

顶部
4
3
2
1底部

                                                                  ↓

顶部
3
2
1底部

        ……

 这种删除数据的 *** 作就是出栈。


例如
Add(int x, int y)
{
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
	int a = 3;
	int b = 5;
	int c = Add(a, b);
	return 0;
}

复习:每一个函数的调用,都会在内存的栈区上开辟一块空间。


                                                                内存分为三块空间

栈区
堆区
静态区

在这之中,栈区:

· 创建 main函数,main函数 分配一块空间。


main函数

· 分配给 main函数 后,main函数 再划分空间,如:

                                                    当执行前三句代码时,main函数内

c = 0
b = 5
a = 3

接下来Add函数即将执行,需要传参。


(大部分情况下[Add(a, b)]内部是从右向左传参的)

先传b

                                                                         栈区内

b' = 5
main函数

再传 a

                                                                         栈区内

a' = 3
b' = 5
main函数

函数的参数传参也称函数的压栈 *** 作

Add函数被调用,在栈区内为Add函数开辟一块空间

Add函数
a' = 3
b' = 5
main函数

在Add函数执行时:

                                                                   Add函数内

z = 0

此时,访问 x 和 y ,其实是访问 a'b'

a' = 3(就是x)
b' = 5(就是y)

当调用完Add函数时,空间被返回。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563785.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-03
下一篇 2022-04-03

发表评论

登录后才能评论

评论列表(0条)

保存