【C++】模块化程序设计

前置:C语言


1.1 IO

1.1.1 cout 输出流

操作符描述
ws提取空白符
endl插入换行符并刷新流
ends插入空字符
setw(int)设置域宽
setprecision(int)设置浮点数小数位数(包含小数点)
cout << setw(5) << setprecision(3) << 3.1415 << endl;
//设置域宽为5,小数点后保留两位有效小数

setw() 函数会用当前的填充字符控制对齐位置,默认的填充字符是空格

可以通过 <iomanip>setfill 来设置填充字符

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout << setfill('0') << setw(10) << 45698 << endl;//0000045698

    return 0;
}

CPU所执行的指令并不对操作数的类型加以区分,对各个操作数都执行相同的操作,编译器根据变量的数据类型选择合适的指令

  • 符号扩展:有符号数据类型,用符号位扩展

  • 0扩展:无符号数据类型,用0填充

1.1.2 I/O格式化输出

cout 是 STL 库提供的一个 iostream 实例,拥有 ios_base 基类的全部函数和成员数据

进行格式化定义可以使用 setfunsetf 函数和 flag 函数

cout 维护一个当前的格式状态

setfunsetf 是在当前的格式状态上追加或删除指定的格式

flag 则是将当前格式状态全部替换成指定的格式

操作符名含义
ios::dec数值类型采用十进制表示
ios::hex数值类型采用十六进制表示
ios::oct数值类型采用八进制表示
ios::showbase为整数添加一个表示其进制的前缀
ios::internal在符号位和数值中间按需插入字符,使两端对齐
ios::left在串的末尾插入填充字符使串左对齐
ios::right在串的末尾插入填充字符使串右对齐
ios::boolalphabool 类型的值以 truefalse 表示
ios::fixed将浮点数按照普通定点格式处理(非科学计数法)
ios::scientific将浮点数按科学计数法处理(带指数域)
ios::showpoint在浮点数表示的小数中强制插入小数点(默认情况下浮点数表示的整数不显示小数点)
ios::showpos强制在正数前添加 +
ios::skipws忽略前导空格,主要用于 cin
ios::unitbuf在每次输出后清空缓存
ios::uppercase强制大写字母

以上每种格式都独立占用一bit,可以用 | 运算符组合使用,调用 setf/unsetf 设置输出格式一般用法

setf 可接受一个或两个参数

  • cout.setf(指定格式);
  • cout.setf(指定格式,删除的格式);
cout.setf(ios::right | ios::hex);//设置十六进制右对齐
cout.setf(ios::right ,ios::adjustfield);//取消其他对对齐,设置为右对齐

以预定义的bit组合位

  • ios::adjustifield 对齐格式的bit组合位
  • ios::basefield 进制的bit组合位
  • ios::floatfield 浮点表示方式的bit组合位

设置格式后,之后所有的 cout 都会按照指定的格式状态执行

如果在一次输出过程中需要混在多种格式,使用 cout 的成员函数来处理就很不方便了,STL 提供了一套 <iomanip> 库可以满足这种使用方式

<iomanip> 库中将每一种格式的设置和删除都进行了函数级的同名封装,比如 fixed ,就可以将一个ostream的对象作为参数,在内部调用 setf(ios::fixed) 后再返回原对象。此外 <iomanip> 还提供了setiosflags、setbase、setfill、setw、setprecision等方便的格式控制函数。大多数示例代码都会使用到,因此默认包含的头文件均为:

#include <iomanip>
#include <iostream>
缩进

将输出内容按指定的宽度对齐

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout.flags(ios::left); //左对齐
    cout << setw(10) << -456.98 << "The End" << endl;
    cout.flags(ios::internal); //两端对齐
    cout << setw(10) << -456.98 << "The End" << endl;
    cout.flags(ios::right); //右对齐
    cout << setw(10) << -456.98 << "The End" << endl;

    return 0;
}

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout << left << setw(10) << -456.98 << "The End" << endl; //左对齐
    cout << internal << setw(10) << -456.98 << "The End" << endl; //两端对齐
    cout << right << setw(10) << -456.98 << "The End" << endl; //右对齐

    return 0;
}

在这里插入图片描述

