文章目录
  1. 1. 复合类型与结构体
    1. 1.1. 定义和访问结构体
    2. 1.2. 结构体变量之间互相赋值和初始化
    3. 1.3. 结构体变量做函数的参数和返回值来传递
  2. 2. 数据抽象

无敌铁人

复合类型与结构体

结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。只不过它是一种符合类型。

最基本的、不可再分的数据类型称为**基本类型** Primitive Type

例如:整形、浮点型;

由基本类型组而成的类型称为**复合类型** Compound Type

例如字符串是有由很多字符组成。有些场合下需要把复合类型当作一个整体来用,而另外一些场合下需要分解组成这个符合类型的各种基本类型,符合类型的这种2面性为数据抽象Data Abstraction奠定了基础。

引子:
复数坐标系

从直角座标系来看,复数由实部和虚部组成,从极座标系来看,复数由模和辐角组成,两种座标系可以相互转换。

tips概念补充:复数x被定义为二元有序实数对(a,b) ,记为z=a+bi,这里a和b是实数,i是虚数单位。在复数a+bi中,a=Re(z)称为实部,b=Im(z)称为虚部。当虚部等于零时,这个复数可以视为实数;当z的虚部不等于零时,实部等于零时,常称z为纯虚数。复数域是实数域的代数闭包,也即任何复系数多项式在复数域中总有根。

用实部和虚部表示一个复数,我们可以写成由两个double型组成的结构体

1
2
3
struct complex_struct {
double x, y;
};

定义和访问结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<stdio.h>

struct complex_struct { double x, y; };

int main(void)
{
double x = 3.0;
struct complex_struct z1 = { x,4.0, }; /*z1.x=3.0,z1.y=4.0*/

struct complex_struct z2 = { 3.0, }; /*末尾多个逗号,不算错:z2.x=3.0,z2.y=0.0*/

struct complex_struct z3 = { 0 }; /*z3.x=0.0,z3.y=0.0*/

return 0;
}

结构体变量之间互相赋值和初始化

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main()
{
struct complex_struct { double x, y; };
struct complex_struct z1 = { 3.0,4.0 };
struct complex_struct z2 = z1; //z2必须是局部变量才能用变量z1的值来初始化。
printf("z2.x=%f\tz2.y=%f\n", z2.x,z2.y);
return 0;

}

结构体变量做函数的参数和返回值来传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//结构体变量可以当作函数的参数和返回值
#include<stdio.h>
struct complex_struct { double x, y; };
struct complex_struct add_complex(struct complex_struct z1, struct complex_struct z2)//add_complex函数实现了2个复数相加
{

z1.x = z1.x + z2.x;
z1.y = z1.y + z2.y;
return z1;

}


int main()
{

struct complex_struct z = { 3.0,4.0 };
z = add_complex(z, z);
printf("z.x=%f\tz.y=%f\n", z.x,z.y);
return 0;

}

数据抽象

引子:复数的定义

设  是-1的平方根(满足条件  =-1)  称为虚数单位*(imaginary unit)*——工程师通常用符号  而不是  来表示虚数单位。复数的形式为  ,其中a和b是实数。我们称为a为该实数的实部,b为虚部。注意,实数是复数的特例(b=0的情况)

复数有什么用呢?

它解决了之前不能解决的问题。考虑方程  ,如果限定  为实数则无解,如果允许复数,这个方程方程有2个解:  &nbp;与   

复数可以用直角座标或极座标表示,直角座标做加减法比较方便,极座标做乘除法比较方便。如果我们定义的复数结构体是直角座标的,那么应该提供极座标的转换函数,以便在需要的时候可以方便地取它的模和辐角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

#include<math.h>
#include<stdio.h>
struct complex_struct {
double x, y;
};

double real_part(struct complex_struct z)//实部
{
return z.x;
}

double img_part(struct complex_struct z) //虚部
{
return z.y;
}

double magnitude(struct complex_struct z) //复数的模
{
return sqrt(z.x*z.x + z.y*z.y);
}

