1 C++简介
1.1 起源
-贝尔实验室20世纪80年代(1979)
1.2 应用范围
- 文字处理程序以及电子表格
- 编译器
- 操作系统
- 大型游戏等
1.3 C++和C
- C语言是结构化和模块化的语言,面向过程。
- C++保留了C语言原有的所有优点,增加了面向对象的机制,俗称“带类的C",1983年更名为C++
2开发工具
- 记事本(Notepad++)+命令行
- Visual C++ 6.0:经典开发工具,与流行操作系统有冲突
- VS 2015等:功能强大,体积也强大
- Code::Blocks:开源免费开发工具,专业开发人员推荐使用
- 其他开发工具:DeV C++、CLion、C-Free、Xcode、C4droid
3 基本语法
- 对象-对象具有状态的行为。对象是类的实例。
- 类-类可以定义为对象行为、状态的模版。
- 方法-从基本上讲,一个方法表示一种行为,一个类可以包含多种方法。
- 变量
3.1 注释
//单行注释
/*
多行注释
多行注释
*/
3.2关键字
asm | else | new | this |
---|---|---|---|
auto | enum | operator | throw |
bool | explicit | private | true |
break | export | protected | try |
case | extern | public | typedef |
catch | false | register | typeid |
char | float | reinterpret_cast | typename |
class | for | return | union |
const | friend | short | unsigned |
const_cast | goto | signed | using |
continue | if | sizeof | virtual |
default | inline | static | void |
delete | int | static_cast | volatile |
do | long | struct | wchar_t |
double | mutable | switch | while |
dynamic_cast | namespace | template |
3.3标识符
- 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。
- 标识符内不允许出现标点字符,比如 @、& 和 %。C++ 是区分大小写的编程语言。
4 数据类型
4.1基本数据类型
七种基本的C++数据类型:bool、char、int、float、double、void、wchar_t
类型修饰符:signed、unsigned、short、long
注:一些基本类型可以使用一个或多个类型修饰符进行修饰,比如:signed short int简写为short、signed long int 简写为long。
类型名 | 占用字节数 | 数值范围 |
---|---|---|
void | 0 | |
bool | 1 | {true.false} |
wchar_t | 2或4个字节 | |
char(signed char) | 1 | -128~+127 |
short(signed short) | 2 | -32768~+32767 |
int(signed int) | 4 | -2147483648~+2147483647 |
long(signed long) | 4 | -2147483648~+2147483647 |
long long(signed long long) | 8 | -9,223,372,036,854,775,808 ~9,223,372,036,854,775,807 |
float | 4 | -.341038~3.41038 |
double | 8 | -1.710308~1.710308 |
unsigned char | 1 | 0~255 |
unsigned shrot | 2 | 0~65525 |
unsigned(unsigned int) | 4 | 0~4294967295 |
unsigned long | 4 | 0~4294967295 |
unsigned long long | 8 | 0 ~ 18,446,744,073,709,551,615 |
//x64处理器 64位window10 vs2015
#include <iostream>
using namespace std;
int main()
{
bool b;
char c;short s; int i; long l; long long ll; float f; double d; long double ld;long float lf;
unsigned char uc; unsigned short us; unsigned int ui; unsigned long ul; unsigned long long ull;
cout << sizeof(bool) << endl;
cout << sizeof(char)<<" " << sizeof(short)<<" "<< sizeof(signed int) << " " << sizeof(long) << " " << sizeof(signed long long) << " " << sizeof(float) << " " << sizeof(double) << " " << sizeof(long float) << " " << sizeof(long double) << endl;
cout <<sizeof(unsigned char)<<" "<< sizeof(unsigned short) << " " << sizeof(unsigned int) << " " << sizeof(unsigned long) << " " << sizeof(unsigned long long) << endl;
cout << sizeof(unsigned) << endl;
cout << "hello World!!!" <<endl;
system("pause");
return 0;
}
4.2 数据类型在不同系统中所占空间大小
这个与机器、操作系统、编译器有关。比如同样是在32bits的操作系统系,VC++的编译器下int类型为占4个字节;而tuborC下则是2个字节。
原因:
- c/c++规定int字长和机器字长相同
- 操作系统字长和机器字长未必一致
- 编译器根据操作系统字长来定义int字长
类型 | 16位操作系统 | 32位操作系统 | 64位操作系统 |
---|---|---|---|
char | 1 | 1 | 1 |
char* | 2 | 4 | 8 |
short | 2 | 2 | 2 |
int | 2 | 4 | 4 |
long | 4 | 4 | 8 |
long long | 8 | 8 | 8 |
注:long类型在不同编译器中的占位不一样: 32位时,VC++和GCC都是4字节; 64位时,VC++是4字节,GCC是8字节。
4.3 typedef声明
//使用typedef为一个已有的类型取一个新的名字,语法如下:
typedef type newname
//eg:
typedef int feet
feet distance
4.4 枚举类型
C++中的一种派生数据类型,它是由用户定义的若干枚举常量的集合;枚举元素是一个整型,枚举型可以隐式的转换为int型,int型不能隐式的转换为枚举型。
//枚举类型的语法:
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
}枚举变量;
如果枚举没有初始化, 即省掉"=整型常数"时, 则从第一个标识符开始;
- 默认情况下,第一个名称的值为 0,第二个名称的值为 1,第三个名称的值为 2,以此类推。但是,您也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。
例如:
enum course {
math,chinese,english,physics,chemistry}c;
c = english;
cout<<c<<endl; //2
//english为1 physics为2 chemistry为3,chinese仍为1,math仍为0
enum course {
math,chinese,english=1,physics,chemistry};
5 变量
变量其实只不过是程序可操作的存储区的名称。C++ 中每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
5.1 变量的声明和定义
- 变量声明向编译器保证变量以给定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。
- 可以在 C++ 程序中多次声明一个变量,但变量只能在某个文件、函数或代码块中被定义一次。
- 多个变量赋同一个值时,需要分别赋值。
int x = y = z = 66;//错误
int x = 3,y = 3,z = 3;
int x, y ,z = 3;
x = y = z;
变量的声明(不分配内存):extern 数据类型 变量名;
变量的定义:数据类型 变量名1,变量名2,...变量名n;
// 变量声明
extern int a, b;
int main ()
{
// 变量定义
int a, b;
// 初始化
a = 23;
b = 25;
return 0;
}
5.2 变量的作用域
局部变量:在函数或一个代码块内部声明的变量,称为局部变量。它们只能被函数内部或者代码块内部的语句使用。
全局变量:在所有函数外部定义的变量(通常是在程序的头部),称为全局变量。全局变量的值在程序的整个生命周期内都是有效的。
- 局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值会覆盖全局变量的值。
- 当局部变量被定义时,系统不会对其初始化;定义全局变量时,系统会自动初始化值:
int float double 0,char ’\0‘,指针 NULL
int i = 66;
int main ()
{
int i = 88;
cout << i<<endl;//8
return 0;
}
float f;
double d;
char c;
int *p;
int main()
{
cout << i << f << d << c << p << endl;//000 00000000
return 0
}
6 运算符
- 算术运算符:
+ - * / % ++ --
- 关系运算符:
== != < > >= <=
- 逻辑运算符:
&& || !
- 位运算符:
& | ^ ~ << >>
- 赋值运算符:
= += -= *= /= %= <<= >>= &= ^= !=
- 杂项运算符:
sizeof //返回变量的大小,eg:sizeof(a)返回4 a是整型 sizeof(int)
Condition?X:Y //三元运算符 Condition为true,值为X,否则值为Y
, //逗号表达式,值为最后一个表达式的值
.和-> //用于引用类、结构和公用体的成员
Cast //强制类型转换符 eg:int(2.202)返回2
& //指针运算符 返回变量的地址
* //指针运算符 指向一个变量
- 运算符优先级
类别 | 运算符 | 结合性 |
---|---|---|
后缀 | () [] -> . ++ - - | 从左到右 |
一元 | + - ! ~ ++ - - (type)* & sizeof | 从右到左 |
乘除 | * / % | 从左到右 |
加减 | + - | 从左到右 |
移位 | << >> | 从左到右 |
关系 | < <= > >= | 从左到右 |
相等 | == != | 从左到右 |
位与 AND | & | 从左到右 |
位异或 XOR | ^ | 从左到右 |
位或 OR | | | 从左到右 |
逻辑与 AND | && | 从左到右 |
逻辑或 OR | || | 从左到右 |
条件 | ?: | 从右到左 |
赋值 | = += -= *= /= %=>>= <<= &= ^= | = |
逗号 | , | 从左到右 |
7 语法结构
7.1 循环结构
- while
while(conditon)//0为false,非0为true
{
statement(s);
}
- for
for(init;conditon;increment)//0为false,非0或什么也不写为true
{
statement(s);
}
1.init首先被执,且只会执行一次,也可以不写任何语句。
2.然后会判断conditon,true执行循环主体,false跳过循环
3.执行完循环主体,执行increment,跳到2
int array[5] = {
11, 22, 33, 44, 55 };
for (int x : array)
{
cout << x << " ";
}
cout << endl;
// auto 类型也是 C++11 新标准中的,用来自动获取变量的类型
for (auto x : array)
{
cout << x << " ";
}
- for each
STL中的for增强循环。
int a[4] = {
4,3,2,1 };
for each (int var in a)
{
cout << var << " ";
}
7.2 判断结构
- if
if(expr)
{
statement;//如果expr为true将执行的语句块
}
if(expr)
{
statement1;// 如果expr为true将执行的语句块
}
else
{
statement2;// 如果expr为false将执行的语句
}
if(expr1)
{
statement1;// 如果expr1为true将执行的语句块
}
elseif(expr2)
{
statement2;// 如果expr2为true将执行的语句块
}
...
else
{
statementElse;// 当上面的表达式都为false执行的语句块
}
- switch
switch(expression){
case constant-expression :
statement(s);
break;
case constant-expression :
statement(s);
break;
// 您可以有任意数量的 case 语句
default : // 可选的
statement(s);
}
- 每个case后满的常量表达式必须各不相同。
- case语句和default语句出现的顺序对执行结果没有影响。
- 若case后没有break,执行完就不会判断,继续执行下一个case语句。直到遇到brerak。
- default后面如果没有case,则break可以省略
- 多个case可以用一组执行语句
char c = 'A';
switch (c)
{
case 'A':
case 'B':
case 'C':
cout << "及格了" << endl;
break;
default:
cout << "不及格" << endl;
}
7.3 三元运算符
//如果 Exp1 为真,则计算 Exp2 的值,结果即为整个 ? 表达式的值。如果 Exp1 为假,则计算 Exp3 的值,结果即为整个 ? 表达式的值
Exp1 ? Exp2 : Exp3;
7.4 预处理命令
预处理程序(删除程序注释,执行预处理命令等)–>编译器编译源程序
- 宏定义:
#define 标识符 字符串
- 文件包含:
#include<filename> 或者#include“filename”
- 条件编译
//如果标识符被#define定义过,执行程序段1,否则执行程序段2
#ifdef 标识符
程序段1
#else
程序段2
#endif
//如果标识符没有被#define定义过,执行程序段1,否则执行程序段2
#ifndef 标识符
程序段1
#else
程序段2
#endif
//如果表达式为true,执行程序段1,否则执行程序段2
#if 表达式
程序段1
#else
程序段2
#endif
8 数组
一些具有相同数据类型或相同属性(类)的数据的集合,用数据名标识,用下标或序号区分各个数据。数组中的数据称为元素。
8.1一维数组
定义一维数组的形式:数据类型 数据名[常量表达式]
初始化的形式:数据类型 数组名[常量表达式] = {初值表};
为数组的某一个元素赋值:数组名[下标] =值
(下标从0开始)
数组的引用:数组名[下标]
- 初始化数组时,可以只给部分数组元素赋值
- 对全部元素数组赋值时,可以不指定数组长度,编译系统会根据初值个数确定数组的长度。
- static型数组元素不赋初值,系统会自动默认为0。
int arr1[4] = {
1,2,3,4};
int arr2[4] = {
1,2 };
int arr[4] = {
0];//所有元素为0
static int arr3[3];
int arr4[4];
cout << "arr1:"<<arr1[0] << arr1[1] << arr1[2] << arr1[3] << endl;
cout << "arr2:" << arr2[0] << arr2[1] << arr2[2] << arr2[3] << endl;
cout << "arr3:" << arr3[0] << arr3[1] << arr3[2] << arr3[3] << endl;
cout << "arr4:" << arr4[0] << arr4[1] << arr4[2] << arr4[3] << endl;
8.2二维数组
定义一维数组的形式:数据类型 数据名[常量表达式1][常量表达式2]
初始化的形式:数据类型 数组名[常量表达式1] [常量表达式2]= {初值表};
为数组的某一个元素赋值:数组名[行下标][列下标] =值
(下标从0开始)
数组的引用:数组名[行下标][列下标]
- 将所有数据写在一个花括号内,自动按照数组元素个数在内存中排列的顺序赋值
- 可对部分元素赋值,其余元素的值自动取0.
- 定义初始化数组时,可以省略第一维的长度,第二维不能省,系统会自动确认行数
int arr1[2][3];
int arr[2][3] = {
0];//所有元素为0
int arr2[2][3] = {
{
1,2,3},{
4,5,6} };
int arr3[2][3] = {
1,2,3 ,4,5,6 };
int arr4[2][3] = {
{
1},{
4,6} };
int arr5[][3] = {
1,2,3 ,4,5,6 };
字符数组
char类型的数组,在字符数组中最后一位为’\0’)时,可以看成时字符串。在C++中定义了string类,在Visual C++中定义了Cstring类。
字符串中每一个字符占用一个字节,再加上最后一个空字符。如:
//字符串长度为8个字节,最后一位是'\0'。
char array[10] = "yuanrui";//yuanrui\0\0\0
//也可以不用定义字符串长度,如:
char arr[] = "yuanrui";//yuanrui\0
8.3 指向数组的指针
指针的概念会在后面详细讲解。
double *p;
double arr[10];
p = arr;//p = &arr[0];
*(p+3);//arr[3]
8.4 数组与new(动态创建数组)
一维数组:
int* arr1 = new int[2];//delete []arr1;
int* arr2 = new int[3]{
1,2 };//delete []arr2
二维数组
int m=2, n=3;
int** arr3 = new int*[2];//delete []arr3
for (int i = 0; i < 10; ++i)
{
arr3[i] = new int[3]; // delete []arr3[i]
}
int* arr4 = new int[m*n];//数据按行存储 delete []arr3
8.5 数组与函数
数组->函数
- 如果传递二维数组,形参必须制定第二维的长度。
形式参数是一个指针:void function(int *param)
形式参数是一个已定义大小的数组:void function(int param[10])
形式参数是一个未定义大小的数组:void function(int param[])
二维数组:void function(int a[][3],int size)
函数返回数组
- C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
int * function();
int** function();
8.6 获取数组的大小
- 动态创建(new)的基本数据类型数组无法取得数组大小
int a[3];
//第一种方法
cout<<sizeof(a)/sizeof(a[0])<<endl;
//第二种方法
cout << end(a) - begin(a) << endl;
//二维数组
int arr[5][3];
int lines = sizeof(arr) / sizeof(arr[0][0]);
int row = sizeof(arr) / sizeof(arr[0]);//行
int col = lines / row;//列
cout << row << "::"<<col << endl;
cout << end(arr) - begin(arr) << endl;//5行
9 函数
函数是实现模块化程序设计思想的重要工具, C++程序中每一项操作基本都是由一个函数来实现的,C++程序中只能有一个主函数(main)
9.1 函数声明与定义
- 函数类型-函数的返回值类型;函数名-必须符合C++标识符命名规则,后面必须跟一对括号;函数体-实现函数功能的主题部分;参数列表-函数名后面的括号内,用于向函数传递数值或带回数值。
- 函数声明中,参数名可以省略,参数类型和函数的类型不能省略。
- 函数声明可以放在主调函数内部,放在调用语句之前;也可以放在主调函数外,如果位于所有定义函数之前,后面函数定义顺序任意,各个主调函数调用也不必再做声明
- 当函数定义在前,函数调用灾后,可以不用函数声明。
后两条总结一下就是:调用函数前,程序得知道有这个函数,声明就是提前让程序知道有这么的玩意
函数声明:
函数类型 函数名(参数列表);
eg:
int max(int a,int b);//声明函数时,a,b可以省略
int max(int,int);
void show();
函数定义:
函数类型 函数名(参数列表)
{
函数体;
}
eg:
int max(int a,int b)
{
int z;
z = a>b?a:b;
return z;
}
9.2 函数的参数与返回值
- 形参:函数定义后面括号里的参数,函数调用前不占内存。
- 实参:函数调用括号里的参数,可以是常量,变量或表达式等。
形参和实参必须个数相同、类型一致,顺序一致
函数传递方式:传值,指针,引用
关于指针和引用后面有详细介绍。
//传值-修改函数内的形式参数对实际参数没有影响
int add(int value)
{
value++;
return value;
}
int main()
{
int v = 10;
cout << "add() = " << add(v) << endl;//add() = 11
cout << "v = " << v << endl;//v = 10
return 0;
}
//指针-修改形式参数会影响实际参数
int add(int* pValue)
{
(*pValue)++;
return *pValue;
}
int main()
{
int v = 10;
cout << "add() = " << add(&v) << endl;//add() = 11
cout << "v = " << v << endl;//v = 11
return 0;
}
//引用-修改形式参数会影响实际参数
int add(int &value)
{
value++;
return value;
}
int main()
{
int v = 10;
cout << "add() = " << add(v) << endl;//add() = 11
cout << "v = " << v << endl;//v = 11
return 0;
}
有默认值参数的函数
int sum(int a, int b=2)
{
return (a + b);
}
int main ()
{
cout << "Total value is :" << sum(100, 200);<< endl;//Total value is :300
cout << "Total value is :" << sum(100);<< endl;//Total value is :102
return 0;
}
函数的返回值
- 返回值通过return给出,return后面跟表达式,且只能放回一个值;如果没有表达式,可以不写return;return后面的括号可有可无。
- return语句中的表达式类型应与函数类型一致,否则自动转换类型(函数类型决定返回值类型)
9.3 函数调用
- 函数可以单独作为一个语句使用。有返回值的函数,可将函数调用作为语句的一部分,利用返回值参与运算。
函数调用形式:参数传递–>函数体执行–>返回主调函数
函数名(实参列表);
show();
函数的嵌套调用:
int a()
{
return 666;
}
int b(int sum)
{
return sum+a()
}
int main()
{
cout<<b(222)<<endl;//888
return 0;
}
函数的递归调用:直接递归调用和间接递归调用
- 一个函数直接或间接递归调用该函数本身,称为函数的递归调用
- 递归和回归:原问题=>子问题 子问题的解=>原问题的解
//直接递归调用:求1+...n的值
int total(int sum)
{
if (sum == 1)
{
return 1;
}
return sum + total(sum - 1);
}
int main()
{
cout << "total = " << total(10) << endl;//total = 55
system("pause");
return 0;
}
//间接递归调用
int f2();
int f1()
{
...</