C++程序设计教程(钱能)第二章 学习笔记

写在前面

        虽说以前学过C++,但忘得都差不多了。为了深入学习C++,决定先过一遍基础,再去看C++的经典书籍,并且最好是英文版。学习方法就是多看书,多实践。先从钱能的《C++程序设计教程》开始,笔记主要记录书中的知识点,同时涉及到的程序也一并记录,并给出运行结果。废话不多讲,下面是第二章的知识概要。

第二章 基本编程语句

2.1 说明语句

变量(或常量),由C++内部数据类型定义而产生。
对象(或常对象),程序员先定义类,再据此创建实体而产生。
说明语句分为定义语句和声明语句。声明语句声明某个名称。定义语句不但声明了名称,还给名称分配了存储空间。

2.1.1 变量定义
#include<iostream>
using namespace std;

int main(){
	double radius;
	cout << "please input radius:";
	cin >> radius;
	double result = radius * radius * 3.14;
	cout << "The result is " << result << "\n";
	system("pause");

}

程序中使用了“using namespace std;”语句,使得后面的名称若没有在现场定义,则会自动到std空间去找,“std::”被省略。
变量赋值方法:
1)定义时初始化

int a = 1;

2)赋值表达式

int a;
a = 1;
2.1.2 函数声明和定义
#include<iostream>
using namespace std;
void sphere();

int main(){
	sphere();
}

void sphere()
{
	double radius;
	cout << "please input radius:";
	cin >> radius;
	double result = radius * radius * 3.14;
	cout << "The result is " << result << "\n";
	system("pause");
}


2.2 条件语句

2.2.1 if语句
int max (int a, int b){
	if(a > b)
		return a;
	else
		return b;
}
//也可以写成下面的形式
int max (int a, int b){
	if(a > b)
		return a;
	return b;
}

注意:  if 的条件可以为一个变量、一个定义语句或赋值语句。因为C++的表达式都是有值的,有值表达式都可以作为条件。

if(s) 
	cout<< "This is s.";
if(int a = b) 
	cout << a << endl;
//用b赋给定义的a变量,若b为0,则跳过,否则输出。

注意:  条件语句可以嵌套,但要防止模棱两可。如:

int b = 48;
if (b > 0)
if (b < 50)
	cout << "OK"<< endl;
else
	cout << "Not OK"<<endl;

C++遇到这种情况,会认为else跟从最近的if,即

int b = 48;
if (b > 0){
	if (b < 50)
		cout << "OK"<< endl;
	else
		cout << "Not OK"<<endl;
}

2.2.2 条件表达式

语法:(条件)?表达式1:表达式2;
条件表达式实际对应了 if-else 语句的三部分。但由于条件表达式的优先级较低,所以整个条件表达式一般总要带上括号。

if(x)
	a = 327981;
else
	b = 327981;

等价于

x ? a = 327981 : b = 327981;

或者

(x ? a : b) = 327981;

但后者必须满足a和b为相同数据类型。
当 a ,b 为不同类型的数据时,则只能替代为

x ? a = 327981 : b = 327981;

注意,x ? a : b加括号,否则会被理解成

x ? a : (b= 327981);

2.2.3 switch语句

语法:
switch(表达式){
        case 常量表达式1:语句1
        case 常量表达式2:语句2
        …
        case 常量表达式n:语句n
        default:                     语句n+1
}

1.整数值分支判断
switch括号中表达式只能是整型、字符型和枚举型表达式。
case后面的常量表达式的类型必须与之匹配。

2.default分支
当表达式的值与某个case后面的值相等时,就执行case后面的语句;若都不匹配,就执行default语句;若无default语句,则直接退出switch语句。

3.case值即标号
每一个case常量表达式的值必须互不相同,否则会出现编译错误“case值已使用”。

4.遇break跳出
case通常与break语句联用,已保证多路分支的正确实现。
最后一个case分支可省略break语句。

5.case顺序随意
各个case包括default的出现次序可任意,在每个case分支都带有break的情况下,case次序不影响执行结果。