double angle(struct complex_struct z)//反正切,夹角
{
return atan2(z.y, z.x);
}

//提供2个函数用来构造复数变量,既可以提供直角坐标系也可以提供极坐标系,在函数中做相应的转换后返回构造的复数变量:
struct complex_struct make_from_real_img(double x, double y)
{
struct complex_struct z;
z.x = x;
z.y = y;
return z;
}
struct complex_struct make_from_mag_ang(double r, double A)
{
struct complex_struct z;
z.x = r*cos(A);
z.y = r*sin(A);
return z;
}

/*-------------------------加减乘除-------------*/
struct complex_struct add_complex(struct complex_struct z1, struct complex_struct z2)
{
return make_from_real_img(real_part(z1) + real_part(z2),
img_part(z1) + img_part(z2));
}

struct complex_struct sub_complex(struct complex_struct z1, struct complex_struct z2)
{
return make_from_real_img(real_part(z1) - real_part(z2),
img_part(z1) - img_part(z2));
}

struct complex_struct mul_complex(struct complex_struct z1, struct complex_struct z2)
{
return make_from_mag_ang(magnitude(z1)*magnitude(z2),
angle(z1) + angle(z2));
}

struct complex_struct div_complex(struct complex_struct z1, struct complex_struct z2)
{
return make_from_mag_ang(magnitude(z1) / magnitude(z2),
angle(z1) - angle(z2));
}



double print_complex(struct complex_struct z) //打印复数的函数,该函数属于数据表示层
{
if (z.x == 0 && z.y == 0) {
printf("0\n");
}
else if (z.x == 0 && z.y != 0) {
printf("%.1f i\n", z.y);
}
else if (z.x != 0 && z.y == 0) {
printf("%.1f\n\n", z.x);
}
else {
printf("%.1f + %.1f i\n\n\n", z.x, z.y);
}
}


/*-----------------------主函数-----------------------*/
int main(void)
{

struct complex_struct z = { 3.4, 4.7 };
z = make_from_real_img(z.x, z.y);
printf("make_from_real_img:参数%f,%f", z.x, z.y);
printf("\nz.x=%f\tz.y=%f\n\n\n",z.x, z.y);


z = make_from_mag_ang(3.0, 4.0);
printf("make_from_mag_ang:参数%f,%f", 3.0, 4.0);
printf(" z.x= %f\tz.y=%f\n\n\n", z.x, z.y);


struct complex_struct l = { 2.7, 3.2 };
struct complex_struct j= { 1.1, 1.1 };
struct complex_struct m;
printf("add_complex:参数%f,%f \t %f,%f\n", l.x,l.y,j.x,j.y);
m = add_complex(l, j);
printf("%f\t%f", m.x, m.y);



struct complex_struct k = { 0.0, 4.7 };
printf("\n\n打印复数:参数%f,%f\n", k.x, k.y);
print_complex(k);

return 0;

}

程序运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
make_from_real_img:参数3.400000,4.700000
z.x=3.400000 z.y=4.700000


make_from_mag_ang:参数3.000000,4.000000 z.x= -1.960931 z.y=-2.270407


add_complex:参数2.700000,3.200000 1.100000,1.100000
3.800000 4.300000

打印复数:参数0.000000,4.700000
4.7 i
Press any key to continue . . .

数据抽象

这里的复数存储表示层和复数运算层称为抽象层*(Abstraction Layer),从底层往上层来看,复数越来越抽象了,把所有这些层组合在一起就是一个完整的系统。*组合使得系统可以任意复杂,而抽象使得系统的复杂性是可以控制的,任何改动都只局限在某一层,而不会波及整个系统。

著名科学家Butter Lampson说过”All problems in computer science can be solved by another level of indirection”这里的indirection其实就是abstraction的意思。

文章目录
  1. 1. 复合类型与结构体
    1. 1.1. 定义和访问结构体
    2. 1.2. 结构体变量之间互相赋值和初始化
    3. 1.3. 结构体变量做函数的参数和返回值来传递
  2. 2. 数据抽象