前言
曾经写过一篇用结构体封装函数的博文
一、小叙-结构体
到目前为止我们使用的大多数数据类型都具有单一的值,例如整数、字符、布尔值、浮点数,这些可称为基本数据类型(Primitive Type)。
但字符串是一个例外,它由很多字符组成,像这种由基本类型组成的数据类型称为复合数据类型(Compound Type),正如表达式和语句有组合规则一样,由基本类型组成复合类型也有一些组合规则,例如本章要讲的结构体,以及第 8 章 数组要讲的数组和字符串。复合数据类型一方面可以从整体上当作一个数据使用,另一方面也可以分别访问它的各组成单元,复合数据类型的这种两面性提供了一种数据抽象(Data Abstraction) 的方法。指出,在学习一门编程语言时,要特别注意以下三方面
1.这门语言提供了哪些Primitive,比如基本数据类型,比如基本的运算符、表达式和语句。
2. 这门语言提供了哪些组合规则,比如复合数据类型,比如表达式和语句的组合规则。
3. 这门语言提供了哪些抽象机制,例如数据抽象和过程抽象(Procedure Abstraction) 。本节将以结构体为例来讲解数据类型的组合和抽象。至于过程抽象我们已经见过最简单的形式,就是把一组语句用一个函数名封装起来,当作一个整体使用,以后我们还会介绍更复杂的过程抽象。-----------《Linux C 编程一站式学习》
ps:作者猜测 结构体封装函数就是一种过程抽象,因为将一个函数的过程封装起来了(没想到之前还误打误撞写了过程抽象,从头学起把基础打牢)
话不多说,直接看程序。
————————————————————————————————————
二、数据抽象
1.复数存储
/* 题目 在本节的基础上实现一个打印复数的函数,打印的格式是x+yi,如果实部或虚部为0则省略,
* 例如: 1.0、 -2.0i、 -1.0+2.0i、 1.0-2.0i。最后编写一个main函数测试本节的所有代码。
* 想一想这个打印函数应该属于上图中的哪一层?
*
*
* 测试
*/
#include <stdio.h>
/* 定义一个复数 */
struct complex_struct
{
double x,y;
};
int main(void)
{
struct complex_struct
{
double x,y;
} ;
struct complex_struct z1;
// struct complex_struct z1={9,9};
printf("请输入实部、虚部,空格间隔:");
scanf("%f %f", &z1.x, &z1.y);
if ( z1.x==0 && z1.y==0 )
printf("0\n");
else if ( z1.x==0 && z1.y!=0)
printf("%.1fi\n", z1.y);
else if ( z1.x!=0 && z1.y==0 )
printf("%.1f\n", z1.x);
else
printf("%.1f+%.1fi\n", z1.x, z1.y);
return 0;
}
void show_complex(struct complex_struct z1)
{
if ( z1.x==0 && z1.y==0 )
printf("0\n");
else if ( z1.x==0 && z1.y!=0)
printf("%.1fi\n", z1.y);
else if ( z1.x!=0 && z1.y==0 )
printf("%.1f\n", z1.x);
else
printf("%.1f+%.1fi\n", z1.x, z1.y);
}
/* 题目 最后编写一个main函数测试本节的所有代码。想一想这个打印函数应该属于上图中的哪一层?
*
*
* 测试
*/
#include <stdio.h>
#include <math.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)
{
double PI=acos(1.0);
if(z.x>0)
return atan(z.y/z.x); /* 返回复数极角 */
else
return atan(z.y/z.x)+PI;
}
struct complex_struct make_from_real_img(double x, double y)
{
struct complex_struct z;
z.x=x;
z.y=y;
return z; /* 由x,y返回一个复数 */
}
struct complex_struct make_from_mag_ang(double r, double A)
{
struct complex_struct z;
z.x=cos(A)*r;
z.y=sin(A)*r;
return z; /* 由r,A返回一个复数 */
}
struct complex_struct add_complex(struct complex_struct z1, struct complex_struct z2)
{ /* 复数相加z1+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)
{ /* 复数相减z1-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)
{ /* 复数相乘z1*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)
{ /* 复数相除z1/z2 */
return make_from_mag_ang(magnitude(z1)/magnitude(z2), angle(z1)-angle(z2));
}
void show_complex(struct complex_struct z1)
{ /* 打印复数 */
if ( z1.x==0 && z1.y==0 )
printf("0\n");
else if ( z1.x==0 && z1.y!=0)
printf("%.1fi\n", z1.y);
else if ( z1.x!=0 && z1.y==0 )
printf("%.1f\n", z1.x);
else
printf("%.1f+%.1fi\n", z1.x, z1.y);
}
int main(void)
{
struct complex_struct z1={1.0,3.0};
struct complex_struct z2={2.0,4.0};
show_complex(add_complex(z1, z2));
show_complex(sub_complex(z1, z2));
show_complex(mul_complex(z1, z2));
show_complex(div_complex(z1, z2));
return 0;
}
2.分数
/* 题目 2、实现一个用分子分母的格式来表示有理数的结构体Rational及相关的函数,
* Rational之间可以做加减乘除运算,运算的结果仍然是Rational。测试代码如下:
*
int main(void)
{
struct Rational a = make_rational(1, 8); a=1/8
struct Rational b = make_rational(-1, 8); b=-1/8
print_rational(add_rational(a, b));
print_rational(sub_rational(a, b));
print_rational(mul_rational(a, b));
print_rational(div_rational(a, b));
return 0;
}
*
*/
#include <stdio.h>
#include <math.h>
/* 分子分母结构体 */
struct Rational
{
int num,den;
};
/* 获取分子 */
int num_part(struct Rational ra)
{
return ra.num;
}
/* 获取分母 */
int den_part(struct Rational ra)
{
return ra.den;
}
/* 生成一个分子分母结构体 */
struct Rational make_rational(int num, int den)
{
struct Rational ra;
ra.num=num;
ra.den=den;
return ra;
}
/* 求最大公约数 */
int GCD(int a, int b)
{
a=abs(a);
b=abs(b);
if ( a%b==0 )
return b;
else {
a=a%b;
return GCD(b,a);
}
}
/* 约分 */
struct Rational reduce_raction(struct Rational ra)
{
if(num_part(ra)==0)
return ra;
int gcd=GCD(num_part(ra), den_part(ra));
ra.num = num_part (ra) / gcd;
ra.den = den_part (ra) / gcd;
return ra;
}
/* 分数相乘 */
struct Rational mul_rational(struct Rational ra1, struct Rational ra2)
{
return reduce_raction( make_rational( num_part(ra1)*num_part(ra2), den_part(ra1)*den_part(ra2) ) );
}
/* 分数相除 */
struct Rational div_rational(struct Rational ra1, struct Rational ra2)
{
return reduce_raction( make_rational( num_part(ra1)*den_part(ra2), den_part(ra1)*num_part(ra2) ) );
}
/* 分数相加 */
struct Rational add_rational(struct Rational ra1, struct Rational ra2)
{
int num,den;
int lcm=den_part(ra1)*den_part(ra2)/GCD(den_part(ra1), den_part(ra2));
den=lcm;
num=num_part(ra1)*(lcm/den_part(ra1))+num_part(ra2)*(lcm/den_part(ra2));
return reduce_raction ( make_rational ( num, den ) );
}
/* 分数相减 */
struct Rational sub_rational(struct Rational ra1, struct Rational ra2)
{
int num,den;
int lcm=den_part(ra1)*den_part(ra2)/GCD(den_part(ra1), den_part(ra2));
den=lcm;
num=num_part(ra1)*(lcm/den_part(ra1))-num_part(ra2)*(lcm/den_part(ra2));
return reduce_raction ( make_rational ( num, den ) );
}
/* 打印分数 */
void print_rational (struct Rational ra)
{
printf("%d/%d\n", num_part(ra), den_part(ra));
}
// int num_part(struct Rational ra);/* 获取分子 */
// int den_part(struct Rational ra);/* 获取分母 */
// struct Rational make_rational(int num, int den);/* 生成一个分子分母结构体 */
// int GCD(int a, int b); /* 求最大公约数 */
// struct Rational reduce_raction(struct Rational ra); /* 约分 */
// struct Rational add_rational(struct Rational ra1, struct Rational ra2);/* 分数相加 */
// struct Rational sub_rational(struct Rational ra1, struct Rational ra2);/* 分数相减 */
// struct Rational mul_rational(struct Rational ra1, struct Rational ra2);/* 分数相乘 */
// struct Rational div_rational(struct Rational ra1, struct Rational ra2);/* 分数相除 */
// void print_rational (struct Rational ra);/* 打印分数 */
int main(void)
{
struct Rational a = make_rational(1, 8); //a=1/8
struct Rational b = make_rational(-1, 8); //b=-1/8
print_rational(add_rational(a, b));
print_rational(sub_rational(a, b));
print_rational(mul_rational(a, b));
print_rational(div_rational(a, b));
return 0;
}
3.优化-复数极坐标和直角坐标共同存储
#include <stdio.h>
#include <math.h>
enum coordinate_type { RECTANGULAR, POLAR };
/* 枚举直角坐标、极坐标 */
struct complex_struct {
enum coordinate_type t;
double x,y; /* 定义一个复数 */
};
double real_part ( struct complex_struct z)
{
if( z.t = RECTANGULAR )
return z.x;
else
return z.x*cos(z.y);
}
ps:有一点需要注意,结构体的成员名和变量名不在同一命名空间,但枚举的成员名和变量名却在同一命名空间,所以会出现命名冲突。例如这样是不合法的:
int main(void)
{
enum coordinate_type { RECTANGULAR = 1, POLAR };
int RECTANGULAR;
printf(“%d %d\n”, RECTANGULAR, POLAR);
return 0;
}
#include <stdio.h>
enum coordinate_type { RECTANGULAR = 1, POLAR };
int main(void)
{
// int RECTANGULAR;
printf("%d %d\n", RECTANGULAR, POLAR);
return 0;
}
总结
- 1-数据抽象
- 2-enum枚举