6.break使用技巧
可选择使用break,也可多个case语句并列,丰富switch语法。
几种情况下都执行同一操作时,不能简单地将值用逗号隔开。
如 case 1,2,3:a = 1 ;

7.switch嵌套
case与default标号是与包含它的最小的switch相联系的。

2.2.4 if 与 switch小结

switch 只能对确定值进行条件测试,而且仅限于整数或整数的子集,如果是范围测试,或者浮点值的比较判断,则只能用嵌套的if。

2.3 循环语句

2.3.1 for循环

for 循环包括四部分:循环初始、条件判断、状态修正、循环语句。
结构:
        for(循环初始;条件判断;状态修正){
                          循环体
         }
例如:求表达式1 + 2 + 3 + … + 100 的值。

int sum = 0;
for (int i = 1; i <= 100; i++) {
	sum += i;
}
cout << sum << endl;

或者

int sum = 0;
for (int i = 100; i > 0 ; i--) {
	sum += i;
}
cout << sum << endl;

或者省略状态修正部分

int sum = 0;
for (int i = 1; i <= 100;) {
	sum += i++;
}
cout << sum << endl;

或者省略条件判断部分

int sum = 0;
for (int i = 1; ; i++) {
	sum += i;
	if (i == 100)
		break;
}
cout << sum << endl;

或者在循环外部定义循环变量并初始化

int sum = 0; 
int i = 1;
for ( ; i <= 100; i++) {
	sum += i;
}
cout << sum << endl;


2.3.2 while 循环

当把上述循环省略循环变量初始化和循环变量修正部分,可演变成while循环。

int sum = 0; 
int i = 1;
for ( ; i <= 100; ) {
	sum += i++;
}
cout << sum << endl;
int sum = 0; 
int i = 1;
whlie(i <= 100) {
	sum += i++;
}
cout << sum << endl;

for循环结构的三个部分,可以省略其中的任意一部分、二部分,甚至是三部分。
当有些循环不能确定循环次数,就可用while循环,它可表示成一种无条件判断的无限循环形式。如:

int n = 1;
while (1) {
	if (n*n-6*n-13 > 0)
		break;
	else
		++n;
}
cout << n << endl;

写成无限的for循环形式:

int n = 1;
for( ; ; ){
	if (n*n - 6*n - 13 > 0) 
		break;
	else 
		++n;	
}
cout << n << endl;

**注意:**for循环结构中的两个分号不能少。
或者写成如下形式:

int n = 1;
for (; n*n - 6 * n - 13 <= 0; ++n);
cout << n << endl;

2.3.3 do-while循环

do- while循环,先执行循环体,再进行条件判断。因此,该循环至少执行一次。
do-while循环越来越少见,因为大多数do-while循环可以转换成while循环,进而转换成for循环。
求和循环可用do-while 表示成:

int sum = 0;
int i = 1;
do {
	sum += i++;
} while (i <= 100);
cout << sum <<endl;

该程序还可以简化成:

int sum = 0;
int i = 1;
do 
	sum += i;
while (++i <= 100);
cout << sum <<endl;

注意: while中的条件为 ++i <= 100 而不是 i++ <= 100,而后者计算出来的是5151,是从1+2+…+101,显然与题目要求不符。(书中这里有错误)

do-while循环的结构问题:

int sum = 0;
do {
	int i = 1;
	sum += i;
	i++;
} while (i <= 100); //错误,i没有定义。

2.4 循环设计

2.4.1 字符图形

例2-1 打印如下图形:

M
MM
MMM
MMMM
MMMMM
MMMMMM
MMMMMMM
MMMMMMMM
MMMMMMMMM
MMMMMMMMMM

程序代码:

for (int i = 1; i <= 10; i++) {
	for (int j = 1; j <= i; j++) {
		cout << "M";
	}
	cout<< endl;
}

例2-2 打印如下图形:

MMMMMMMMMMMMMMMMMMM
 MMMMMMMMMMMMMMMMM
  MMMMMMMMMMMMMMM
   MMMMMMMMMMMMM
    MMMMMMMMMMM
     MMMMMMMMM
      MMMMMMM
       MMMMM
        MMM
         M

程序代码:

