《Linux C 编程一站式学习》学习日记 4 结构体

本文介绍了C语言中结构体的基础概念,包括复数、分数的存储与操作,以及通过结构体实现数据抽象的方法。重点讲解了如何封装函数体现过程抽象,并展示了复数极坐标和直角坐标的联合存储。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

曾经写过一篇用结构体封装函数的博文


一、小叙-结构体

到目前为止我们使用的大多数数据类型都具有单一的值,例如整数、字符、布尔值、浮点数,这些可称为基本数据类型(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枚举
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值