第二章 基础概念
基本字符集和词法记号
基本字符:
- 大小写英文字母:A~Z a~z
- 数字字符:0~9
- 特殊字符
数据类型(常量&变量)
- 首选char
- C++中无字符串变量
- 用字符数组存放字符串变量
- 用string类存放字符串
字符串:“a”=a+\0
字符:‘a’=a
(\0表示结尾标识)
初始化变量的方式:
(浮点数在机器中近似存储)
int a=0
int a(0)
int a={0}
int a{0}
ps:用{}是初始化列表,不允许数据类型丢失。保持数据类型一致。
运算及表达式
简单运算符:
n=n+5
将n+5赋值给n
数据类型为左边对象的类
复合赋值运算符:
a+=3 等价于 a=a+3
x*=y+8 等价于 x=x*(y+8)
- 逗号运算及表达
格式:表达式1,表达式2
运算:先求表达式1,再求表达式2,输出结果为表达式2的值
eg:
a=3*5,a*4
输出为60
- 关系运算及表达(需进行比较运算)
优先次序:
高 < <= > >= 优先级相同
↓
低 == =!优先级相同
布尔类型:值只能为true/false
eg:
a>b,c<=a+b,x+y==3
- 逻辑运算及表达(布尔类型)
高 !非
↓ &&与
低 ||或 - 条件运算及表达
表达式1(布尔类型) ?表达式2:表达式3
先求1,为真则求2;为假,求3; - sizeof运算(计算某字节或变量所占字节)
sizeof(变量名) 或 sizeof 表达式
sizeof(short)
sizeof x
- 按位运算
3 :00000011
5 :00000101
3&5:00000001
3|5:00000111
第三章 数据的输入与输出
-
数据的流[I/O]:数据从一个对象到另一个对象的流动
cin cout -
预定义插入符和提取符
cout<<表达式<<表达式…
【<<为预定义插入符,标准输入和输出】
cin>>表达式>>表达式…
【>>表示预定义提取符】
if语句
//语法结构
·if(表达式) 语句
·if(表达式) 语句1 else 语句2
·if ()
{
if () 语句1
else 语句2
}
else
{
if () 语句3
else 语句4
}
PS:加{}方便检查匹配关系
#eg:取两个整数,比较大小
#include <iostream>
using namespace std;
int main() {
int x,y;
cout << "Enter x and y:";
cin >> x >> y;
if (x != y)
if (x > y)
cout << "x>y" << endl;
else (x < y)
cout << "x<y" << endl;
else
cout << "x=y" << endl;
return 0;
}
switch语句
//语法结构
{case 常量表达式1:语句1
case 常量表达式2:语句2
...
case 常量表达式n:语句n
default: 语句n+1
}
执行顺序
- 以case中常量表达式为入口标号,由此开始顺序执行。因此每个分支后必须加入break语句。
#eg:输入一个0~6的整数,转换成星期输出
#include <iostream>
using namespace std;
int main() {
int day;
cin >> day;
switch (day) {
case 0:cout << "Sunday" << endl;
break;
case 1:cout << "Monday" << endl;
break;
case 2:cout << "Tuesday" << endl;
break;
case 3:cout << "Wednesday" << endl;
break;
case 4:cout << "Thursday" << endl;
break;
case 5:cout << "Friday" << endl;
break;
case 6:cout << "Saturday" << endl;
break;
default:
cout << "Day out of range Sunday...Saturday" << endl; break;
}
return 0;
}
删除break语句会顺序执行其他语句,不会跳出
while语句(先判断条件)
//语法结构
while(表达式)语句
#eg:求自然数1~100的和
#include <iostream>
using namespace std;
int main() {
int i = 1, sum = 0;
while (i <= 100) {
sum += 1;//sum = sum + 1;
i++;
}
cout << "sum=" <<sum << endl;
return 0;
}
dowhile语句(后判断条件)
//语法结构
do 语句
while(表达式)
先执行循环体结构,后判断条件
表达式为true,继续执行循环体
#eg:输入一个数,将各数字翻转后输出
#include <iostream>
using namespace std;
int main() {
int n,right_digit,newnum=0;
cout << "Enter the number:";
cin >> n;
cout << "The number is reverse order is ";
do {
right_digit = n % 10;
cout << right_digit;
n /= 10;
} while (n != 0);
cout << endl;
return 0;
}
#eg:求自然数1~100的和
#include <iostream>
using namespace std;
int main() {
int i = 1, sum = 0;
do{
sum+=i;
i++;
}
while (i <= 100);
cout << "sum=" <<sum << endl;
return 0;
}
for语句
//语法结构
for(初始语句;表达式1;表达式2)语句
#eg:输入一个整数,求它的所有因子
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Enter a positive integer:";
cin >> n;
cout << "Number"<<n<<"Factors";
for (int k=1;k<=n;k++)
if(n%k==0)
cout << k <<" ";
cout << endl;
return 0;
}
嵌套的控制结构、其他控制语句
- 嵌套
#eg:输入一系列整数,统计出正整数的个数i和负整数个数j,读入0则结束。
#include <iostream>
using namespace std;
int main() {
int i=0,j=0,n;
cout << "Enter some integers (enter 0 to quit):"<< endl;
cin >> n;//循环体外的n要准备好,用于判断
while (n != 0) {
if (n > 0)i += 1;
if (n < 0)j += 1;
cin >> n;//每次循环体结束读入n,用于下次一处理读入的数据
}
cout << "Count of positive integers:"<< i << endl;
cout << "Count of positive integers:"<< j << endl;
return 0;
}
其他
break:使程序从循环体和switch语句跳出,继续执行逻辑下一条语句,不宜用在别处。
continue:结束本次循环,接着判断是否指向下一次循环。
goto:使程序的执行流程跳转到语句标号所指定位置,不提倡使用。
类型别名
typedef:已有类型别名,新类型名表typeof double Area,Volume; typeof int Natural;
using:新类型名=已有类型名 using Area = double、using Volume=double
枚举类型
定义方式:将全部可取值一一列举出来
语法形式:enum 枚举类型名 {变量值列表}
enum Weekend {SUN,MON,TUE.WED,THU,FRI,SAT}
不限定作用域枚举类型
- 枚举元素是常量,不能对其进行赋值;
- 枚举元素具有默认值,依次为:0,1,2…
- 可以在声明时另外定义指定枚举元素的值,如
enum Weekend {SUN=7,MON=1,TUE.WED,THU,FRI,SAT}
TUE自动定义为2; - 枚举值可以进行关系运算;
- 整数值不能直接赋给枚举变量,需要进行强制类型转化;
- 枚举值可以赋给整型变量,因为它是整型的子集。
auto与decltype类型
- auto:编译器通过初始值自动推断变量的类型
例如auto val = val1 + val2
如果 val1 + val2 是int类型,则val是int类型,
如果 val1 + val2 是double类型,则val是double类型 - decltype:定义一个变量与某一表达式的类型相同,但并不用该表达式初始化变量
例如:decltype(i)j=2 表示j以2做为初始值,但类型与i一致
实验二
#eg:求自然数1~100的和
利用dowhile:
#include <iostream>
using namespace std;
int main() {
int i = 1, sum = 0;
do{
sum+=i;
i++;
}
while (i <= 100);
cout << "sum=" <<sum << endl;
return 0;
}
利用for:
#include <iostream>
using namespace std;
int main() {
int i = 1, sum = 0;
for (i = 1; i <= 100; i++)
{
sum += i;
}
cout << "sum=" << sum << endl;
system("pause");
return 0;
}
#eg:编程计算图形面积
程序可计算圆形、长方形、正方形的面积,运行时先提示用户选择图形的类型,然后,对圆形要求用和输入半径值,对长方形用户要求输入长和宽的值,对正方形要求用户输入边长,计算出面积的值然后显示。
#include <iostream>
using namespace std;
const float Pi = 3.1416;
int main() {
int iType;
float radius, a, b, area;
cout << "图形的类型为?(1-圆形 2-长方形 3-正方形):";
cin >> iType;//iType为int型
switch(iType)
{
case 1:cout << "圆的半径为:";
cin >> radius;
area = Pi * radius * 2;
cout << "面积为:" << area << endl;
break;
case 2:cout << "长方形的长为:";
cin >> a;
cout << "长方形的宽为:";
cin >> b;
area = a * b;
cout<<"面积为:"<< area << endl;
break;
case 3:cout << "正方形的边长为:";
cin >> a;
area = a * a;
cout << "面积为:" << area << endl;
break;
default: cout << "不是合法的输入值!" << endl;
}system("pause");
return 0;
}
#eg:声明一个表示时间的结构体
可以精确表示年、月、日、小时、分、秒;
提示用户输入年、月、日、小时、分、秒的值,然后完整的显示。
#include <iostream>
using namespace std;
struct MyTimeStruct
{
unsigned int year;
unsigned int month;
unsigned int day;
unsigned int hour;
unsigned int min;
unsigned int sec;
};
int main()
{
MyTimeStruct mytime = { 2020,1,1,12,0,0 };
cout << "Please input year:" << endl;
cin >> mytime.year;
cout << "please input month:" << endl;
cin >> mytime.month;
cout << "Please input day:" << endl;
cin >> mytime.day;
cout << "Please input hour:" << endl;
cin >> mytime.hour;
cout << "Please input min:" << endl;
cin >> mytime.min;
cout << "Please input sec:" << endl;
cin >> mytime.sec;
cout << "the time is set to:"
<< mytime.year << "/"
<< mytime.month << "/"
<< mytime.day << "/"
<< mytime.hour<< ":"
<< mytime.min << ":"
<< mytime.sec << endl;
return 0;
}
第四章
函数定义的语法形式
类型标识符 函数名(形式参数表)
{
语句序列 —— 最后一句是return,返回结果类型。
}
函数的调用
- 函数在调用前需要先声明——原型声明
【函数的定义与调用往往不在一个程序中】 - 可嵌套调用——在函数体中调用另一个函数
- 递归调用——直接或间接调用自身
函数调用
#eg:在键盘中输入2进制数,将其转换成10进制
#include <iostream>
using namespace std;
double power(double x, int n);//计算x的n次方
int main()
{
int value = 0;
cout << "Enter an 8 bit binary number ";
for (int i = 7; i >= 0; i--) {
char ch;
cin >> ch;
if (ch == '1')
value += static_cast<int>(power(2, 1));
}
cout << "Decimal value is " << value << endl;
system("pause");
return 0;
}
double power(double x, int n) {
double val = 1.0;
while (n--)
val *= x;
return val;
}
#eg:编写程序求pi,pi=16arctan(1/5)-4arctan(1/239),其中arctan x=x-(x^3/3) + (x^5/5) - (x^7/7)+…
直到级数某项绝对值不大于10^-15为止;pi和x均为double类型
#include <iostream>
using namespace std;
double arctan(double x) {
double sqr = x * x;
double e = x;
double r = 0;
int i = 1;
while (e / i > 1e-15) {
double f = e / i;
r = (i % 4 == 1) ? r + f : r - f;
e = e * sqr;
i += 2;
}
return r;
}
int main() {
double a = 16.0*arctan(1 / 5.0);
double b = 4.0*arctan(1 / 239.0);
//整数相除结果取整,若写1/5和1/239结果都是0
cout << "Pi= " << a - b << endl;
system("pause");
return 0;
}
#eg:寻找并输出11~999之间的数m,满足m m^2 m^3均为回文数
例如11满足上述条件,11^2=121 ,11^3=1331
#include <iostream>
using namespace std;
//判断是否是回文数
bool symm(unsigned n) {
unsigned i = n;
unsigned m = 0;
while (i > 0) {
m = m * 10 + i % 10;
//第一次输出为最低位,下一次输出时将最低位 *10进位为高一位再累加
i /= 10;
//i除以10取余数后留着下一次用
//直到 i=0,所有数遍历完成,反转结束,全部存到 m 中
}
return m == n;
}
int main()
{
for (unsigned m=11;m<1000;m++)
if (symm(m) && symm(m*m) && symm(m*m*m)) {
cout << "m= " << m;
cout << "m*m= " << m * m;
cout << "m*m*m= " << m * m * m<<endl;
}
system("pause");
return 0;
}
函数的嵌套调用
#eg:输入两个整数,求平方和
#include <iostream>
using namespace std;
int fun2(int m) {
return m * m;
}
int fun1(int x, int y) {
return fun2(x) + fun2(y);
}
int main() {
int a, b;
cout << "Please enter two integers(a and b) :" ;
cin >> a >> b;
cout << "The sum of square of a and b :" << fun1(a, b) << endl;
system("pause");
return 0;
}
函数的递归调用
#eg:计算n!
#include <iostream>
using namespace std;
unsigned fac(unsigned n) {
unsigned f;
if (n == 0)
f = 1;
else
f = fac(n - 1)*n;
return f;
}
int main() {
unsigned n;
cout << "Enter a positive integer: ";
cin >> n;
unsigned y = fac(n);
cout << n << "!= " << y << endl;
system("pause");
return 0;
}
函数的参数传递
- 在函数被调用时才分配形参的存储单元
- 实参可以是常量、变量或表达式
- 实参类型必须与形参类型相符
- 值传递是传递参数值,即单向传递
- 引用传递可以实现双向传递,比直接赋值所占内存空间小,但如果对类进行引用,则需要内存空间很大
- 常引用做作参数可以保障实参数据的安全
引用类型
- 引用(&)是标识符的别名
- 定义一个引用时,必须同时对它进行初始化,使它指向一个已经存在的对象
int i,j; int &ri=i;//定义int引用ri,并初始化为变量i的引用
j=10 ri=j;//相当于i=j
- 一旦一个引用被初始化后,就不能改指向其他对象
- 引用可以作为形参
#eg:输入两个整数交换后输出(值传递)
#include <iostream>
using namespace std;
void swap(int a, int b) { //改swap(int& a,int& b)
int t = a;
a = b;
b = t;
}
int main(){
int x = 5, y = 10;
cout << "x= " << x << "y= " << y << endl;
swap(x, y);
cout << "x= " << x << "y= " << y << endl;
system("pause");
return 0;
}
//输出的 x y 值没有被交换
含有可变参数的函数
C++标准中提供了两种主要的方法
- 如果所有实参类型相同,可以传递一个名为initializer_list的标准库类型(标准库类型,用于表示某种特定类型的值的数组。该类型定义在同名的头文件中)
- 如果实参的类型不同,可以编写可变参数模板
initializer_list使用方法
- 使用该类模板需要在名字后跟一对尖括号,括号内给出参数类型。例如
initializer_list<string> Is;
initializer_list<int> Ii;
- 特殊的一点:其对象中元素永远是常量值,无法改变对象元素中的值
- 含有initializer_list形参的函数可以同时拥有其他形参
内联函数
内联函数声明使用关键字inline
- 编译时在调用处用函数体进行替换
- 节省了参数传递
- 控制转移等开销
注意:
- 内联函数中不能有循环语句和switch语句
- 内联函数的定义必须出现在内连函数第一次被调用之前
- 对内联函数不能进行异常接口声明
#eg:计算圆的面积
#include <iostream>
using namespace std;
const double PI = 3.14159265358979;
inline double calArea(double radius){
return PI * radius * radius;
}
int main(){
double r = 3.0;
double area = calArea(r);
cout<< area << endl;
system("pause");
return 0;
}
constexpr函数
用于初始化常量
constexpr函数语法规定
- constexpr修饰的函数,在其所有参数都是constexpr时一定返回constexpr
- 举例:
constexpr int get_size() {return 20};constexpr int foo = get_size() //正确,foo是一个常量表达式
带默认参数值的函数
可以预先设置默认的参数值,调用时如给出实参,则采用实参值,否则采用预先设定的默认值。
#eg:加法函数
int add(int x = 5,int y = 6){
return x+y;
}
int main(){
add(10,20); //10+20
add(10); //10+6
add(); //5+6
}
默认参数值的说明次序
- 有默认值参数的形参必须列在形参列表的最右,即默认参数值的右面不能有无默认值的参数(有→无)
- 调用时实参与形参的结合次序是从左向右
int add(int x, int y=5, int z=6);
√
int add(int x=1, int y=5, int z);
×
int add(int x=1, int y, int z=6);
×
默认参数值与函数的调用位置
- 有原型声明的函数,且原型声明在定义之前,则默认参数值应在函数原型声明中给出
- 只有函数的定义,或函数定义在前,默认参数值在定义中给出
#eg:计算长方体体积
函数getVolume计算体积。
形参:length(长)、width(宽)、height(高),其中width和height带有默认值2和3
#include <iostream>
#include <iomanip>
using namespace std;
int getVolume(int length, int width = 2, int height = 3);
int main(){
const int X = 10, Y = 12, Z = 15;
cout << "Some box data is: ";
cout<<getVolume(X,Y,Z)<<endl; //10*12*15
cout << "Some box data is: ";
cout << getVolume(X, Y) << endl; //10*12*3
cout << "Some box data is: ";
cout << getVolume(X) << endl; //10*2*3
system("pause");
return 0;
}
int getVolume(int length, int width, int height) {
cout << setw(5) << length << setw(5) << width
<< setw(5) << height << '\t';
return length * width*height;
}
函数重载
同样的函数名对不同类进行运算操作
C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重载。方便使用和记忆。
注意:
-
重载函数的形参必须不同:个数不同或类型不同
int add(int x,int y);
float add(float a,float b,float c);
√
int add(int x,int y);
int add(int a,int b);
× 编译器不以参数类型区分
int add(int x,int y);
void add(int x,int y);
× 编译器不以返回值区分 -
编译程序将根据实参和形参的类型和个数的最佳匹配实现选择调用
-
不要将不同功能的函数声明为重载函数,以免误解和混淆调用结果
int add(int x,int y) {return x + y};
float add(float x,float y) {return x -y};
#eg:编写两个名为sumOfSquare的重载函数
分别求两个整数的平方和和两个实数的平方和
#include <iostream>
using namespace std;
int sumOfSquare(int a, int b) {
return a * a + b * b;
}
double sumOfSquare(double a, double b) {
return a * a + b * b;
}
int main(){
int m, n;
cout << "Enter two integers: ";
cin >> m >> n;
cout<<"Their sum of square: "<< sumOfSquare(m,n)
<<endl;
double x, y;
cout << "Enter two real number: ";
cin >> x >> y;
cout << "Their sum of square: " << sumOfSquare(x, y)
<< endl;
system("pause");
return 0;
}
C++系统函数
- 使用系统函数时要包含相应的头文件
- 函数的声明在头文件cmath中
#eg:从键盘输入一个角度值,求出该角度的正弦、余弦和正切
系统提供了sin()、cos()、tan(),函数的声明在头文件cmath中
#include <iostream>
#include<cmath>
using namespace std;
const double PI = 3.14159265358979;
int main(){
double angle;
cout << "Please enter an angle: ";
cin >>angle; //输入角度值
double radian = angle * PI / 180; //转为弧度值
cout << "sin(" << angle << ") =" << sin(radian) << endl;
cout << "cos(" << angle << ") =" << cos(radian) << endl;
cout << "tan(" << angle << ") =" << tan(radian) << endl;
system("pause");
return 0;
}
实验三
加强学习数据结构中递归函数的调用