目录
C++语言基础
1. 数据类型
- 基本数据类型: 预定义好的数据类型
数据类型 | 关键词 | 字节数 | 数值范围 |
---|---|---|---|
字符型 | char | 1 | -128-127 |
整型 | int | 4 | -214783648-2147483647 |
单精度浮点型 | float | 4 | |
双精度浮点型 | double | 8 | |
长双精度浮点型 | long double | 10 | |
布尔型 | bool | 1 | |
无值型 | void | 0 |
- 构造类型:枚举类型(enum),数组类型,结构体类型,共用体类型
- 指针类型
- 引用类型
2. 类型修饰符
- signed : 有符号类型,修饰的类型值可以为正数或者负数
- unsigned : 无符号类型,修饰的类型值只能为正数
- short : 短型,修饰的类型值一定不大于对应的整数
- long : 长型,修饰的类型值一定不小于对应的整数
- 四种修饰符都可以用修饰整型和字符型
3. 常量
3.1 常量类型
- 整型常量:
- 十进制形式: 由数字0-9以及正负号组成.如果为long int 型常量,则需要在常量后加字母l/L eg.123L
- 八进制形式: 以0开头的数字(0-7)序列
- 十六进制形式: 以0x/0X开头的数字(0-9/a-f)序列
- 浮点型常量
3.2 常量表示方法
- 在程序中直接写入常量 : i = 20;
- 使用#define定义宏常量 : #define 宏名 常数 eg.#define PI 3.14
- 使用const定义正规常数 : const [数据类型标识符] 常数名 = 常量值; (如果省略了数据类型,一般默认是整型)
4. 变量
4.1 变量定义修饰符
- volatile: 说明一种特殊的变量,其值可能随时变化.关键词volatile用于特殊的程序,是一个高级修饰符
- register: 指明一类频繁使用的变量,这些变量放在计算机的寄存器中
- static: 在函数体外被其修饰的变量只能由定义该变量的文件访问;在函数体内被其修饰的变量表示其是永久的,只被初始化一次
- extern: 表示变量已经在其他文件中定义了,在此只是进行是说明
- auto: 从堆栈中分配的变量,该关键词很少使用
4.2 定义变量的位置
定义位置 | 变量名称 | 作用范围 |
---|---|---|
函数体内部定义 | 局部变量 | 定义该函数体的内部发挥作用 |
函数名后的括号中 | 形式参数 | 在函数中 |
在函数体外部定义 | 全局变量 | 在整个程序中发挥作用 |
4.2.1 区分局部变量和全局变量
- 局部变量和全局变量同名时,使用域解析符"::"对隐藏的同名全局变量进行访问
源程序
#include<iostream>
using namespace std;
int sum = 5050; //定义全局变量 sum
int main()
{
int arr[3], i; //定义局部变量,但是i的作用域不包括for循环体内
{
for (int i = 0; i < 3; i++)
{
cin >> arr[i];
}
}
int sum = 0; //定义局部变量,与全局变量同名
for (i = 0; i < 3; i++) //此处的i为函数开始定义的i
{
sum += arr[i];
}
for (i = 0; i < 3; i++)//此处的i为函数开始处定 义的i
{
cout << arr[i] << endl;
}
cout << " 局部sum = " << sum << endl;//输出局部变量
::sum += sum;//域解析符对全局变量进行访问,赋值号右边sum为局部变量
cout << " 全局sum = " << ::sum << endl;//输出全局变量sum的值
return 0;
}
运行结果
5. const修饰符和指针的结合
- 指向常量的指针: const 类型名*指针名;
- const int *p;
- 代码理解
#include<iostream>
using namespace std;
int main()
{
int a = 666;
int b = 999;
const int* p = &a; //指向常量的指针,不可以通过指针改变所指向的内容
cout << *p << endl;
a = 111;//但是可以通过直接修改常量本身进行改变常量的值
cout << "直接修改常量后p指向的值: " << * p << endl;
//*p = 222; 此处程序会报错,因为p指向的内容不可以该百年
p = &b;//但是p的指向可以改变
cout <<"改变p的指向之后的值: " << * p << endl;
return 0;
}
- 运行结果
- 常指针: 类型名* const 指针名 = 地址值;
- int * const p;
#include<iostream>
using namespace std;
int main()
{
/*
定义常指针,地址不变,
就指针本身的作用而言,指针不能改变就是它指向的地址不可以改变
但是指针所指向的地址所存储的内容是可以随意改变的
*/
int a = 666;
int b = 999;
int* const p = &a;
// p = &b;不可以修改p的指向
*p = 111;//但是可以修改内容
}
- 指向常量的常指针: const 类型名* const 指针名 = 地址值;
- const int *const p;
- 综合使用上面两种方法;
6. 枚举类型
- 使用enum定义符号常量
enum{Min = 0,Max = 100};
int x = Min,arr[Max];//可以直接匿名使用enum
7. 无名联合
- 无名联合在关键词union后没有给出联合体的类型名称,这样可以使一组变量 共享同一段内存空间,起始地址相同
在此代码段中三个变量具有相同的起始地址,可以直接使用数据项的名字直接存取数据
union
{
char c;
int i;
double d;
};
8. 扩展结构体
- c++中的结构体不仅包含是数据成员,也可以将对这些数据成员进行操作的成员函数也定义在结构体中.
struct Point
{
double x,y;
void SetVal(double a,double b)
{x = a; y = b;}
}p;
- C++中定义结构体时,struct后面的标识符可以直接作为该结构体类型的类型名
struct Point{
double x,y;
};
Point p;
//C语言中的写法: struct Point p;
9. void型指针
- void作为指针类型时表示不确定的类型.是一种通用型指针,任何类型的指针值都可以赋值给该类型的变量
void *p;
- 但是对于已经获值的void指针,对它进行处理时(eg.输出/传递指针),必须进行显示类型转换,否则会出错
代码理解
#include<iostream>
using namespace std;
int main()
{
void* p;
int i = 999;
char a = 'A';
p = &i;
cout << *(int*)p << endl;
p = &a;
cout << *(char*)p << endl;
return 0;
}
10. 运算符
- 运算符优先级:
单目运算符>算数运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符
11. 数据类型转换
- (目标类型)带转换的源数据
12. 内联函数
- 函数说明前冠以关键字"inline",则声明为内联函数
- 程序中出现对该函数的调用时,编译器使用函数体中的代码插入到该函数的语句之处,程序运行的时候不再进行函数的调用
- 引入内联函数的原因: 为了消除函数调用时的系统开销,提高运行速度
- 内联函数中不能有循环语句和开关语句
- 内联函数是一种空间换时间的措施,内联函数太长且调用频繁程序就会加长很多,因此,只有较短的函数才能定义为内联函数
13. 重载
- 函数名相同
- 参数个数不同或者参数类型不同
- 或者两者兼而有之
int add(int a,int b)
{
return a + b;
}
float add(float a,float b)//参数类型不同
{
return a + b;
}
float add(float a, float b, float c)//参数个数不同
{
return a + b + c;
}
double add (double a,double b,double c)//参数类型且个数不同
{
return a + b + c;
}
14. 引用
- 引用是C++新增加的概念,用作函数参数或者作为函数的返回类型
- C++是通过引用运算符&来声明一个引用的,在声明时必须进行初始化
- 声明格式如下:
数据类型 &引用名 = 已定义的变量名
int i = 5;
int & j = i;
- 声明引用时使用&, & 不是取地址符,而是引用运算符,只在声明一个引用时使用,之后引用就像普通对象一样不再使用&
- 声明引用的同时,如果不是作为函数的参数或者返回值类型,就必须进行初始化,以明确该引用是哪一个对象的别名
- 不能建立void型引用,引用的引用,指向引用的指针,引用数组
14.1 引用作为参数传递
#include<iostream>
using namespace std;
int main()
{
int a = 5, b = 10;
cout << "交换前a,b的值分别为: " << a << " " << b << endl;
swap(a, b);//相当于 int &m = a; int &n = b;
cout << "交换后a,b的值分别为: " << a << " " << b << endl;
return 0;
}
void swap(int& m, int& n)
{
int temp;
temp = m;
m = n;
n = temp;
}
运行结果
交换前a,b的值分别为: 5 10
交换后a,b的值分别为: 10 5
- 形式参数克服了值传递并不能改变对应实际参数的缺陷,因为引用参数和对应实际参数变量共享同一个内存
- 与引用参数对应的实际参数只能是变量,而不能是常量或表达式
- 就算不需要改变实际参数的值,引用参数仍然比值形式参数更高效,因为无需另外分配空间和进行传值操作
14.2 引用和指针的区别
- 使用起来的效果是一样的,引用可以说是一种"自动间接引用的指针"
- 引用不需要使用*,超级方便,真的好好用
指针形式实现以上交换
#include<iostream>
using namespace std;
void swap(int* m, int* n)
{
int temp;
temp = *m;
*m = *n;
*n = temp;
}
int main()
{
int a = 5, b = 10;
cout << "交换前a,b的值分别为: " << a << " " << b << endl;
swap(&a, &b);//相当于 int &m = a; int &n = b;
cout << "交换后a,b的值分别为: " << a << " " << b << endl;
return 0;
}
14.3 引用作为返回类型
- 引用返回函数的类型声明
类型名& 函数名(形式参数表); - 调用引用返回函数可以作为:
- 独立的函数语句;
- 表达式的某一个运算对象;
- 作为左值,这是引用作为返回值的函数的主要用法
代码理解
#include<iostream>
using namespace std;
int& Fun(const int& x, int& y, int z)
{
z++;
y = x + y + z;
return y;
}
int main()
{
int a = 1, b = 2, c = 3, d = 0;
cout << "a = " << a << "\t b = " << b << "\tc = " << c << "\td = " << d << endl;
Fun(a, b, c) = 20;
cout << "a = " << a << "\t b = " << b << "\tc = " << c << "\td = " << d << endl;
}
运行结果
a = 1 b = 2 c = 3 d = 0
a = 1 b = 20 c = 3 d = 0
- return 后面只能是变量,而不能是常量或者表达式
- return 后面变量的内存空间在本次函数调用结束后仍然存在,因此局部自动型变量不能作为引用值返回
- return 后面返回的不能是常饮用,因为常引用是为了保护对应的实在参数变量不被修改,而引用返回的函数作为左值必定要引起变量的修改
15. 动态内存分配
15.1 动态内存分配与释放函数
- 程序运算时,计算机内存被分为4个区:
- 程序代码区
- 全程数据区
- 栈
- 堆
- 堆由用户分配和释放
- C语言中使用malloc()和free()等进行管理,并在头部嵌入头文件#include<stdlib.h>
- malloc函数
void * malloc(unsigned int size)- 作用: 在内存的动态存储区中分配一个长度为size的连续空间
- 此函数的返回值是一个指向分配域起始地址的指针
- 如果此函数未能成功执行,则返回空指针
- calloc函数
void *calloc(unsigned n,unsigned size);- 作用: 在内存的动态区存储中分配n个长度为size的连续空间.函数返回一个指向分配域起始地址的指针,分配不成功返回NULL
- 用calloc函数可以为一位数组开辟动态存储空间,n为数组元素个数,每个元素长度为size
- free函数
void free(void *p)- 作用是释放由p指向的内存区,使这部分内存区域能被其他变量使用
- p使最近一次调用calloc或malloc函数时返回的值,free函数无返回值
- malloc函数
15.2 new和delete
15.2.1 具体使用
- new
- 分配内存的最基本的语法形式: 指针变量 = new 类型名;
int *p = new int;
int *p = new int(99);//分配空间的同时进行初始化
- 该语句运行的时候从堆中为程序分配一块sizeof字节大小的内存空间,该内存空间的首地址被存于指针变量中
- new为数组动态分配内存空间时,后缀数组大小: 指针变量 = new 类型名[下缀表达式];
int *p = new int[10];
- delete
- 释放new分配的存储空间: delete 指针变量;
- 指针变量保存着new分配的内存首地址
- delete释放数组存储区域时,可以不用指出数组大小
delete []p;
15.2.2 new和delete的优点
- new可以自动计算分配内存的类型大小
- new能够自动返回正确的指针类型,不需要对返回指针进行强制的类型转换
- 可以使用new将分配的对象初始化
- new和delete都可以被重载
15.2.3 注意点
- new分配的空间只能由delete显式释放
- new动态分配内存时,如果没有足够的内存满足分配要求,new将返回空指针,因此常需对内存的动态分配是否成功进行检查
代码理解
#include<iostream>
using namespace std;
int main()
{
int* p;
p = new int;
if (!p)
{
cout << "分配内存失败!" << endl;
return -1;
}
*p = 20;
cout << *p;
delete p;
return 0;
}
16. 异常处理
16.1 程序中的错误类型
- 语法错误: 包括编译错误和链接错误,这类错误在编译链接时根据出现的错误信息可以进行纠正
- 运行错误: 在编译链接通过后在运行时出现的错误,通常包括不可预料的逻辑错误和可预料的运行异常
16.2 异常处理的机制
- C++中使用throw和try-catch语句支持异常处理
- C++语言中异常处理的机制由三步解决"
- 检查异常(try块)
- 抛出异常(throw块)
- 捕捉异常(catch块)