整数
#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout.setf(ios::showpos | ios::uppercase);
    cout << showbase << hex << setw(4) << 12 << setw(12) << -12 << endl;
    cout << showbase << dec << setw(4) << 12 << setw(12) << -12 << endl;
    cout << showbase << oct << setw(4) << 12 << setw(12) << -12 << endl;
        
    cout.unsetf(ios::showpos | ios::uppercase);
    cout << noshowbase << hex << setw(4) << 12 << setw(12) << -12 << endl;
    cout << noshowbase << dec << setw(4) << 12 << setw(12) << -12 << endl;
    cout << noshowbase << oct << setw(4) << 12 << setw(12) << -12 << endl;

    return 0;
}

在这里插入图片描述


由于 <iomanip>setbase() 函数设置整数进制反而比上述方法还复杂,所以除非特殊的代码规范要求,一般不建议使用

小数

分为两种:

  • 定点表示 ios::fixed ,不带指数域
  • 科学计数法表示 ios::scientific 带指数域

<iomanip>setprecision 配合使用,可以指定小数点后保留位数

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout.setf(ios::fixed);
    cout << setprecision(0) << 12.05 << endl;
    cout << setprecision(1) << 12.05 << endl;
    cout << setprecision(2) << 12.05 << endl;
    cout << setprecision(3) << 12.05 << endl;

    cout.setf(ios::scientific, ios::floatfield);
    cout << setprecision(0) << 12.05 << endl;
    cout << setprecision(1) << 12.05 << endl;
    cout << setprecision(2) << 12.05 << endl;
    cout << setprecision(3) << 12.05 << endl;

    return 0;
}

在这里插入图片描述

有时因为机器表示浮点数的舍入误差,需要手动修正

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout << fixed << setprecision(1) << 2.05 << endl;//2.0
    cout << fixed << setprecision(1) << 2.05 + 1e-8 << endl;//2.1

    return 0;
}
字符串

字符串的输出处理主要是对齐,

字符串的输入方法

getline() 会读取屏幕上输入的字符,直至遇到换行符 \n 位置

  • getline(指定输入流,指定一个string对象)
  • getline(指定输入流,指定一个string对象,指定的结束字符)

getline 不会读入结束符号,读取指针会跳转至下一个非结束字符处

#include <iomanip>
#include <iostream>
#include <string>

using namespace std;

int main(void) {
    string str1, str2;
    getline(cin, str1);

    cin >> str2;
    cout << str1 << endl << str2 << endl;

    return 0;
}

输入:

abc
abc

结果:

abc
abc

缓冲区

由于调用系统函数在屏幕上逐个显示字符是很慢的,因此cin/cout为了加快速度使用缓冲区技术,粗略的讲就是暂时不输出指定的字符,而是存放在缓冲区中,在合适的时机一次性输出到屏幕上

如果要和C标准库的stdio库函数混合使用就必须要小心的处理缓冲区了

如果要与scanf和printf联合使用,务必在调用cout前加上cout.sync_with_stdio(),设置与stdio同步,否则输出的数据顺序会发生混乱。

flush和endl都会将当前缓冲区中的内容立即写入到屏幕上,而unitbuf/nounitbuf可以禁止或启用缓冲区。

#include <iomanip>
#include <iostream>

using namespace std;

int main(void) {
    cout << 123 << flush << 456 << endl;
    cout << unitbuf << 123 << nounitbuf << 456 << endl;
    return 0;
}

1.2 函数

C++完全兼容了 C语言结构化程序设计

  • 自顶向下:针对可能存在二义性的问题描述,转化为流程化、有限确定的算法描述,进而用无二义性的程序进行实现
  • 按功能划分模块
  • 每一模块都由顺序,选择,循环三种基本结构组成
  • 模块化实现的具体方法为子程序

1.2.1 基本结构

/*求x的n次方*/
# include<iostream>

using namespace std;

double mypower(int x,int n){
    double val = 1.0;
    
    while(n--)
		val *= x;
    return val;
}

int main(){
    int x,n;
    
    cin >> x >> n;
    cout << x << "的" << n << "次幂是:" << mypower(x,n) << endl;
    
    return 0;
}
/*二进制转十进制*/
# include<iostream>

using namespace std;