for (int i = 1; i <= 10; i++) {
	for (int j = 1; j <= i - 1; j++) {
		cout << " ";
	}
	for (int k = 1; k <= 21 - 2*i; k++) {
		cout << "M";
	}
	cout << endl;
}	

例2-3 画出下列图形:

         A
        ABC
       ABCDE
      ABCDEFG
     ABCDEFGHI
    ABCDEFGHIJK
   ABCDEFGHIJKLM
  ABCDEFGHIJKLMNO
 ABCDEFGHIJKLMNOPQ
ABCDEFGHIJKLMNOPQRS

程序代码:

for (int i = 1; i <= 10; i++) {
	for (int j = 1; j <= 10 - i; j++) {
			cout << " ";
		}
	for (int k = 1; k <= 2*i-1; k++) {
		cout << char('A'+k-1);
	}
	/*for (char k = 'A'; k < 'A'+2*i-1; k++) {
			cout << k;
	}*/
	/*for (int k = 65; k < 65 +2*i-1; k++) {
		cout << char(k);
	}*/
	cout << endl;
}

注意: ‘A’+3 的值是整数类型,因为整数的表示范围大于字符。
C++支持类型扩展,也就是说当一个大范围的类型和一个小范围的类型做运算时,小范围类型会自动强转为大范围类型。

2.4.2 素数判定

1.按素数定义判断素数,即除以从2开始到m-1的整数。

cout << "Please input a number:\n";
int m;
cin >> m;
for (int i = 2; i < m; i++) {
	if (m % i == 0) {
		cout << m << " is not a prime.\n";
		return 1;
	}
}
cout << m << " is a prime.\n";

2.判断素数的稍微优化版.若一个整数不是素数,则必有一个因子小于等于该数的平方根。

cout << "Please input a number:\n";
int m;
cin >> m;
double sqrtm = sqrt(m*1.0);
for (int i = 2; i <= sqrtm; i++) {
	//这里有等号
	if (m % i == 0) {
		cout << m << " is not a prime.\n";
		return 1;
	}
}
cout << m << " is a prime.\n";

2.5 输入输出语句

2.5.1 标准I/O流

C++的标准输入/输出库就是头文件iostream。它不但提供了I/O库,也提供了使用该库的流模式。“cin>>”从输入设备流入和“cout<<”流出到输出设备。

2.5.2 流状态

1.常用的流状态
showpos           在正数(包括0)前面显示 + 号
showbase         十六进制整数前加 0x,八进制整数前加 0
uppercase         十六进制格式字母用大写字母表示(默认为小写字母)
showpoint         浮点输出即使小数点后都为 0 也加小数点
boolalpha         逻辑值 1 和 0 用 true 和 false 表示
left                    左对齐(填充字符填在右边)
right                  右对齐(填充字符填在左边)
dec                    十进制显示整数
hex                    十六进制显示整数
oct                     八进制显示整数
fixed                  定点数格式输出
scientific            科学计数法格式输出

注意:

  1. showpoint 默认6个有效位。
  2. C++默认的流输出数值有效位是6。
  3. fixed表示浮点输出应以固定点或小数点表示法显示。默认小数点后面数字位数为6.
  4. scientific格式为 a + E + b ,其中a表示浮点数,E或e均可,b可正可负,且正数可省略正号。
  5. setprecision操作符控制显示浮点数值的有效数的数量。
  • 不计算小数点。
  • 末尾的零将被省略。
  • 必须包含头文件<iomanip>才能使用。
  • setprecision的精度设置将保持有效,直到更改其他值为止。
  • 若值的位数小于setprecision指定的精度位数,则操作符不起作用。
  • 若有效数少于要显示的数字,setprecision将进行四舍五入,而非截断。
    例如:
    double num = 4.91877;
    cout << num << endl;//4.91877
    //有效数少于要显示的数字,setprecision将进行四舍五入,而非截断。
    cout << setprecision(5) << num << endl;//4.9188	
    cout << setprecision(4) << num << endl;//4.919
    cout << setprecision(3) << num << endl;//4.92
    cout << setprecision(2) << num << endl;//4.9
    cout << setprecision(1) << num << endl;//5
    
    double dollar = 24.51;
    cout << dollar << endl;//24.51
    //操作符不起作用,显示24.51。
    cout << setprecision(5) << dollar << endl;
    
    //末尾的零将被省略,显示21.4。
    cout << setprecision(5) <<  21.40 << endl;
    