/*x的n次幂*/
double power(int x,int n){
    double val = 1.0;
    
    while(n--)
        val *= x;
    
    return val;
}

int main(){
	int val = 0;
    char ch;
    
    /*每8位为一组*/
    for(int i = 8;i >= 0;--i){
        cin >> ch;
        if('1' == ch)
            val += static_cast<int>(power(2,i));
    }
    
    return 0;
}
随机数
/*随机数的获取*/
# include<iostream>
# include<cstdlib>

using namespace std;

enum GameStatus{WIN,LOSE,PLAYING};

/*产生结果*/
int rollDice(){
    int die1 = 1 + rand()%6;
    int die2 = 1 + rand()%6;
    
    cout << "payer rolled" << die1 << "+" << die2 << "=" << die1 + die2 << endl;
    
    return die1 + die2;
}

int main(){
    int sum,myPoint;
    GameStatus status;
    
    unsigned seed;
    cin >> seed;//输入随机数种子,即为随机数序列设置初值,不同初值,产生的随机数序列不同
    srand(seed);//产生随机数序列
    
    sum = rollDice();
    switch(sum){
        case 7:
        case 11:
            status = WIN;
            break;
        case 2:
        case 3:
        case 12:
            status = LOSE;
            break;
        default:
        	status = PLAYING;
        	myPoint = sum;
            cout << "point is" << sum << endl;
    }
    
    while(PLAYING == status){
		sum = rollDice();
        if(sum == myPoint)
            status == WIN;
        else if(7 == sum)
            status == LOSE;
    }
    
    if(WIN == status)
        cout << "You win" << endl;
    else
        cout << "You lose" << endl;
    
    
    return 0;
}
数学函数

s i n ( x ) = x + x 3 3 ! + x 5 5 ! + . . . + x 2 n − 1 ( 2 n − 1 ) ! \begin{aligned} sin(x) = x+\frac{x^3}{3!}+\frac{x^5}{5!}+...+\frac{x^{2n-1}}{(2n-1)!} \end{aligned} sin(x)=x+3!x3+5!x5+...+(2n1)!x2n1

# include<iostream>
# include<cmath>

using namespace std;

const double TINY_VALUE = 1e-10;

double tsin(double x){
    double g = 0;
    double t = x;
    int n = 1;
    
    do{
        g += t;
        n++;
        t = -t*x*x/(2*n-1)/(2*n-1);
    }while(fabs(t) >= TINY_VALUE);//涉及精确度,添加精度变量
    
    return g;
}

1.2.2 递归

# include<iostream>

using namespacce std;

int c(int n,int k){
    if(k > n)
        return 0;
    else if(n == k || k == 0)
        return 1;
    else
        return c(n-1,k)+c(n-1,k-1);
}

int main(){
    int n,k;
    
    cin >> n >> k;
    cout << "C(n,k)" << c(n,k) << endl;
    
    return 0;
}

1.2.3 引用形参

一个变量的别名,指向同一块内存空间

声明引用时,必须对他初始化,使他指向已存在的对象

  • 只能初始化,不能修改

在作为函数参数时:执行主调函数中的 调用 时才会为变量分配内存,同时用实参来初始化形参

1.2.4 内联函数

内联函数不在调用时发生控制转移,只是将代码嵌入到调用处

适用于功能简单,规模小,经常使用的函数

inline 数据类型 函数名(形参列表){
    /*函数体*/
}

1.2.5 带默认形参的函数

在函数声明时,声明默认值

带默认形参值的形参必须在参数列表的最后

不允许对同于函数的形参多次定义,默认形参只能声明一次,声明时初始化,定义是不需要再次初始化的

1.2.6 函数重载

两个以上的函数,具有相同的函数名,但是形参个数或数据类型不同,编译器根据不同的参数列表调用最佳匹配函数

  • 构造函数可以重载,析构函数不能重载

在C标准中

  • 求整数的绝对值 abs()labs() 应该包含 stdlib.h

  • 求浮点数的绝对值 fabs() 应该包含 math.h

在C++标准中

  • stdlib.h:

    int abs(int n);

    long int abs(long int n);

  • math.h:

    double abs(int n);

    float abs(float x);

    long double abs(long double x);

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AmosTian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值