6.setprecision + fixed 控制小数点后的数字位数。
   setprecision + scientific 控制系数小数点后的数字位数。

例如:

cout << showpos << 12 << endl ;//+12
cout << hex << 18 << " " <<showbase << 18 << endl;//12 0x12
cout << hex << 255 << " " << uppercase << 255 << endl;//ff FF
cout << 123.0 << " " <<showpoint << 123.0 << endl;//123 123.000
cout << (2>3) << " " << boolalpha << (2>3)<< endl; //0 false
cout << fixed << 12345.678<< endl;//12345.678000
cout << scientific << 123456.678 << endl;//1.234567e+05

取消流状态的操作方式为:

  • noshowpos, noshowbase, nouppercase, noshowpoint, noboolalpha
  • left与right是对立的,设置了此就取消了彼.
  • dec、oct、hex三者也是相互独立的,设置了此就取消了彼.
  • fixed 与 scientific 和一般显示方式三者也是独立的,但取消方式比较别扭,为 cout 捆绑函数调用的方式: cout.unsetf(ios::scientific);

2.三个有参数的常用流状态

width(int)          设置显示宽度
fill(char)            设置填充字符
precision(int)    设置有效位数(普通显示方式)或精度(定点或科学计数法方式)

这些流状态是以 cout 捆绑调用的形式设置的,不能与 << 连用。
特别注意 width(n) 为一次性操作,即第二次显示时将不再有效。默认为width(0),表示仅显示数值。
例如:

cout.width(5);
cout.fill('S');
cout << 23 << 23 << endl;  //显示SSS2323

3.与 << 连用的设置方式

setw(int)                 设置显示宽度
setfill(char)             设置填充字符
setprecision(int)     设置有效位数(普通显示方式)或精度(定点或科学计数法)

【例1】 倒三角形流状态设置版

for (int i = 1; i <= 10; i++) {
	cout << setfill(' ') << setw(i) << " "
		 << setfill('M') << setw(21 - 2 * i) << "M" << endl;
	}

注意: setw(int n) 当后面紧跟着的输出字段长度小于n的时候,在该字段前面用空格补齐;当输出字段长度大于n时,全部整体输出。
           所以输出空格时,应设置为setw(i) 而不是 setw(i-1) 。原因是setw(0) 与 setw(1) 显示相同。

【例2】 倒三角形string版

for (int i = 1; i <= 10; i++) {
	cout << string(i-1, ' ') << string(21 - 2 * i, 'M') << endl;
}

注意: 在头文件中要加上#include <string>,否则会报错。
           setw控制符只对后面紧跟的起作用,而setfill控制符一旦设定,就会对后面一直起作用,直到重新设置。

2.5.3 文件流

语法: ifstream fin(filename,openmode = ios::in);
            ofstream fout(filename,openmode = ios::out);
其中:
             ifstream 与 ofstream 是类型名,表示输入和输出文件流。
             fin 与 fout 是文件流的名称。
             filename是外部文件名,它与文件流一一对应。
             openmode是打开方式,ifstream 的默认打开方式是ios::in,ofstream 的默认打开方式是ios::out。因此,打开已经存在的输入文件和新建一个输出文件时可省略这个参数。

【例】 将输入文件aIn.txt 复制到输出文件aOut.txt。

ifstream in("aIn.txt");
ofstream out("aOut.txt");
for (string str; getline(in, str);)
	out << str << endl;

注意:
1)无须关闭文件操作,程序结束后,它会自动善后处理。
2)要保证程序能够运行,还要让文件aIn.txt与程序处在同一个目录中。
3)由于整行整行地读入,读入到 str中时,文件中的每个换行符都被丢掉了。为了照文件原样输出,在out流上输出str的同时,还要再补上一个回车。

许多输入输出语句都能返回操作状态(true/false),例如:

if(cin>>a) cout<<a;
if(getline(in,str)) cout<<str;
if((a = cin.get()) < 0 ) cout<<a;
if(cin) cin >> a;

注意: cin实际上代表着一段内存缓冲区,这段缓冲区的作用是,用于缓存从键盘输入的信息。

cin << 与 cin.get() 的区别:

  1. cin.get()是保留回车在输入流队列中的,而cin是丢弃回车的。

  2. get()函数是内置在 cin 对象中的,是cin 的一个成员函数。

  3. get()函数有3种形式:无参数的,有一个参数的和有3个参数的。
    ① cin.get():从指定的输入流中提取一个字符(包括空白字符),函数的返回值就是读入的字符。

    ② cin.get(ch):从输入流中读取一个字符,赋给字符变量ch。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。

    ③ cin.get(字符数组/字符指针, 字符个数n, 终止字符):从输入流中读取n-1个字符,赋给指定的字符数组(或字符指针指向的数组),如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取。如果读取成功则函数返回true(真),如失败(遇文件结束符) 则函数返回false(假)。

  4. 混合使用 cin>> 和 cin.get可能会有问题。示例:

    char ch;    //定义一个字符变量
    int number; //定义一个整型变量
    cout << "Enter a number:;
    cin >> number;   // 读取整数
    cout << "Enter a character: ";
    ch = cin.get() ;   // 读取字符
    cout << "Thank You!\n";
    

    在这个程序中,第 6 行的 cin.get 语句已经被跳过了。
    当执行第 4 行时,用户输入一个数字,然后按回车键。它会在遇到换行符时停止,换行字符未被读取,而是仍保留在键盘缓冲区中。从键盘读取数据的输入语句只在键盘缓冲区为空时等待用户输入值,但现在不为空。
    当第 6 行中的 cin.get 函数执行时,它开始从先前输入操作停止的键盘缓冲区读取,并发现了换行符,所以它无须等待用户输入另一个值。这种问题最直接的解决办法是使用 cin.ignore 函数。

筛法判断素数
基本思路:素数的倍数不是素数

int main() {
	vector<int> prime(10000, 1);
	for (int i = 2; i < 100; i++) {
		if (prime[i]) {
			for (int j = i; i * j < 10000; j++) {
				prime[i*j] = 0;
			}
		}
	}
	ifstream in("aIn.txt");
	for (int a; in >> a && a > 1 && a < 10000; ) {
		cout << a << " is " << (prime[a] ? "" : "not") << " a prime.\n";
	}
	system("pause");
}

aIn.txt
在这里插入图片描述
运行结果:
3 is a prime.
12 is not a prime.
101 is a prime.
131 is a prime.
6 is not a prime.



2.6 转移语句

break语句
break语句用于跳出当前循环。若有多重循环要一并跳出,则要借助于每重循环的额外条件判断或者是goto语句来完成。

continue语句
continue语句用在循环语句中,作为结束本次循环,准备进入下次循环的条件测试。若条件成立则执行continue的语句块,可以转变为若条件不成立则执行无continue的语句块。

goto语句

  • goto语句是低级语言的表征,可在函数体内直来直往。但现代程序设计不能容忍它在过程中任意穿梭而破坏过程体的结构。
  • 没有goto语句,过程体结构更清晰,程序更易读。
  • 若跳过声明和定义语句,则还将造成过程体的逻辑错误,因为后面引用的变量没有经过声明或定义是非法的。
  • C++中只有一个地方还有使用goto的价值:当从多重循环深处直接跳转到最外围循环之外时,如果用break, 就只能一重一重地退,而且还要边退边做记号,若用goto则显得更为直观。
    【例1】使用goto语句求1-100的和。
int sum = 0, i = 1;
Loop:
	sum += i;
	i++;
	if (i <= 100)
		goto Loop;
	cout << "The sum is " << sum << endl;

【例2】使用goto语句的极端例子:打印输出1-100的整数。

int a;
	goto Init;
Forward:
	a = a + 1;
Print:
	cout << a << endl;
	goto Down;
Init:
	a = 1;
	goto Print;
Down:
	if (a < 100)
		goto Forward;
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值